Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Jake Edge @ 2011-03-02 20:38 UTC (permalink / raw)
  To: Vasiliy Kulikov
  Cc: linux-kernel, mjt, arnd, mirqus, netdev, Ben Hutchings,
	David Miller, kuznet, pekkas, jmorris, yoshfuji, kaber,
	eric.dumazet, therbert, xiaosuo, jesse, kees.cook, eugene,
	dan.j.rosenberg, akpm
In-Reply-To: <20110302201807.GA31965@albatros>

On Wed, 2 Mar 2011 23:18:07 +0300 Vasiliy Kulikov wrote:

> > and on systems that today use CAP_SYS_MODULE
> 
> Since Linux 2.6.32 CAP_SYS_MODULE may not load modules via "ifconfig
> gre0".  It was changed to CAP_NET_ADMIN.  So nothing is broken here.
> 
> > (or really the full set of
> > capabilities cuz they are running as root)?
> 
> As root has CAP_NET_ADMIN, the alias netdev-gre0 is tried and it
> succeeds.

(I feel like I'm beating a dead horse here, sorry if so ...)

If I have a setuid-root program today that loads ip_gre by using the
alias "gre0", and I run that program on a kernel with this change,
won't it fail because the "gre0" alias is missing?  That program
doesn't know to try "netdev-gre0". i.e. won't backward compatibility be
affected by this change?

jake

-- 
Jake Edge - LWN - jake@lwn.net - http://lwn.net

^ permalink raw reply

* Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Jake Edge @ 2011-03-02 20:40 UTC (permalink / raw)
  To: Vasiliy Kulikov
  Cc: linux-kernel, mjt, arnd, mirqus, netdev, Ben Hutchings,
	David Miller, kuznet, pekkas, jmorris, yoshfuji, kaber,
	eric.dumazet, therbert, xiaosuo, jesse, kees.cook, eugene,
	dan.j.rosenberg, akpm
In-Reply-To: <20110302201807.GA31965@albatros>

On Wed, 2 Mar 2011 23:18:07 +0300 Vasiliy Kulikov wrote:

> As root has CAP_NET_ADMIN, the alias netdev-gre0 is tried and it
> succeeds.

Never mind, my apologies for the noise ... one always reads replies
most carefully just *after* hitting send ...

jake

-- 
Jake Edge - LWN - jake@lwn.net - http://lwn.net

^ permalink raw reply

* [net-2.6 PATCH] net: dcbnl: check correct ops in dcbnl_ieee_set()
From: John Fastabend @ 2011-03-02 20:35 UTC (permalink / raw)
  To: netdev; +Cc: john.r.fastabend, davem, shmulikr

The incorrect ops routine was being tested for in
DCB_ATTR_IEEE_PFC attributes. This patch corrects
it.

Currently, every driver implementing ieee_setets also
implements ieee_setpfc so this bug is not actualized
yet.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---

 net/dcb/dcbnl.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index d5074a5..c44348a 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -1193,7 +1193,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
 			goto err;
 	}
 
-	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
+	if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
 		struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
 		err = ops->ieee_setpfc(netdev, pfc);
 		if (err)


^ permalink raw reply related

* Re: [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Nicolas de Pesloüan @ 2011-03-02 20:47 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: Andy Gospodarek, netdev, davem, fubar, eric.dumazet
In-Reply-To: <20110302100354.GB2858@psychotron.brq.redhat.com>

Le 02/03/2011 11:03, Jiri Pirko a écrit :
> Tue, Mar 01, 2011 at 09:38:43PM CET, andy@greyhouse.net wrote:
>> On Tue, Mar 01, 2011 at 10:29:07AM +0100, Jiri Pirko wrote:
>>> Unapplicable, sorry (wrong branch :(). Here's corrected patch:
>>>
>>> Subject: [PATCH net-next-2.6 v2] bonding: remove skb_share_check in handle_frame
>>>
>>> No need to do share check here.
>>>
>>> Signed-off-by: Jiri Pirko<jpirko@redhat.com>
>>> ---
>>>   drivers/net/bonding/bond_main.c |    3 ---
>>>   1 files changed, 0 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>>> index 584f97b..367ea60 100644
>>> --- a/drivers/net/bonding/bond_main.c
>>> +++ b/drivers/net/bonding/bond_main.c
>>> @@ -1498,9 +1498,6 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
>>>   	struct net_device *slave_dev;
>>>   	struct net_device *bond_dev;
>>>
>>> -	skb = skb_share_check(skb, GFP_ATOMIC);
>>> -	if (unlikely(!skb))
>>> -		return NULL;
>>>   	slave_dev = skb->dev;
>>>   	bond_dev = ACCESS_ONCE(slave_dev->master);
>>>   	if (unlikely(!bond_dev))
>>> --
>>> 1.7.3.4
>>>
>>
>> Why did you decide to get rid of it here rather than the 3 places in the
>> bonding driver where it is currently needed?  I think this can cover
>> those cases since bond_handle_frame will be called after the ptype_all
>> handlers before any of the ptype handlers.
>
> I have already a patch prepared which converts bond ptype handlers into
> being called from bond_handle_frame. You are propably right that this
> should probably stay here.

Hi Jiri,

Do you plan to call the bonding ARP handler from inside bond_handle_frame()?

A few days ago (http://marc.info/?l=linux-netdev&m=129883949022340&w=2), I noticed that it is not 
possible to call the bonding ARP handler from inside the bonding rx_handler, because some frame 
processing may be required after the bonding rx_handler call, to put the frame in a suitable state 
for the bonding ARP handler.

This is at least true with the following setup, eth0 -> bond0 -> bond0.100, where the ARP frames are 
VLAN tagged at the time the bonding rx_handler process them.

	Nicolas.

^ permalink raw reply

* Re: [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Nicolas de Pesloüan @ 2011-03-02 21:05 UTC (permalink / raw)
  To: Changli Gao
  Cc: Jiri Pirko, netdev, davem, fubar, eric.dumazet, andy, Herbert Xu
In-Reply-To: <AANLkTikvJ3n0mSabakpBOiLJZd55ZJUGz7wM2wm0th5C@mail.gmail.com>

Le 02/03/2011 17:13, Changli Gao a écrit :
> On Wed, Mar 2, 2011 at 4:11 AM, Nicolas de Pesloüan
> <nicolas.2p.debian@gmail.com>  wrote:
>> Le 01/03/2011 16:12, Changli Gao a écrit :
>>> I don't think so. Although you avoid netif_rx(), you can't avoid
>>> ptype_all handlers. In fact, all the RX handlers should has this
>>> check(), if they may modify the skb.
>>
>> Can you please develop your explanation?
>>
>> In current __netif_receive_skb() (after the recent patch from Jiri), we
>> deliver the skb to ptype_all handlers inside a loop, while possibly changing
>> skb->dev inside this loop.
>>
>> Then, at the end of __netif_receive_skb(), we loop on ptype_base, without
>> changing anything in skb.
>>
>> Should we consider ptype_*->func() to be called in a pure sequential way?
>> Should we consider that when a ptype_*->func() returns, nothing from this
>> handler will use the skb in anyway later, in a parallel way?
>>
>> Or should we, instead, consider that special precautions must be taken,
>> because protocol handlers may run in parallel for the same skb? Which kind
>> of precautions?
>>
>
> If the packets gotten by __netif_receive_skb() are unshared, the skb
> gotten by bond should be unshared, as we call prev_pt before calling
> bond. I don't see there is any  relationship with the previous patch
> from Jiri. The bridge is in the same condition with bond here, and it
> checks if the skb is shared or not. Does it imply that dev->rx_handler
> may see shared skbs?

Thanks for you explanations.

My question is not strictly linked to bonding, but more general to __netif_receive_skb().

Jiri's patch added a "goto another_round" if the rx_handler changed skb->dev. (The idea was from 
me). The ptype_all list_foreach_entry_rcu delivery loop is between "another_round:" and "goto 
another_round", so some ptype_all handlers will receive an skb where skb->dev will have changed.

I wonder whether this might cause any troubles and if yes, what should be done to fix it.

And depending on the answer, I wonder whether we can move the ptype_base loop to the same place as 
the ptype_all loop. This would allow for a better handling of orig_dev, I think.

	Nicolas.

^ permalink raw reply

* [PATCH 01/27] HFI: skeleton driver
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Device driver Makefile & Kconfig plumbing plus simple mod_init and mod_exit

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/Kconfig                |    2 +
 drivers/net/Makefile               |    2 +
 drivers/net/hfi/Makefile           |    1 +
 drivers/net/hfi/core/Kconfig       |    8 ++
 drivers/net/hfi/core/Makefile      |    5 +
 drivers/net/hfi/core/hfidd_init.c  |  142 ++++++++++++++++++++++++++++++++++++
 include/linux/Kbuild               |    1 +
 include/linux/hfi/Kbuild           |    1 +
 include/linux/hfi/hfidd_client.h   |   40 ++++++++++
 include/linux/hfi/hfidd_internal.h |   53 +++++++++++++
 10 files changed, 255 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/hfi/Makefile
 create mode 100644 drivers/net/hfi/core/Kconfig
 create mode 100644 drivers/net/hfi/core/Makefile
 create mode 100644 drivers/net/hfi/core/hfidd_init.c
 create mode 100644 include/linux/hfi/Kbuild
 create mode 100644 include/linux/hfi/hfidd_client.h
 create mode 100644 include/linux/hfi/hfidd_internal.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0382332..d4ca094 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3422,4 +3422,6 @@ config VMXNET3
 	  To compile this driver as a module, choose M here: the
 	  module will be called vmxnet3.
 
+source "drivers/net/hfi/core/Kconfig"
+
 endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..f7522bc 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -302,3 +302,5 @@ obj-$(CONFIG_CAIF) += caif/
 obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
 obj-$(CONFIG_PCH_GBE) += pch_gbe/
 obj-$(CONFIG_TILE_NET) += tile/
+
+obj-$(CONFIG_HFI) += hfi/
diff --git a/drivers/net/hfi/Makefile b/drivers/net/hfi/Makefile
new file mode 100644
index 0000000..0440cbe
--- /dev/null
+++ b/drivers/net/hfi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HFI)                += core/
diff --git a/drivers/net/hfi/core/Kconfig b/drivers/net/hfi/core/Kconfig
new file mode 100644
index 0000000..3cd637c
--- /dev/null
+++ b/drivers/net/hfi/core/Kconfig
@@ -0,0 +1,8 @@
+config HFI
+	tristate "HFI driver support"
+	depends on IBMEBUS
+	---help---
+	This driver supports the IBM System p HFI adapter.
+
+	To compile the driver as a module, choose M here. The module
+	will be called hfi_core.
diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
new file mode 100644
index 0000000..80790c6
--- /dev/null
+++ b/drivers/net/hfi/core/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the HFI device driver for IBM eServer System p
+#
+hfi_core-objs:=	hfidd_init.o
+obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
new file mode 100644
index 0000000..e03620e
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -0,0 +1,142 @@
+/*
+ * hfidd_init.c
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <linux/hfi/hfidd_internal.h>
+
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Device Driver for IBM eServer HFI for IBM System p");
+MODULE_AUTHOR("James Dykman <dykmanj@linux.vnet.ibm.com> and "
+	 "Piyush Chaudhary <piyushc@linux.vnet.ibm.com>");
+MODULE_LICENSE("GPL v2");
+
+struct hfidd_global hfidd_global;
+EXPORT_SYMBOL_GPL(hfidd_global);
+
+static dev_t   hfidd_dev;
+
+#define MAX_HFI_DEVS (MAX_HFIS + 1)
+
+/* Function to get our internal traces */
+static ssize_t hfidd_read(struct file *filep, char *buf, size_t count,
+		loff_t *pos)
+{
+	return 0;
+}
+
+/* Entry point for user space to do driver requests. */
+static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	return 0;
+}
+
+static const struct file_operations hfidd_fops = {
+	.owner		= THIS_MODULE,
+	.read		= hfidd_read,
+	.write		= hfidd_cmd_write,
+};
+
+/* Destroy the HFI class */
+static inline void hfidd_destroy_class(void)
+{
+	class_destroy(hfidd_global.class);
+	cdev_del(&hfidd_global.cdev);
+	unregister_chrdev_region(hfidd_dev, MAX_HFI_DEVS);
+}
+
+/* Create the HFI class */
+static int hfidd_create_class(void)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&hfidd_dev, 0, MAX_HFI_DEVS, HFIDD_DEV_NAME);
+	if (rc) {
+		printk(KERN_ERR "%s: hfidd_create_class: alloc_chrdev_region"
+				" failed rc 0x%x\n", HFIDD_DEV_NAME, rc);
+		return rc;
+	}
+
+	cdev_init(&hfidd_global.cdev, &hfidd_fops);
+	hfidd_global.cdev.owner = THIS_MODULE;
+	kobject_set_name(&hfidd_global.cdev.kobj, HFIDD_DEV_NAME);
+	rc = cdev_add(&hfidd_global.cdev, hfidd_dev, MAX_HFI_DEVS);
+	if (rc) {
+		printk(KERN_ERR "%s: hfidd_create_class cdev_add fail"
+				" rc = %d\n", HFIDD_DEV_NAME, rc);
+		goto hfidd_create_class_error1;
+	}
+
+	hfidd_global.class = class_create(THIS_MODULE, HFIDD_CLASS_NAME);
+	if (IS_ERR(hfidd_global.class)) {
+		rc = PTR_ERR(hfidd_global.class);
+		printk(KERN_ERR "%s: hfidd_create_class class_create fail rc = %d\n",
+				HFIDD_DEV_NAME, rc);
+		goto hfidd_create_class_error2;
+	}
+
+	return rc;
+
+hfidd_create_class_error2:
+	cdev_del(&hfidd_global.cdev);
+hfidd_create_class_error1:
+	unregister_chrdev_region(hfidd_dev, MAX_HFI_DEVS);
+
+	return rc;
+}
+
+static int __init hfidd_mod_init(void)
+{
+	int			rc = 0;
+
+	rc = hfidd_create_class();
+	if (rc < 0) {
+		printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_class failed"
+			" rc=%d\n", HFIDD_DEV_NAME, rc);
+		return -1;
+	}
+
+	printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
+	return 0;
+}
+
+static void __exit hfidd_mod_exit(void)
+{
+	hfidd_destroy_class();
+}
+
+module_init(hfidd_mod_init);
+module_exit(hfidd_mod_exit);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index b0ada6f..dde085b 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -3,6 +3,7 @@ header-y += can/
 header-y += caif/
 header-y += dvb/
 header-y += hdlc/
+header-y += hfi/
 header-y += isdn/
 header-y += nfsd/
 header-y += raid/
diff --git a/include/linux/hfi/Kbuild b/include/linux/hfi/Kbuild
new file mode 100644
index 0000000..3a742ce
--- /dev/null
+++ b/include/linux/hfi/Kbuild
@@ -0,0 +1 @@
+header-y += hfidd_client.h
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
new file mode 100644
index 0000000..b738f4b
--- /dev/null
+++ b/include/linux/hfi/hfidd_client.h
@@ -0,0 +1,40 @@
+/*
+ * hfidd_client.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFIDD_CLIENT_H_
+#define _HFIDD_CLIENT_H_
+
+#define MAX_TORRENTS            1
+#define MAX_HFI_PER_TORRENT     2
+#define MAX_HFIS                (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
+
+#endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
new file mode 100644
index 0000000..f5de1bb
--- /dev/null
+++ b/include/linux/hfi/hfidd_internal.h
@@ -0,0 +1,53 @@
+/*
+ * hfidd_internal.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFI_INTERNAL_H_
+#define _HFI_INTERNAL_H_
+
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <linux/hfi/hfidd_client.h>
+
+#define HFIDD_DEV_NAME		"hfi"
+#define HFIDD_CLASS_NAME	"hfi"
+
+/* DD global */
+struct hfidd_global {
+	struct cdev		cdev;
+	struct class		*class;
+};
+
+#endif
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 02/27] HFI: Add HFI adapter control structure
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Alloc/free of hfidd_acs to track the state of each HFI

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/Makefile      |    3 +-
 drivers/net/hfi/core/hfidd_adpt.c  |   60 ++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_init.c  |   57 ++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h |   39 +++++++++++++++++++++++
 include/linux/hfi/hfidd_adpt.h     |   45 +++++++++++++++++++++++++++
 include/linux/hfi/hfidd_internal.h |   14 ++++++++
 6 files changed, 217 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_adpt.c
 create mode 100644 drivers/net/hfi/core/hfidd_proto.h
 create mode 100644 include/linux/hfi/hfidd_adpt.h

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 80790c6..6fe4e60 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -1,5 +1,6 @@
 #
 # Makefile for the HFI device driver for IBM eServer System p
 #
-hfi_core-objs:=	hfidd_init.o
+hfi_core-objs:=	hfidd_adpt.o \
+		hfidd_init.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
new file mode 100644
index 0000000..d64fa38
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -0,0 +1,60 @@
+/*
+ * hfidd_adpt.c
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
+
+int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
+{
+
+	struct hfidd_acs	*p_acs = NULL;
+
+	p_acs = kzalloc(sizeof(*p_acs), GFP_KERNEL);
+	if (p_acs == NULL)
+		return -ENOMEM;
+
+	p_acs->dev_num = devno;
+	p_acs->index  = MINOR(devno);
+	p_acs->state  = HFI_INVALID;
+	snprintf(p_acs->name, HFI_DEVICE_NAME_MAX - 1,
+			"%s%d", HFIDD_DEV_NAME, p_acs->index);
+
+	*adpt = p_acs;
+	return 0;
+}
+
+void hfidd_free_adapter(struct hfidd_acs *p_acs)
+{
+	kfree(p_acs);
+	p_acs = NULL;
+	return;
+}
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index e03620e..114b772 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -36,6 +36,7 @@
 #include <linux/device.h>
 
 #include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
 
 MODULE_VERSION("1.0");
 MODULE_DESCRIPTION("Device Driver for IBM eServer HFI for IBM System p");
@@ -118,10 +119,52 @@ hfidd_create_class_error1:
 	return rc;
 }
 
+/* Free adapter resources and the devicese */
+static void hfidd_destroy_devices(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_HFIS; i++) {
+		hfidd_free_adapter(hfidd_global.p_acs[i]);
+		hfidd_global.p_acs[i] = NULL;
+		hfidd_global.acs_cnt--;
+	}
+}
+
+/*
+ * Create the adapter structure, allocate resources and create
+ * the hfi devices
+ */
+static int hfidd_create_devices(void)
+{
+	int i, j;
+	int rc = 0;
+
+	for (i = 0; i < MAX_HFIS; i++) {
+		rc = hfidd_alloc_adapter(&(hfidd_global.p_acs[i]),
+				MKDEV(MAJOR(hfidd_dev), i), NULL);
+		if (rc) {
+			printk(KERN_ERR "%s: hfidd_create_devices: "
+				"hfidd_alloc_adapter fail rc = %d\n",
+				HFIDD_DEV_NAME, rc);
+			for (j = 0; j < i; j++) {
+				hfidd_free_adapter(hfidd_global.p_acs[j]);
+				hfidd_global.p_acs[j] = NULL;
+				hfidd_global.acs_cnt--;
+			}
+			return rc;
+		}
+		hfidd_global.acs_cnt++;
+	}
+	return rc;
+}
+
 static int __init hfidd_mod_init(void)
 {
 	int			rc = 0;
 
+	hfidd_global.acs_cnt = 0;
+
 	rc = hfidd_create_class();
 	if (rc < 0) {
 		printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_class failed"
@@ -129,12 +172,26 @@ static int __init hfidd_mod_init(void)
 		return -1;
 	}
 
+	rc = hfidd_create_devices();
+	if (rc < 0) {
+		printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_devices"
+			" failed rc = %d\n", HFIDD_DEV_NAME, rc);
+		goto error1;
+	}
+
 	printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
 	return 0;
+
+error1:
+	hfidd_destroy_class();
+
+	/* Returning -1 so insmod will fail */
+	return -1;
 }
 
 static void __exit hfidd_mod_exit(void)
 {
+	hfidd_destroy_devices();
 	hfidd_destroy_class();
 }
 
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
new file mode 100644
index 0000000..01a5ba2
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -0,0 +1,39 @@
+/*
+ * hfidd_proto.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com)
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFIDD_PROTO_H_
+#define _HFIDD_PROTO_H_
+
+int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
+void hfidd_free_adapter(struct hfidd_acs *p_acs);
+
+#endif
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
new file mode 100644
index 0000000..6b1432d
--- /dev/null
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -0,0 +1,45 @@
+/*
+ * hfidd_adpt.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFIDD_ADPT_H_
+#define _HFIDD_ADPT_H_
+
+#include <linux/hfi/hfidd_client.h>
+
+
+/* Adpt state */
+#define HFI_INVALID		0
+#define HFI_AVAIL		1
+#define HFI_GOING_UNAVAIL	2
+#define HFI_UNAVAIL		3
+
+#endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index f5de1bb..2c58b56 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -38,16 +38,30 @@
 #include <linux/cdev.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 
 #include <linux/hfi/hfidd_client.h>
+#include <linux/hfi/hfidd_adpt.h>
 
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
 
+#define HFI_DEVICE_NAME_MAX 64
+/* hfi global */
+struct hfidd_acs {
+	dev_t			dev_num;
+	char			name[HFI_DEVICE_NAME_MAX];
+	unsigned int		index;
+	unsigned int		acs_cnt;
+	unsigned int		state;
+};
+
 /* DD global */
 struct hfidd_global {
 	struct cdev		cdev;
 	struct class		*class;
+	int			acs_cnt;
+	struct hfidd_acs	*p_acs[MAX_HFIS];
 };
 
 #endif
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 03/27] HFI:  Add device_create/device_destroy calls for HFI devices.
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_init.c  |   52 ++++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_internal.h |    1 +
 2 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 114b772..68d6e65 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -47,6 +47,7 @@ MODULE_LICENSE("GPL v2");
 struct hfidd_global hfidd_global;
 EXPORT_SYMBOL_GPL(hfidd_global);
 
+struct device  *hfidd_class_dev[MAX_HFIS + 1];
 static dev_t   hfidd_dev;
 
 #define MAX_HFI_DEVS (MAX_HFIS + 1)
@@ -71,6 +72,38 @@ static const struct file_operations hfidd_fops = {
 	.write		= hfidd_cmd_write,
 };
 
+/* Create the hfi device */
+static int hfidd_mkdev(int ai, struct hfidd_acs *p_acs)
+{
+	char			dname[128];
+	int			rc = 0;
+
+	sprintf(dname, "%s%d", HFIDD_DEV_NAME, ai);
+
+	hfidd_class_dev[ai] = device_create(hfidd_global.class,
+			NULL, MKDEV(MAJOR(hfidd_dev), ai),
+			(void *)p_acs, (char *)dname);
+
+	if (IS_ERR(hfidd_class_dev[ai])) {
+		rc = PTR_ERR(hfidd_class_dev[ai]);
+		printk(KERN_ERR "%s: hfidd_mkdev: device_create for ai=%d fail"
+				" rc = %d\n", dname, ai, rc);
+		return rc;
+	}
+
+	if (ai == MAX_HFIS)
+		return 0;
+
+	p_acs->hfidd_dev = hfidd_class_dev[ai];
+	return rc;
+}
+
+/* delete the hfi device, /dev/hfi* files and sysclass files */
+static void hfidd_rmdev(int ai)
+{
+	device_destroy(hfidd_global.class, MKDEV(MAJOR(hfidd_dev), ai));
+}
+
 /* Destroy the HFI class */
 static inline void hfidd_destroy_class(void)
 {
@@ -124,6 +157,8 @@ static void hfidd_destroy_devices(void)
 {
 	int i;
 
+	for (i = 0; i <= MAX_HFIS; i++)
+		hfidd_rmdev(i);
 	for (i = 0; i < MAX_HFIS; i++) {
 		hfidd_free_adapter(hfidd_global.p_acs[i]);
 		hfidd_global.p_acs[i] = NULL;
@@ -156,6 +191,23 @@ static int hfidd_create_devices(void)
 		}
 		hfidd_global.acs_cnt++;
 	}
+
+	for (i = 0; i <= MAX_HFIS; i++) {
+		rc = hfidd_mkdev(i, hfidd_global.p_acs[i]);
+		if (rc) {
+			for (j = 0; j < i; j++)
+				hfidd_rmdev(j);
+			goto hfidd_create_devices_error0;
+		}
+	}
+	return 0;
+
+hfidd_create_devices_error0:
+	for (i = 0; i < MAX_HFIS; i++) {
+		hfidd_free_adapter(hfidd_global.p_acs[i]);
+		hfidd_global.p_acs[i] = NULL;
+		hfidd_global.acs_cnt--;
+	}
 	return rc;
 }
 
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 2c58b56..695d7f4 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -54,6 +54,7 @@ struct hfidd_acs {
 	unsigned int		index;
 	unsigned int		acs_cnt;
 	unsigned int		state;
+	struct device		*hfidd_dev;
 };
 
 /* DD global */
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

H_HFI_START_INTERFACE Notifies the hypervisor that a new instance of the DD is
starting, and any leftover state should be considered stale.
H_HFI_STOP_INTERFACE tells the hypervisor that the DD is unloading, and to
clean up any activity related to this DD instance.
H_HFI_QUERY_INTERFACE lets us get info about the HFIs that is not in the
device tree.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/Makefile       |    3 +-
 drivers/net/hfi/core/hfidd_adpt.c   |  139 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_hcalls.c |   90 ++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |   12 +++
 include/linux/hfi/hfidd_client.h    |    8 ++
 include/linux/hfi/hfidd_hcalls.h    |   58 +++++++++++++++
 include/linux/hfi/hfidd_internal.h  |    7 ++-
 7 files changed, 315 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_hcalls.c
 create mode 100644 include/linux/hfi/hfidd_hcalls.h

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 6fe4e60..4e6cbd6 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -2,5 +2,6 @@
 # Makefile for the HFI device driver for IBM eServer System p
 #
 hfi_core-objs:=	hfidd_adpt.o \
-		hfidd_init.o
+		hfidd_init.o \
+		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index d5065cf..bec838a 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -33,6 +33,18 @@
 #include <linux/hfi/hfidd_internal.h>
 #include "hfidd_proto.h"
 
+#define HFIDD_TIME_AGE  (10 * HZ)
+
+int hfidd_age_hcall(u64 time_start)
+{
+	u64	timestamp = get_jiffies_64();
+
+	if ((timestamp - time_start) > HFIDD_TIME_AGE)
+		return 1;
+	else
+		return 0;
+}
+
 int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
 {
 
@@ -68,3 +80,130 @@ void hfidd_free_adapter(struct hfidd_acs *p_acs)
 	p_acs = NULL;
 	return;
 }
+
+/* Allocate the page for the HCALL */
+int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page, caddr_t *laddr,
+	int size)
+{
+	*page = (caddr_t)__get_free_pages(GFP_KERNEL, get_order(size));
+	if (*page == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_phyp_page: __get_free_pages failed\n");
+		return -ENOMEM;
+	}
+
+	/* translate virtual to logical address */
+	*laddr = (caddr_t)__pa((caddr_t) *page);
+	memset(*page, 0, size);
+	return 0;
+}
+
+/* Release the page allocated for the HCALL */
+inline void hfidd_release_phyp_page(caddr_t page, int size)
+{
+	free_pages((unsigned long)page, get_order(size));
+}
+
+int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
+		unsigned int hfi_id, unsigned long long *state)
+{
+	long long		hvrc;
+	int			rc = 0;
+	struct hfi_query_interface *query_p;
+	caddr_t			laddr = NULL;
+
+	if (subtype != COMP_QUERY && subtype != EEH_QUERY) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_query_interface: subtype not supported, %d\n",
+			subtype);
+		return -EINVAL;
+	}
+
+	if (subtype == COMP_QUERY) {
+		/* Allocate the page for the HCALL */
+		rc = hfidd_get_phyp_page(p_acs, (caddr_t *)&query_p, &laddr,
+				PAGE_SIZE_4K);
+		if (rc) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_query_interface: hfidd_get_phyp_page "
+				"failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	hvrc = hfi_hquery_interface(hfi_id, subtype,
+		(unsigned long long)laddr, state);
+	if (hvrc != H_SUCCESS) {
+		rc = -EPERM;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_query_interface: failed, state 0x%llx "
+			"hvrc 0x%llx\n", *state, hvrc);
+		goto query1;
+	}
+
+	if (subtype == COMP_QUERY) {
+		if (*state == ACTIVE) {
+			if (p_acs->state != HFI_AVAIL) {
+				p_acs->isr = query_p->local_node_id;
+				p_acs->state = HFI_AVAIL;
+			}
+		} else {
+			p_acs->state = HFI_UNAVAIL;
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_query_interface: Bad state %lld, "
+				"return ENODEV\n", *state);
+			rc = -EIO;
+		}
+	}
+
+query1:
+	if (subtype == COMP_QUERY)
+		hfidd_release_phyp_page((caddr_t)query_p, PAGE_SIZE_4K);
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_query_interface: return rc %d\n", rc);
+	return rc;
+}
+
+int hfidd_start_interface(struct hfidd_acs *p_acs)
+{
+	long long hvrc = 0;
+	int	rc = 0;
+	u64	start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = hfi_start_interface(p_acs->dds.hfi_id);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	if (hvrc != H_SUCCESS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_start_interface: HFI_START_INTERFACE failed "
+			"hvrc 0x%llx\n", hvrc);
+		rc = -EPERM;
+	}
+	return rc;
+}
+
+int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id)
+{
+	long long hvrc = 0;
+	int	rc = 0;
+	u64	start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = hfi_stop_interface(hfi_id);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	if (hvrc != H_SUCCESS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_stop_interface: HFI_STOP_INTERFACE failed "
+			"hvrc 0x%llx\n", hvrc);
+		rc = -EPERM;
+	}
+	return rc;
+}
diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
new file mode 100644
index 0000000..84467b3
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -0,0 +1,90 @@
+/*
+ * hfidd_hcalls.c
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
+
+static inline long long h_hfi_start_interface(int token,
+		u64 HFI_chip_ID)
+{
+	return plpar_hcall_norets(token, HFI_chip_ID);
+}
+
+static inline long long h_hfi_stop_interface(int token,
+		u64 HFI_chip_ID)
+{
+	return plpar_hcall_norets(token, HFI_chip_ID);
+}
+
+static inline long long h_hfi_query_interface(int token,
+		u64 HFI_chip_ID,
+		u64 type,
+		u64 output_page_ptr,
+		u64 *state)
+{
+	long long rc;
+	u64 hyp_outputs[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(token, (unsigned long *)hyp_outputs, HFI_chip_ID, type,
+			output_page_ptr);
+	*state = hyp_outputs[0];	/* 1st ret value */
+
+	return rc;
+}
+
+long long hfi_hquery_interface(u64 unit_id, u64 subtype,
+			       u64 query_p, u64 *state)
+{
+	long long	hvrc;
+
+	hvrc = h_hfi_query_interface(H_HFI_QUERY_INTERFACE,
+			unit_id,
+			subtype,
+			query_p,
+			state);
+	return hvrc;
+}
+
+long long hfi_start_interface(u64 unit_id)
+{
+	return h_hfi_start_interface(H_HFI_START_INTERFACE,
+			unit_id);
+}
+
+long long hfi_stop_interface(u64 unit_id)
+{
+	long long	hvrc;
+
+	hvrc = h_hfi_stop_interface(H_HFI_STOP_INTERFACE,
+			unit_id);
+	return hvrc;
+}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index e2ed4c9..6ec9245 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -36,5 +36,17 @@
 int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
 void hfidd_free_adapter(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
+int hfidd_age_hcall(u64 time_start);
+int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
+	caddr_t *laddr, int size);
+void hfidd_release_phyp_page(caddr_t page, int size);
+int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
+	unsigned int hfi_id, unsigned long long *state);
+int hfidd_start_interface(struct hfidd_acs *p_acs);
+int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
+long long hfi_hquery_interface(u64 unit_id, u64 subtype, u64 query_p,
+		u64 *state);
+long long hfi_start_interface(u64 unit_id);
+long long hfi_stop_interface(u64 unit_id);
 
 #endif
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 28f1693..2714a27 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -40,4 +40,12 @@
 
 #define HFI_DYN_WINS_DEFAULT	32
 
+#define PAGE_SIZE_4K		0x1000
+#define PAGE_SIZE_64K		0x10000
+#define PAGE_SIZE_1M		0x100000
+#define PAGE_SIZE_16M		0x1000000
+#define PAGE_SIZE_256M		0x10000000
+#define PAGE_SIZE_4G		0x100000000
+#define PAGE_SIZE_16G		0x400000000
+
 #endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
new file mode 100644
index 0000000..5349e9e
--- /dev/null
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -0,0 +1,58 @@
+/*
+ * hfidd_hcalls.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFIDD_HCALLS_H_
+#define _HFIDD_HCALLS_H_
+
+#include <asm/hvcall.h>
+
+/* Token IDs */
+#define H_HFI_START_INTERFACE		0xF000
+#define H_HFI_QUERY_INTERFACE		0xF004
+#define H_HFI_STOP_INTERFACE		0xF008
+
+#define EEH_QUERY	1
+#define COMP_QUERY	2
+
+/* States of Query interface */
+#define NOT_READY	0
+#define NOT_STARTED	1
+#define ACTIVE		2
+#define CLOSING	3
+#define ERROR		101
+
+struct hfi_query_interface {
+	unsigned long long	hypervisor_capabilities;
+	unsigned int		local_node_id;
+};
+
+#endif /* _HFIDD_HCALLS_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index fafca96..8fe313d 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -39,10 +39,12 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/device.h>
 
 #include <linux/hfi/hfidd_client.h>
 #include <linux/hfi/hfidd_adpt.h>
-
+#include <linux/hfi/hfidd_hcalls.h>
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
 
@@ -65,6 +67,9 @@ struct hfidd_acs {
 	unsigned int		index;
 	unsigned int		acs_cnt;
 	unsigned int		state;
+
+	unsigned int		isr;
+
 	struct device		*hfidd_dev;
 	struct hfidd_dds	dds;
 };
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

H_NMMU_START resets/inits state for the nMMU in the hypervisor.
H_NMMU_STOP cleans up hypervisor nMMU state, called on DD unload after HFIs are
stopped.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_adpt.c   |   36 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_hcalls.c |   33 ++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_init.c   |   29 +++++++++++++++++++++++++--
 drivers/net/hfi/core/hfidd_proto.h  |    3 ++
 include/linux/hfi/hfidd_hcalls.h    |    2 +
 5 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index bec838a..feb1b59 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -164,6 +164,42 @@ query1:
 	return rc;
 }
 
+int hfidd_start_nmmu(struct hfidd_acs *p_acs)
+{
+	long long		hvrc;
+	int			rc = 0;
+	struct nmmu_info	*nmmu_info;
+	caddr_t			laddr = NULL;
+	u64	start_time = get_jiffies_64();
+
+	rc = hfidd_get_phyp_page(p_acs, (caddr_t *)&nmmu_info, &laddr,
+			PAGE_SIZE_4K);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_start_nmmu: hfidd_get_phyp_page failed\n");
+		return -ENOMEM;
+	}
+
+	while (1) {
+		hvrc = hfi_start_nmmu(p_acs->dds.torr_id,
+				(struct nmmu_info *) laddr);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+
+	if (hvrc != H_SUCCESS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_start_nmmu: HFI_START_NMMU failed "
+			"hvrc 0x%llx\n", hvrc);
+		rc = -EPERM;
+	}
+
+	hfidd_release_phyp_page((caddr_t)nmmu_info, PAGE_SIZE_4K);
+	return rc;
+}
+
 int hfidd_start_interface(struct hfidd_acs *p_acs)
 {
 	long long hvrc = 0;
diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
index 84467b3..2ca1c8a 100644
--- a/drivers/net/hfi/core/hfidd_hcalls.c
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -33,6 +33,18 @@
 #include <linux/hfi/hfidd_internal.h>
 #include "hfidd_proto.h"
 
+static inline long long h_nmmu_start(int token,
+		u64 torrent_chip_ID,
+		void *output_page_ptr)
+{
+	return plpar_hcall_norets(token, torrent_chip_ID, output_page_ptr);
+}
+
+static inline long long h_nmmu_stop(int token, u64 torrent_chip_ID)
+{
+	return plpar_hcall_norets(token, torrent_chip_ID);
+}
+
 static inline long long h_hfi_start_interface(int token,
 		u64 HFI_chip_ID)
 {
@@ -61,6 +73,27 @@ static inline long long h_hfi_query_interface(int token,
 	return rc;
 }
 
+long long hfi_start_nmmu(u64 chip_id, void *nmmu_info)
+{
+	return h_nmmu_start(H_NMMU_START, chip_id, nmmu_info);
+}
+
+long long hfi_stop_nmmu(u64 chip_id)
+{
+	long long hvrc;
+	u64 start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = h_nmmu_stop(H_NMMU_STOP,
+				chip_id);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	return hvrc;
+}
+
 long long hfi_hquery_interface(u64 unit_id, u64 subtype,
 			       u64 query_p, u64 *state)
 {
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 9dfd2b4..448349d 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -321,31 +321,44 @@ hfidd_create_devices_error0:
 
 /*
  * Disable message passing to each adapter by calling the
- * Stop Interface hcall.
+ * Stop Interface hcall and free phyp NMMU tables for this
+ * lpar by calling STOP NMMU
  */
 static void hfidd_stop_adapter(void)
 {
 	int i;
+	long long hvrc;
 
 	for (i = 0; i < MAX_HFIS; i++) {
 		hfidd_stop_interface(hfidd_global.p_acs[i],
 			hfidd_global.p_acs[i]->dds.hfi_id);
 	}
+	hvrc = hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
+	if (hvrc != H_SUCCESS)
+		dev_printk(KERN_ERR, hfidd_global.p_acs[0]->hfidd_dev,
+			"%s: hfidd_stop_adapter: HFI_STOP_NMMU failed"
+			" hvrc = 0x%llx\n", HFIDD_DEV_NAME, hvrc);
 	return;
 }
 
 /*
  * Query the interface to check the logical state of HFI.
- * Enable message passing to each adapter by calling Start
- * Interface hcall.
+ * Initialize the phyp NMMU tables for this lpar by calling
+ * the START NMMU hcall and enable message passing to each
+ * adapter by calling Start Interface hcall.
  */
 static int hfidd_start_adapter(void)
 {
+	long long hvrc;
 	unsigned long long	hfi_state;
 	int i, j;
 	int rc = 0;
 
 	for (i = 0; i < MAX_HFIS; i++) {
+		/* query interface before doing START_NMMU.
+		 * If we crashed the LPAR a few minutes ago, we never did the
+		 * stop interface and the stop nmmu.  Do it now.
+		 */
 		rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
 			hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
 		if (hfi_state != NOT_STARTED) {
@@ -376,6 +389,15 @@ static int hfidd_start_adapter(void)
 
 	}
 
+	hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
+	hvrc = hfidd_start_nmmu(hfidd_global.p_acs[0]);
+	if (hvrc != H_SUCCESS) {
+		dev_printk(KERN_ERR, hfidd_global.p_acs[0]->hfidd_dev,
+			"%s: hfidd_start_adapter: HFI_START_NMMU failed"
+			" hvrc = 0x%llx\n", HFIDD_DEV_NAME, hvrc);
+		return -EIO;
+	}
+
 	for (i = 0; i < MAX_HFIS; i++) {
 		rc = hfidd_start_interface(hfidd_global.p_acs[i]);
 		if (rc) {
@@ -404,6 +426,7 @@ hfidd_start_adapter_err:
 		hfidd_stop_interface(hfidd_global.p_acs[j],
 			hfidd_global.p_acs[j]->dds.hfi_id);
 	}
+	hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
 	return rc;
 }
 
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 6ec9245..320f41f 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -42,8 +42,11 @@ int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
 void hfidd_release_phyp_page(caddr_t page, int size);
 int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
 	unsigned int hfi_id, unsigned long long *state);
+int hfidd_start_nmmu(struct hfidd_acs *p_acs);
 int hfidd_start_interface(struct hfidd_acs *p_acs);
 int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
+long long hfi_start_nmmu(u64 chip_id, void *nmmu_info);
+long long hfi_stop_nmmu(u64 chip_id);
 long long hfi_hquery_interface(u64 unit_id, u64 subtype, u64 query_p,
 		u64 *state);
 long long hfi_start_interface(u64 unit_id);
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 5349e9e..2a374e6 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -39,6 +39,8 @@
 #define H_HFI_START_INTERFACE		0xF000
 #define H_HFI_QUERY_INTERFACE		0xF004
 #define H_HFI_STOP_INTERFACE		0xF008
+#define H_NMMU_START			0xF028
+#define H_NMMU_STOP			0xF02C
 
 #define EEH_QUERY	1
 #define COMP_QUERY	2
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 04/27] HFI: Find HFI devices in the device tree
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_adpt.c  |   10 +++
 drivers/net/hfi/core/hfidd_init.c  |  108 ++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h |    1 +
 include/linux/hfi/hfidd_adpt.h     |    5 ++
 include/linux/hfi/hfidd_client.h   |    3 +
 include/linux/hfi/hfidd_internal.h |   12 ++++
 6 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index d64fa38..d5065cf 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -36,6 +36,7 @@
 int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
 {
 
+	int			ret = 0;
 	struct hfidd_acs	*p_acs = NULL;
 
 	p_acs = kzalloc(sizeof(*p_acs), GFP_KERNEL);
@@ -48,8 +49,17 @@ int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
 	snprintf(p_acs->name, HFI_DEVICE_NAME_MAX - 1,
 			"%s%d", HFIDD_DEV_NAME, p_acs->index);
 
+	ret = hfidd_init_adapter(p_acs, uiop);
+	if (ret)
+		goto err_exit0;
+
 	*adpt = p_acs;
 	return 0;
+
+err_exit0:
+	kfree(p_acs);
+	p_acs = NULL;
+	return ret;
 }
 
 void hfidd_free_adapter(struct hfidd_acs *p_acs)
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 68d6e65..fcdbd03 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/of.h>
 
 #include <linux/hfi/hfidd_internal.h>
 #include "hfidd_proto.h"
@@ -104,6 +105,113 @@ static void hfidd_rmdev(int ai)
 	device_destroy(hfidd_global.class, MKDEV(MAJOR(hfidd_dev), ai));
 }
 
+/*
+ * Read the hfi device tree attributes and
+ * fill the hfidd_dds structure to be used by the driver
+ */
+static int hfidd_dds_init(struct hfidd_acs *p_acs, struct hfidd_dds *pdds)
+{
+	struct device_node	*node;
+	struct device_node	*child_node = NULL;
+	unsigned long long	*lp;
+	int			*p;
+	unsigned char		octant;
+	unsigned char		id;
+	int			found = 0;
+
+	node = of_find_node_by_name(NULL, "hfi-iohub");
+	if (!node) {
+		printk(KERN_ERR "%s: hfidd_dds_init: of_find_node_by_name"
+			" 'hfi-iohub' failed\n", p_acs->name);
+		return -EINVAL;
+	}
+
+	lp = (unsigned long long *)of_get_property(node, "reg", NULL);
+	if (!lp) {
+		printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+			" 'hfi-iohub/reg' failed\n", p_acs->name);
+		return -EINVAL;
+	}
+	pdds->torr_id = *lp;
+
+	lp = (unsigned long long *)of_get_property(node,
+				"ibm,fw-ec-level", NULL);
+	if (!lp) {
+		printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+			" 'ibm,fw-ec-level' failed\n", p_acs->name);
+		return -EINVAL;
+	}
+	pdds->fw_ec_level = *lp;
+
+	octant = (node->full_name[strlen(node->full_name) - 1] - '0');
+	if (octant > HFI_MAX_OCTANT) {
+		printk(KERN_ERR "%s: hfidd_dds_init: invalid hfi-iohub octant"
+			" '%s'\n", node->full_name, p_acs->name);
+		return -EINVAL;
+	}
+
+	id = ((octant << HFI_SHIFT_OCTANT) | p_acs->index);
+
+	while ((child_node = of_get_next_child(node, child_node))) {
+		p = (int *)of_get_property(child_node, "reg", NULL);
+		if (!p) {
+			printk(KERN_ERR "%s: hfidd_dds_init: of_get_property "
+				"'reg' failed\n", p_acs->name);
+			return -EINVAL;
+		}
+
+		if (id == *p) {
+			pdds->hfi_id = *p;
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0) {
+		printk(KERN_ERR "%s: hfidd_dds_init: can not find child\n",
+			p_acs->name);
+		return -EINVAL;
+	}
+
+	lp = (unsigned long long *)of_get_property(child_node,
+					"ibm,hfi-windows", NULL);
+	if (!lp) {
+		printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+			" 'ibm,hfi-windows' failed\n", p_acs->name);
+		return -EINVAL;
+	}
+
+	pdds->window_num   = (int) (*lp >> HFI_WNUM_SHIFT);
+	pdds->window_start = (int) *lp;
+
+	if (pdds->window_num > MAX_WIN_PER_HFI) {
+		printk(KERN_ERR "%s: hfidd_dds_init: Max windows exceeded,"
+			" windows=%d\n", p_acs->name, pdds->window_num);
+		return -EINVAL;
+	}
+
+	lp = (unsigned long long *)of_get_property(child_node,
+				"ibm,hfi-misc-user-base-addr", NULL);
+	if (!lp) {
+		printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+			" 'ibm,hfi-misc-user-base-addr' failed\n", p_acs->name);
+		return -EINVAL;
+	}
+	pdds->misc_base_address = *lp;
+
+	return 0;
+}
+
+/* Initialize adapter structure */
+int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop)
+{
+	int rc = 0;
+
+	rc = hfidd_dds_init(p_acs, &(p_acs->dds));
+	p_acs->dds.num_d_windows = HFI_DYN_WINS_DEFAULT;
+	return rc;
+}
+
 /* Destroy the HFI class */
 static inline void hfidd_destroy_class(void)
 {
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 01a5ba2..e2ed4c9 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -35,5 +35,6 @@
 
 int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
 void hfidd_free_adapter(struct hfidd_acs *p_acs);
+int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 
 #endif
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index 6b1432d..e3271e9 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -36,6 +36,11 @@
 #include <linux/hfi/hfidd_client.h>
 
 
+#define HFI_WNUM_SHIFT		32
+#define HFI_CAUNUM_SHIFT	32
+#define HFI_SHIFT_OCTANT	3
+#define HFI_MAX_OCTANT		7
+
 /* Adpt state */
 #define HFI_INVALID		0
 #define HFI_AVAIL		1
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index b738f4b..28f1693 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -36,5 +36,8 @@
 #define MAX_TORRENTS            1
 #define MAX_HFI_PER_TORRENT     2
 #define MAX_HFIS                (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
+#define MAX_WIN_PER_HFI		256
+
+#define HFI_DYN_WINS_DEFAULT	32
 
 #endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 695d7f4..fafca96 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -46,6 +46,17 @@
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
 
+struct hfidd_dds {
+	unsigned int		version;	/* HFI adapter type */
+	unsigned long long	misc_base_address; /* Misc user base address */
+	int			window_start;	/* window start for this HFI */
+	int			window_num;	/* window count for this HFI */
+	unsigned int		num_d_windows;	/* number of dynamic windows */
+	unsigned long long	torr_id;	/* torrent chip id */
+	unsigned int		hfi_id;		/* HFI Unit Id */
+	unsigned long long	fw_ec_level;	/* Firmware Level */
+};
+
 #define HFI_DEVICE_NAME_MAX 64
 /* hfi global */
 struct hfidd_acs {
@@ -55,6 +66,7 @@ struct hfidd_acs {
 	unsigned int		acs_cnt;
 	unsigned int		state;
 	struct device		*hfidd_dev;
+	struct hfidd_dds	dds;
 };
 
 /* DD global */
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 09/27] HFI: Add HFI window resource tracking
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

An HFI window is very roughly similar to an infiniband UD queue pair.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_adpt.c  |   65 ++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h |    2 +
 include/linux/hfi/hfidd_adpt.h     |   10 +++++
 include/linux/hfi/hfidd_client.h   |   27 +++++++++++++++
 include/linux/hfi/hfidd_internal.h |   43 +++++++++++++++++++++++
 5 files changed, 147 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index feb1b59..372eeec 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -66,6 +66,16 @@ int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
 		goto err_exit0;
 
 	*adpt = p_acs;
+
+	/* alloc window structures */
+	ret = hfidd_alloc_windows(p_acs);
+	if (ret) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_alloc_adapter: hfidd_alloc_windows failed, "
+			"ret = 0x%x\n", ret);
+		goto err_exit0;
+	}
+
 	return 0;
 
 err_exit0:
@@ -76,11 +86,66 @@ err_exit0:
 
 void hfidd_free_adapter(struct hfidd_acs *p_acs)
 {
+	hfidd_free_windows(p_acs);
 	kfree(p_acs);
 	p_acs = NULL;
 	return;
 }
 
+int hfidd_alloc_windows(struct hfidd_acs *p_acs)
+{
+	int		i;
+
+	p_acs->win = kzalloc(sizeof(*p_acs->win) * p_acs->dds.window_num,
+			GFP_KERNEL);
+
+	if (p_acs->win == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_alloc_windows: kzalloc p_acs->win failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < p_acs->dds.window_num; i++) {
+		p_acs->win[i] = kzalloc(sizeof(*(p_acs->win[i])),
+			GFP_KERNEL);
+		if (p_acs->win[i] == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_alloc_windows: kzalloc win 0x%x "
+				"failed\n", i);
+			hfidd_free_windows(p_acs);
+			return -ENOMEM;
+		}
+
+		/* Initialize window fields */
+		spin_lock_init(&(p_acs->win[i]->win_lock));
+
+		p_acs->win[i]->ai = p_acs->index;
+		p_acs->win[i]->index = p_acs->dds.window_start + i;
+
+		if (p_acs->win[i]->index < (p_acs->dds.window_start +
+				MAX_D_WIN_PER_HFI)) {
+			p_acs->win[i]->type  = HFIDD_DYNAMIC_WIN;
+		} else {
+			p_acs->win[i]->type  = HFIDD_RESERVE_WIN;
+		}
+		p_acs->win[i]->state = WIN_AVAILABLE;
+	}
+	return 0;
+}
+
+void hfidd_free_windows(struct hfidd_acs *p_acs)
+{
+	int		i;
+
+	for (i = 0; i < p_acs->dds.window_num; i++) {
+		kfree(p_acs->win[i]);
+		p_acs->win[i] = NULL;
+	}
+	kfree(p_acs->win);
+	p_acs->win = NULL;
+	return;
+}
+
 /* Allocate the page for the HCALL */
 int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page, caddr_t *laddr,
 	int size)
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 320f41f..c61387e 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -35,6 +35,8 @@
 
 int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
 void hfidd_free_adapter(struct hfidd_acs *p_acs);
+int hfidd_alloc_windows(struct hfidd_acs *p_acs);
+void hfidd_free_windows(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 int hfidd_age_hcall(u64 time_start);
 int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index e3271e9..babdb14 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -47,4 +47,14 @@
 #define HFI_GOING_UNAVAIL	2
 #define HFI_UNAVAIL		3
 
+/* HFI window states */
+#define WIN_AVAILABLE		0
+#define WIN_RESERVED		1
+#define WIN_OPENED		2
+#define WIN_SUSPENDED		3
+#define WIN_ERROR		4
+#define WIN_HERROR		5
+#define WIN_PENDING		6
+#define WIN_FAIL_CLOSE		7
+
 #endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index b2ebd01..c3c8fef 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -64,6 +64,33 @@ struct hfi_req_hdr {
 };
 #define HFIDD_REQ_HDR_SIZE			sizeof(struct hfi_req_hdr)
 
+struct fifo_info {
+	struct hfi_64b		eaddr;
+	unsigned long long	size;		/* bytes */
+};
+
+#define HFIDD_IP_WIN		1	/* IP windows get broadcasts forwarded
+						to them... */
+#define HFIDD_KERNEL_WIN	2	/* ... other kernel windows do not */
+#define HFIDD_RESERVE_WIN	3	/* Must be reserved by job scheduler */
+#define HFIDD_DYNAMIC_WIN	4	/* First come, first served. Window# is
+						returned */
+struct hfi_client_info {
+	struct hfi_req_hdr	hdr;
+
+	unsigned int		window;
+	unsigned int		win_type;		/* HFIDD_*_WIN */
+	unsigned int		job_id;
+	unsigned int		protection_key_flag;
+	unsigned int		protection_key;
+	unsigned int		local_isrid;		/* Output */
+	struct fifo_info	sfifo;
+	struct fifo_info	rfifo;
+	struct hfi_64b		sfifo_finish_vec;
+	unsigned int		sfifo_lkey;		/* Output	*/
+	struct hfi_64b		mmio_regs;		/* Output	*/
+};
+
 #define MAX_TORRENTS            1
 #define MAX_HFI_PER_TORRENT     2
 #define MAX_HFIS                (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 311f906..a36c244 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -59,9 +59,13 @@
 #include <asm/pgalloc.h>
 #include <asm/ibmebus.h>
 #include <linux/kthread.h>
+
 #include <linux/hfi/hfidd_client.h>
 #include <linux/hfi/hfidd_adpt.h>
 #include <linux/hfi/hfidd_hcalls.h>
+
+#define MAX_D_WIN_PER_HFI	(p_acs->dds.num_d_windows)
+
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
 
@@ -76,6 +80,44 @@ struct hfidd_dds {
 	unsigned long long	fw_ec_level;	/* Firmware Level */
 };
 
+struct hfidd_fifo {
+	unsigned long long	eaddr;
+	unsigned long long	size;
+};
+
+#define IRQ_NAME_SIZE	20
+
+struct hfidd_window {
+	spinlock_t		win_lock;	/* lock for window */
+	int			index;
+	unsigned int		type;		/* dynamic/scheduled */
+	int			state;
+
+	unsigned int		ai;		/* index to p_acs */
+	unsigned int		is_ip;
+
+	unsigned int		job_id;
+	unsigned int		pid;
+	unsigned int		protection_key_flag;	/* by job/task */
+
+	unsigned int		recv_intr;		/* Recv interrupt */
+	unsigned int		send_intr;		/* Send interrupt */
+	char			recv_name[IRQ_NAME_SIZE];
+	char			send_name[IRQ_NAME_SIZE];
+
+	uid_t			uid;
+
+	struct hfi_client_info	client_info;		/* From user input */
+	struct win_open_info	*win_open_info_p;	/* virtual addr
+							   OPEN_WINDOW hcall */
+	caddr_t			win_open_info_laddr;	/* logical addr
+							   OPEN_WINDOW hcall */
+	unsigned long long	mmio_regs;		/* logical addr from
+							   OPEN WINDOW hcall */
+	struct hfidd_vlxmem	*sfifo_x_tab;
+	struct hfidd_vlxmem	*rfifo_x_tab;
+};
+
 #define HFI_DEVICE_NAME_MAX 64
 /* hfi global */
 struct hfidd_acs {
@@ -87,6 +129,7 @@ struct hfidd_acs {
 
 	unsigned int		isr;
 
+	struct hfidd_window	**win;
 	struct device		*hfidd_dev;
 	struct hfidd_dds	dds;
 };
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Set up protocol access to an HFI window.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/Makefile       |    1 +
 drivers/net/hfi/core/hfidd_init.c   |   14 +++++++
 drivers/net/hfi/core/hfidd_proto.h  |    3 +
 drivers/net/hfi/core/hfidd_window.c |   70 +++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_client.h    |   22 +++++++++++
 include/linux/hfi/hfidd_internal.h  |   26 +++++++++++++
 include/linux/hfi/hfidd_requests.h  |    1 +
 7 files changed, 137 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_window.c

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 4e6cbd6..0224a57 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -2,6 +2,7 @@
 # Makefile for the HFI device driver for IBM eServer System p
 #
 hfi_core-objs:=	hfidd_adpt.o \
+		hfidd_window.o \
 		hfidd_init.o \
 		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index a57f247..1008260 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -130,6 +130,20 @@ static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
 	}
 
 	switch (cmd.req) {
+	case HFIDD_REQ_OPEN_WINDOW:
+		if (cmd.req_len != sizeof(struct hfi_client_info)) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_cmd_write: hdr.reqlen 0x%x expected "
+				"0x%lx for cmd req 0x%x\n",
+				cmd.req_len,
+				sizeof(struct hfi_client_info), cmd.req);
+			return -EINVAL;
+		}
+		rc = hfidd_open_window_func(p_acs, is_userspace,
+			(struct hfi_client_info *) buf,
+			(struct hfi_client_info *) cmd.result.use.kptr);
+		break;
+
 	case HFIDD_REQ_QUERY_DD_INFO:
 		if (cmd.req_len != sizeof(struct hfi_query_dd_info)) {
 			dev_printk(KERN_ERR, p_acs->hfidd_dev,
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index c61387e..e7f2901 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,6 +39,9 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
 void hfidd_free_windows(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 int hfidd_age_hcall(u64 time_start);
+int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+		struct hfi_client_info *user_p,
+		struct hfi_client_info *out_p);
 int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
 	caddr_t *laddr, int size);
 void hfidd_release_phyp_page(caddr_t page, int size);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
new file mode 100644
index 0000000..f16caf7
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -0,0 +1,70 @@
+/*
+ * hfidd_window.c
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_hcalls.h>
+#include "hfidd_proto.h"
+#include <linux/hfi/hfidd_requests.h>
+
+/*
+ * Allows an user/kernel window to send/receive network traffic thru HFI
+ * adapter. This function will allocate the system resources needed to open
+ * a window. If any problem detected, then the request will fail. This function
+ * is called directly by kernel users and by a write system call by userspace.
+ */
+int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+		struct hfi_client_info *user_p,
+		struct hfi_client_info *out_p)
+{
+	int			rc = 0;
+	struct hfi_client_info	*local_p = NULL;
+
+	/* Allocate local data structure */
+	local_p = kmalloc(sizeof(struct hfi_client_info), GFP_KERNEL);
+	if (local_p == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"open_window_func: kmalloc local_p failed\n");
+		return -ENOMEM;
+	}
+
+	/* Copy into local from user */
+	rc = hfi_copy_from_user((void *)local_p, (void *)user_p,
+			is_userspace, sizeof(struct hfi_client_info));
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"open_window_func: hfi_copy_from_user failed\n");
+	}
+
+	kfree(local_p);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(hfidd_open_window_func);
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index c3c8fef..7e4c1a7 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -69,6 +69,28 @@ struct fifo_info {
 	unsigned long long	size;		/* bytes */
 };
 
+/*
+ * HFIDD_REQ_OPEN_WINDOW: Window Open
+ * For reserved windows
+ *	The job scheduler provides the application with window number and
+ *	jobid, which need to be passed in/will be checked on the window open.
+ *	Immediate send slots were also reserved by the job scheduler, and the
+ *	DD returns the count. The application has the option of setting
+ *	protection keys by task or by jobid. Protection key is passed in.
+ * For Dynamic windows
+ *	The DD will select a free dynamic window and return its window number.
+ *	The jobid will be assigned by the DD (upper bits set to select a
+ *	reserved range of jobids, lower bits come from userid).  The
+ *	protection key flag is always by task. The protection key is passed in.
+ * For Kernel/IP windows
+ *	The DD will select a free dynamic window and return its window number.
+ *	The jobid is passed in. The jobid is used for the protection key.
+ *
+ * Finished vectors:
+ *	sfifo_finishvec and imm_finishvec must reside in an extra page (last
+ *	page) in the sfifo memory range, provided by the user.
+ */
+
 #define HFIDD_IP_WIN		1	/* IP windows get broadcasts forwarded
 						to them... */
 #define HFIDD_KERNEL_WIN	2	/* ... other kernel windows do not */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index a36c244..dd1ce4c 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -142,4 +142,30 @@ struct hfidd_global {
 	struct hfidd_acs	*p_acs[MAX_HFIS];
 };
 
+static inline int hfi_copy_to_user(void *user_p, void *local_p,
+		unsigned int is_userspace, unsigned int size)
+{
+	int	rc = 0;
+
+	if (is_userspace)
+		rc = copy_to_user(user_p, local_p, size);
+	else
+		memcpy(user_p, local_p, size);
+
+	return rc;
+}
+
+static inline int hfi_copy_from_user(void *local_p, void *user_p,
+		unsigned int is_userspace, unsigned int size)
+{
+	int	rc = 0;
+
+	if (is_userspace)
+		rc = copy_from_user(local_p, user_p, size);
+	else
+		memcpy(local_p, user_p, size);
+
+	return rc;
+}
+
 #endif
diff --git a/include/linux/hfi/hfidd_requests.h b/include/linux/hfi/hfidd_requests.h
index b6e255f..4f1c74d 100644
--- a/include/linux/hfi/hfidd_requests.h
+++ b/include/linux/hfi/hfidd_requests.h
@@ -33,6 +33,7 @@
 #ifndef _HFIDD_REQUESTS_H_
 #define _HFIDD_REQUESTS_H_
 
+#define HFIDD_REQ_OPEN_WINDOW			0x00000a01
 #define HFIDD_REQ_QUERY_DD_INFO			0x00001004
 
 #endif /* _HFIDD_REQUESTS_H_ */
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_init.c |   98 +++++++++++++++++++++++++++++++++++++
 1 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index fcdbd03..9dfd2b4 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -319,6 +319,94 @@ hfidd_create_devices_error0:
 	return rc;
 }
 
+/*
+ * Disable message passing to each adapter by calling the
+ * Stop Interface hcall.
+ */
+static void hfidd_stop_adapter(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_HFIS; i++) {
+		hfidd_stop_interface(hfidd_global.p_acs[i],
+			hfidd_global.p_acs[i]->dds.hfi_id);
+	}
+	return;
+}
+
+/*
+ * Query the interface to check the logical state of HFI.
+ * Enable message passing to each adapter by calling Start
+ * Interface hcall.
+ */
+static int hfidd_start_adapter(void)
+{
+	unsigned long long	hfi_state;
+	int i, j;
+	int rc = 0;
+
+	for (i = 0; i < MAX_HFIS; i++) {
+		rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
+			hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
+		if (hfi_state != NOT_STARTED) {
+			rc = hfidd_stop_interface(hfidd_global.p_acs[i],
+					hfidd_global.p_acs[i]->dds.hfi_id);
+			if (rc) {
+				dev_printk(KERN_ERR,
+					hfidd_global.p_acs[i]->hfidd_dev,
+					"%s: hfidd_start_adapter:"
+					" hfidd_stop_interface failed rc = "
+					" 0x%x\n", hfidd_global.p_acs[i]->name,
+				rc);
+			}
+
+			rc = hfidd_query_interface(hfidd_global.p_acs[i],
+					COMP_QUERY,
+					hfidd_global.p_acs[i]->dds.hfi_id,
+					&hfi_state);
+			if (hfi_state != NOT_STARTED) {
+				dev_printk(KERN_ERR,
+					hfidd_global.p_acs[i]->hfidd_dev,
+					"%s: hfidd_start_adapter: query"
+					" interface bad state 0x%llx\n",
+					hfidd_global.p_acs[i]->name, hfi_state);
+				return -EIO;
+			}
+		}
+
+	}
+
+	for (i = 0; i < MAX_HFIS; i++) {
+		rc = hfidd_start_interface(hfidd_global.p_acs[i]);
+		if (rc) {
+			dev_printk(KERN_ERR, hfidd_global.p_acs[i]->hfidd_dev,
+				"%s: hfidd_start_adapter: "
+				"hfidd_start_interface failed rc = "
+				"%d\n", hfidd_global.p_acs[i]->name, rc);
+			goto hfidd_start_adapter_err;
+		}
+
+		/* query interface to get src ISR */
+		rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
+				hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
+		if (rc) {
+			dev_printk(KERN_ERR, hfidd_global.p_acs[i]->hfidd_dev,
+				"%s: hfidd_start_adapter: "
+				"hfidd_query_interface failed rc = %d\n",
+				hfidd_global.p_acs[i]->name, rc);
+			goto hfidd_start_adapter_err;
+		}
+	}
+	return 0;
+
+hfidd_start_adapter_err:
+	for (j = 0; j < i; j++) {
+		hfidd_stop_interface(hfidd_global.p_acs[j],
+			hfidd_global.p_acs[j]->dds.hfi_id);
+	}
+	return rc;
+}
+
 static int __init hfidd_mod_init(void)
 {
 	int			rc = 0;
@@ -339,9 +427,18 @@ static int __init hfidd_mod_init(void)
 		goto error1;
 	}
 
+	rc = hfidd_start_adapter();
+	if (rc < 0) {
+		printk(KERN_ERR "%s: hfidd_mod_init: hfidd_start_adapter failed"
+			" rc = %d\n", HFIDD_DEV_NAME, rc);
+		goto error2;
+	}
+
 	printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
 	return 0;
 
+error2:
+	hfidd_destroy_devices();
 error1:
 	hfidd_destroy_class();
 
@@ -351,6 +448,7 @@ error1:
 
 static void __exit hfidd_mod_exit(void)
 {
+	hfidd_stop_adapter();
 	hfidd_destroy_devices();
 	hfidd_destroy_class();
 }
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 25/27] HFI: hf fifo transmit paths
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/ip/hf_if_main.c |  436 ++++++++++++++++++++++++++++++++++++++-
 drivers/net/hfi/ip/hf_proto.h   |    1 +
 include/linux/hfi/hf_if.h       |   73 +++++++-
 3 files changed, 508 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
index 329baa1..ea4579e 100644
--- a/drivers/net/hfi/ip/hf_if_main.c
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -208,6 +208,87 @@ alloc_resource_err0:
 	return rc;
 }
 
+static int hf_send_intr_callback(void *parm, u32 win, u32 ext)
+{
+	struct hf_net	*net = (struct hf_net *)parm;
+	struct hf_if	*net_if = &(net->hfif);
+	u64		sintr_status;
+
+	sintr_status = hf_mmio_regs_read(net_if, HFI_SINTR_STATUS_REG);
+
+	netdev_info(net->netdev, "hf_send_intr_callback: "
+		"sintr_status 0x%016llx", sintr_status);
+
+	/* mask off the interrupt */
+	if (sintr_status & HF_SFIFO_INTR_EVENT)
+		hf_mmio_regs_write(net_if, HFI_SFIFO_INTR_CNTL, 0);
+
+	/* Make sure interrupts are masked */
+	/* Otherwise after the queue is awaken, it will get stale interrupt */
+	mb();
+
+	netif_wake_queue(net->netdev);
+
+	return 0;
+}
+
+struct hf_events_cb hf_events[HF_EVENT_NUM] = {
+	{HFIDD_SEND,		(void *)hf_send_intr_callback},
+};
+
+static int hf_register_ip_events(struct hf_net *net,
+				 struct hfidd_acs *p_acs,
+				 int flag)
+{
+	struct hf_if		*net_if = &(net->hfif);
+	int			rc = 0, i, j;
+	struct hfi_reg_events	events[HF_EVENT_NUM];
+	int			(*reg_func)(struct hfidd_acs *,
+				struct hfi_reg_events *);
+
+	if (flag == HFIDD_REQ_EVENT_REGISTER)
+		reg_func = hfidd_callback_register;
+	else
+		reg_func = hfidd_callback_unregister;
+
+	for (i = 0; i < HF_EVENT_NUM; i++) {
+		events[i].window = net_if->client.window;
+		events[i].type = FUNCTIONS_FOR_EVENTS;
+		events[i].info.func.index = hf_events[i].type;
+		events[i].info.func.function_p.use.kptr = hf_events[i].func;
+		events[i].info.func.parameter.use.kptr = (void *)(net);
+
+		events[i].hdr.req = flag;
+		events[i].hdr.req_len = sizeof(struct hfi_reg_events);
+		events[i].hdr.result.use.kptr = &(events[i]);
+
+		rc = reg_func(p_acs, &(events[i]));
+		if (rc) {
+			netdev_err(net->netdev, "hf_register_ip_events: "
+				"fail event 0x%x, flag=0x%x rc=0x%x\n",
+				hf_events[i].type, flag, rc);
+
+			if (flag == HFIDD_REQ_EVENT_REGISTER)
+				goto err_out;
+		}
+	}
+
+	return rc;
+
+err_out:
+	for (j = 0; j < i; j++) {
+		events[j].hdr.req = HFIDD_REQ_EVENT_UNREGISTER;
+		rc = hfidd_callback_unregister(p_acs, &(events[i]));
+		if (rc) {
+			netdev_err(net->netdev, "hf_register_ip_events: failed "
+				"to unregister callback event 0x%x, rc=0x%x\n",
+				events[i].info.func.index, rc);
+		}
+	}
+
+	return rc;
+}
+
 static int hf_close_ip_window(struct hf_if *net_if, struct hfidd_acs *p_acs)
 {
 	int		rc;
@@ -295,6 +376,16 @@ static int hf_set_mac_addr(struct net_device *netdev, void *p)
 	return 0;
 }
 
+static void hf_init_hw_regs(struct hf_if *net_if)
+{
+	/* setup IP with payload threshold in cache line size */
+	hf_mmio_regs_write(net_if, HFI_IP_RECV_SIZE,
+		(HF_PAYLOAD_RX_THRESHOLD << HF_PAYLOAD_RX_THRESH_SHIFT));
+
+	/* initialize SEND INTR STATUS */
+	hf_mmio_regs_write(net_if, HFI_SINTR_STATUS_REG, 0);
+}
+
 static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
 {
 	struct net_device	*netdev = (struct net_device *)parm;
@@ -320,13 +411,25 @@ static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
 	if (rc)
 		goto delayed_open_err1;
 
+	rc = hf_register_ip_events(net, p_acs, HFIDD_REQ_EVENT_REGISTER);
+	if (rc)
+		goto delayed_open_err2;
+
 	hf_set_mac_addr(netdev, NULL);
 
+	hf_init_hw_regs(net_if);
+
 	net_if->state = HF_NET_OPEN;
 	spin_unlock(&(net_if->lock));
 
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
 	return 0;
 
+delayed_open_err2:
+	hf_close_ip_window(net_if, p_acs);
+
 delayed_open_err1:
 	hf_free_resource(net_if);
 
@@ -408,6 +511,11 @@ static int hf_net_close(struct net_device *netdev)
 
 	spin_lock(&(net_if->lock));
 	if (net_if->state == HF_NET_OPEN) {
+		netif_stop_queue(netdev);
+		netif_carrier_off(netdev);
+
+		hf_register_ip_events(net, p_acs, HFIDD_REQ_EVENT_UNREGISTER);
+
 		hf_close_ip_window(net_if, p_acs);
 
 		hf_free_resource(net_if);
@@ -422,6 +530,328 @@ static int hf_net_close(struct net_device *netdev)
 	return 0;
 }
 
+static void hf_tx_recycle(struct hf_if *net_if)
+{
+	u32		head, head_idx, slots_per_blk;
+	u32		*fv;
+	int		i;
+	u32		fv_bit;
+	u8		nr;
+
+	head = net_if->tx_fifo.head;
+
+	slots_per_blk = net_if->sfifo_slots_per_blk;
+
+	head_idx = head / slots_per_blk;
+
+	fv = (u32 *)(net_if->sfifo_finishvec);
+
+	while (1) {
+		nr = HF_FV_BIT_MAX - head_idx;
+		fv_bit = BIT(nr) & (ACCESS_ONCE(*fv));
+		fv_bit = fv_bit >> nr;
+
+		if ((fv_bit ^ (net_if->sfifo_fv_polarity)) == 0)
+			break;
+
+		for (i = 0; i < slots_per_blk; i++) {
+			struct sk_buff		*skb;
+
+			skb = net_if->tx_skb[head + i];
+			if (skb != NULL) {
+				dev_kfree_skb_any(skb);
+				net_if->tx_skb[head + i] = NULL;
+			}
+		}
+
+		head = (head + slots_per_blk) & (net_if->tx_fifo.emax);
+
+		atomic_add(slots_per_blk, &(net_if->tx_fifo.avail));
+
+		if (++head_idx == HF_FV_BIT_CNT) {
+			head_idx = 0;
+			net_if->sfifo_fv_polarity ^= 1;
+		}
+	}
+
+	net_if->tx_fifo.head = head;
+
+	return;
+}
+
+int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls)
+{
+	struct net_device	*netdev = net->netdev;
+	struct hf_if		*net_if = &(net->hfif);
+
+	if (atomic_read(&net_if->tx_fifo.avail) < xmit_cls) {
+
+		hf_tx_recycle(net_if);
+
+		if (atomic_read(&net_if->tx_fifo.avail) < xmit_cls) {
+			u32		intr_cntl;
+			u64		intr_thresh;
+
+			netif_stop_queue(netdev);
+
+			/* turn on transmit interrupt */
+			intr_thresh = (net_if->sfifo_packets -
+			HF_SFIFO_INTR_WATERMARK) & HF_SFIFO_INTR_MASK;
+
+			intr_cntl = HF_SFIFO_INTR_ENABLE |
+			(intr_thresh << HF_SFIFO_INTR_CNT_SHIFT);
+
+			hf_mmio_regs_write_then_read(net_if,
+					HFI_SFIFO_INTR_CNTL, intr_cntl);
+
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+static inline void hf_fill_route(u16 dst_isr, struct base_hdr *base_hdr_p)
+{
+	base_hdr_p->route_control = HFI_HW_DIRECT_ROUTE;
+}
+
+static int hf_copy_skb_to_fifo(struct hf_if *net_if,
+				struct sk_buff *skb,
+				char *dst,
+				u32 len,
+				u32 offset)
+{
+	u64		fifo_end;
+	u32		tail_room;
+	int		rc;
+
+	fifo_end = (u64)(net_if->tx_fifo.addr) + net_if->tx_fifo.size;
+
+	tail_room = fifo_end - (u64)dst;
+	if (tail_room >= len) {
+		rc = skb_copy_bits(skb, offset, dst, len);
+		if (rc) {
+			printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+				"fail1 offset=0x%x, len=0x%x, rc=0x%x\n",
+				offset, len, rc);
+			return rc;
+		}
+	} else {
+		rc = skb_copy_bits(skb, offset, dst, tail_room);
+		if (rc) {
+			printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+				"fail2 offset=0x%x, len=0x%x, rc=0x%x\n",
+				offset, tail_room, rc);
+
+			return rc;
+		}
+		rc = skb_copy_bits(skb, offset + tail_room,
+				net_if->tx_fifo.addr, len - tail_room);
+		if (rc) {
+			printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+				"fail3 offset=0x%x, len=0x%x, rc=0x%x\n",
+				offset + tail_room, len - tail_room, rc);
+
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/* Build base_hdr and proto_hdr for payload pkt.
+   Return pointer to the end of proto_hdr */
+static char *hf_build_payload_hdr(struct hf_net *net,
+				  struct sk_buff *skb,
+				  u32 msg_len,
+				  u32 xmit_cls,
+				  u32 is_bcast)
+{
+	struct hf_if			*net_if = &(net->hfif);
+	struct hf_if_proto_hdr		*proto_hdr_p;
+	struct hfi_ip_with_payload_pkt	*hdr_p;
+	char				*dst;
+	u8				msg_type, msg_flag;
+	struct hf_hwhdr			*hwhdr_p;
+
+	hwhdr_p = (struct hf_hwhdr *)(skb->data);
+
+	if (hwhdr_p->h_proto == htons(ETH_P_IP))
+		msg_type = HF_IF_FIFO;
+	else if (hwhdr_p->h_proto == htons(ETH_P_ARP))
+		msg_type = HF_IF_ARP;
+	else {
+		netdev_err(net->netdev, "hf_build_payload_hdr: h_proto = 0x%x "
+			" not supported\n", hwhdr_p->h_proto);
+
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+
+	dst = net_if->tx_fifo.addr +
+		(net_if->tx_fifo.tail << HFI_CACHE_LINE_SHIFT);
+
+	/* fill in base_hdr + ip_extended_hdr */
+	hdr_p = (struct hfi_ip_with_payload_pkt *)dst;
+
+	/* Do not memset over one cacheline since it might wrap */
+	memset(hdr_p, 0, HF_IP_HDR_LEN);
+
+	hdr_p->hfi_hdr.type.header_type = HFI_IP_WITH_PAYLOAD;
+	hdr_p->hfi_hdr.id.job_id = net_if->client.job_id;
+
+	if (is_bcast) {
+		hdr_p->hfi_hdr.base_hdr.dst_isr = HFIDD_DST_BCST_ISR;
+		hdr_p->hfi_hdr.base_hdr.dst_win = HFIDD_DST_BCST_WIN;
+		hdr_p->hfi_hdr.type.header_type = HFI_IP_MULTICAST_WITH_PAYLOAD;
+
+		msg_flag = HF_IF_BCAST;
+	} else {
+		u16	dst_isr, dst_win;
+
+		hf_get_dst_info(hwhdr_p, &dst_isr, &dst_win);
+		hdr_p->hfi_hdr.base_hdr.dst_isr = dst_isr;
+		hdr_p->hfi_hdr.base_hdr.dst_win = dst_win;
+
+		hf_fill_route(dst_isr, &(hdr_p->hfi_hdr.base_hdr));
+
+		msg_flag = HF_IF_UCAST;
+	}
+
+	netdev_dbg(net->netdev, "hf_build_payload_hdr: dst_isr = 0x%x, "
+			"dst_win = 0x%x, xmit_cls = 0x%x\n",
+			hdr_p->hfi_hdr.base_hdr.dst_isr,
+			hdr_p->hfi_hdr.base_hdr.dst_win, xmit_cls);
+
+	hdr_p->hfi_hdr.base_hdr.pkt_len = hfi_cachelines_to_pktlen(xmit_cls);
+
+	dst += HF_IP_HDR_LEN;
+	proto_hdr_p = (struct hf_if_proto_hdr *)dst;
+
+	proto_hdr_p->version = HF_PROTO_HDR_VERSION;
+	proto_hdr_p->msg_len = msg_len;
+	proto_hdr_p->msg_id = net_if->msg_id;
+	proto_hdr_p->msg_type = msg_type;
+	proto_hdr_p->msg_flag = msg_flag;
+
+	dst += HF_PROTO_LEN;
+
+	return dst;
+}
+
+static int hf_payload_tx(struct sk_buff *skb, struct hf_net *net, u32 is_bcast)
+{
+	struct hf_if		*net_if = &(net->hfif);
+	u32			msg_len, len;
+	u32			xmit_cls;
+	char			*dst;
+	int			rc = 0;
+
+	msg_len = skb->len - HF_HLEN + HF_PROTO_LEN;
+	xmit_cls = hfi_bytes_to_cacheline(msg_len + HF_IP_HDR_LEN);
+
+	if (is_bcast) {
+		if (xmit_cls <= HF_BCAST_CACHE_LINE_2)
+			xmit_cls = HF_BCAST_CACHE_LINE_2;
+		else
+			xmit_cls = HF_BCAST_CACHE_LINE_16;
+	}
+
+	rc = hf_tx_check_avail(net, xmit_cls);
+	if (rc) {
+		netdev_err(net->netdev, "hf_payload_tx: hf_tx_check_avail find "
+				"no avail slot\n");
+		return rc;
+	}
+
+	dst = hf_build_payload_hdr(net, skb, msg_len, xmit_cls, is_bcast);
+	if (!dst)
+		return 0;
+
+	/* copy skb data, skipping hwhdr */
+	len = skb->len - HF_HLEN;
+
+	rc = hf_copy_skb_to_fifo(net_if, skb, dst, len, HF_HLEN);
+	if (rc)
+		return rc;
+
+	net_if->tx_fifo.tail =
+		(net_if->tx_fifo.tail + xmit_cls) & (net_if->tx_fifo.emax);
+	atomic_sub(xmit_cls, &(net_if->tx_fifo.avail));
+
+	net_if->sfifo_packets++;
+	net_if->net_stats.tx_packets++;
+	net_if->net_stats.tx_bytes += msg_len;
+
+	netdev_dbg(net->netdev, "hf_payload_tx: exit, tx_fifo tail = 0x%x, "
+		"avail = 0x%x, skb->len = 0x%x\n", net_if->tx_fifo.tail,
+		atomic_read(&(net_if->tx_fifo.avail)), skb->len);
+
+	dev_kfree_skb_any(skb);
+	return 0;
+
+}
+
+static int hf_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct hf_net	*net = netdev_priv(netdev);
+	struct hf_if	*net_if = &(net->hfif);
+	u32		len, is_bcast;
+	u32		send_cnt = 1;
+
+	is_bcast = !memcmp(((struct hf_hwhdr *)(skb->data))->h_dest,
+				netdev->broadcast,
+				netdev->addr_len);
+
+	if (unlikely(skb->len <= 0)) {
+		netdev_err(netdev, "hf_start_xmit: invalid skb->len 0x%x\n",
+						skb->len);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* total len to transfer */
+	len = skb->len - HF_HLEN;
+
+	if (len <= HF_PAYLOAD_MAX) {
+		/* send ip with payload */
+		if (hf_payload_tx(skb, net, is_bcast) < 0) {
+			netdev_err(netdev, "hf_start_xmit: "
+				"hf_payload_tx fail 1\n");
+
+			return NETDEV_TX_BUSY;
+		}
+	} else {
+		netdev_err(netdev, "hf_start_xmit: skb->len 0x%x "
+			"greater than max 0x%x\n",
+			skb->len, (u32)HF_PAYLOAD_MAX);
+
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* Make sure all fields are written before ringing hw doorbell */
+	wmb();
+
+	/* ring doorbell */
+	hf_mmio_regs_write(net_if, HFI_SFIFO_DB_REG, send_cnt);
+
+	if (atomic_read(&net_if->tx_fifo.avail) < HF_TX_LOW_WATERMARK)
+		hf_tx_check_avail(net, HF_TX_LOW_WATERMARK);
+
+	net_if->msg_id++;
+	netdev->trans_start = jiffies;
+
+	return NETDEV_TX_OK;
+}
+
+static void hf_tx_timeout(struct net_device *netdev)
+{
+	netdev_warn(netdev, "hf_tx_timeout: queue_stopped is %d\n",
+			netif_queue_stopped(netdev));
+}
+
 struct net_device_stats *hf_get_stats(struct net_device *netdev)
 {
 	struct hf_net	*net = netdev_priv(netdev);
@@ -480,6 +910,8 @@ static const struct net_device_ops hf_netdev_ops = {
 	.ndo_open		= hf_net_open,
 	.ndo_stop		= hf_net_close,
 	.ndo_change_mtu		= hf_change_mtu,
+	.ndo_start_xmit		= hf_start_xmit,
+	.ndo_tx_timeout		= hf_tx_timeout,
 	.ndo_set_mac_address	= NULL,
 	.ndo_get_stats		= hf_get_stats,
 };
@@ -497,6 +929,7 @@ static void hf_if_setup(struct net_device *netdev)
 	netdev->header_ops	= &hf_header_ops;
 	netdev->netdev_ops	= &hf_netdev_ops;
 
+	netdev->watchdog_timeo	= HF_TX_TIMEOUT;
 	netdev->features       |= NETIF_F_SG;
 
 	memcpy(netdev->broadcast, hfi_bcast_addr, HF_ALEN);
@@ -534,7 +967,7 @@ static struct hf_net *hf_init_netdev(int idx, int ai)
 	if (rc) {
 		printk(KERN_ERR "hf_init_netdev: "
 				"failed to register netdev=hfi%d:hf%d, "
-				"rc 0x%x\n", ai, idx, rc);
+				"rc = 0x%x\n", ai, idx, rc);
 		free_netdev(netdev);
 		return (struct hf_net *) -ENODEV;
 	}
@@ -601,6 +1034,7 @@ static void __exit hf_cleanup_module(void)
 	unregister_inetaddr_notifier(&hf_inet_notifier);
 	for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
 		for (ai = 0; ai < MAX_HFIS; ai++) {
+
 			net = hf_ginfo.net[idx][ai];
 			if (net != NULL) {
 				hf_del_netdev(net);
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
index f2b159e..b7c6d3c 100644
--- a/drivers/net/hfi/ip/hf_proto.h
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -33,6 +33,7 @@
 #ifndef _HF_PROTO_H_
 #define _HF_PROTO_H_
 
+int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls);
 extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
 		u32 is_userspace,
 		struct hfi_client_info *user_p,
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
index d13c6ab..90b6331 100644
--- a/include/linux/hfi/hf_if.h
+++ b/include/linux/hfi/hf_if.h
@@ -43,6 +43,7 @@
 #include <linux/hfi/hfidd_internal.h>
 #include <linux/hfi/hfidd_client.h>
 #include <linux/hfi/hfidd_requests.h>
+#include <linux/hfi/hfidd_regs.h>
 #include <linux/hfi/hfidd_pkt_formats.h>
 
 #define HF_DRV_VERSION			"1.0"
@@ -51,15 +52,31 @@
 
 #define MAX_HF_PER_HFI			2
 #define	HF_IP_JOBID			0xFFFFFFF0
+#define HF_TX_TIMEOUT			(500 * HZ)
 #define HF_MAX_NAME_LEN			64
 
+/* sfifo intr: bit 39-55 is threshold */
+/*             bit 34 enable, bit 35 unmask */
+#define HF_SFIFO_INTR_ENABLE		(0x3 << (63 - 35))
+#define HF_SFIFO_INTR_MASK		0x1FFFF		/* 17 bits */
+#define HF_SFIFO_INTR_CNT_SHIFT		(63 - 55)
+#define HF_SFIFO_INTR_EVENT		0x00000040 /* bit 57 */
+#define HF_SFIFO_INTR_WATERMARK		(HF_SFIFO_SLOTS - (HF_SFIFO_SLOTS >> 3))
+
 #define HF_SFIFO_SIZE			0x40000	/* 256K */
 #define HF_SFIFO_SLOTS			(HF_SFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
 #define HF_RFIFO_SIZE			0x1000000	/* 16M */
 #define HF_RFIFO_SLOTS			(HF_RFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+#define HF_TX_LOW_WATERMARK		(HF_SFIFO_SLOTS >> 4)
 
 #define HF_FV_BIT_CNT			32
-#define HF_NET_MTU			(2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+#define HF_FV_BIT_MAX			31
+#define HF_SEND_ONE			1
+
+#define HF_PAYLOAD_MAX			(2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+#define HF_NET_MTU			HF_PAYLOAD_MAX
+#define HF_PAYLOAD_RX_THRESHOLD		0x10ULL
+#define HF_PAYLOAD_RX_THRESH_SHIFT	59
 
 struct hfi_ip_extended_hdr {            /* 16B */
 	u32		immediate_len:7;/* In bytes */
@@ -91,6 +108,15 @@ struct hf_hwhdr {
 #define HF_HLEN				sizeof(struct hf_hwhdr)
 #define HF_ALIGN_PAD			2
 
+#define HF_PROTO_HDR_VERSION		0x1
+/* HFI protocol message type */
+#define	HF_IF_ARP			0xA0
+#define	HF_IF_FIFO			0xA1
+
+/* HFI protocol message flag */
+#define	HF_IF_UCAST			0xB0
+#define	HF_IF_BCAST			0xB1
+
 struct hf_if_proto_hdr {
 	u16			version;
 	u8			msg_type;
@@ -100,6 +126,8 @@ struct hf_if_proto_hdr {
 };
 
 #define HF_PROTO_LEN		sizeof(struct hf_if_proto_hdr)
+#define HF_BCAST_CACHE_LINE_16	16
+#define HF_BCAST_CACHE_LINE_2	2
 
 struct hf_fifo {
 	void			*addr;
@@ -126,6 +154,7 @@ struct hf_if {
 	u32			sfifo_fv_polarity;
 	u32			sfifo_slots_per_blk;
 	u32			sfifo_packets;
+	u32			msg_id;
 	void __iomem		*doorbell;		/* mapped mmio_regs */
 	struct hf_fifo		tx_fifo;
 	struct hf_fifo		rx_fifo;
@@ -152,5 +181,47 @@ struct hf_global_info {
 
 extern struct hf_global_info	hf_ginfo;
 
+#define HF_EVENT_NUM		1
+
+struct hf_events_cb {
+	enum hfi_event_type	type;
+	void			*func;
+};
+
 #define HF_MAC_HFI_SHIFT	12
+#define HF_HDR_HFI_SHIFT	8
+
+static inline u32 hf_get_win(u16 id)
+{
+	return ((id >> HF_MAC_HFI_SHIFT) << HF_HDR_HFI_SHIFT) | (id & 0xFF);
+}
+
+static inline void hf_get_dst_info(struct hf_hwhdr *hwhdr_p,
+				   u16 *d_isr,
+				   u16 *d_win)
+{
+	*d_isr = (*(u16 *)(&(hwhdr_p->h_dest[2]))) & 0xFFF;
+	*d_win = hf_get_win(*(u16 *)(&(hwhdr_p->h_dest[4])));
+}
+
+static inline void hf_mmio_regs_write_then_read(struct hf_if *net_if,
+				int off,
+				u64 data)
+{
+	__raw_writeq(data, net_if->doorbell + off);
+	isync();
+	__raw_readq(net_if->doorbell + off);
+	/* Make sure all received pkt shows up in rfifo */
+	mb();
+}
+
+static inline u64 hf_mmio_regs_read(struct hf_if *net_if, int off)
+{
+	return __raw_readq(net_if->doorbell + off);
+}
+
+static inline void hf_mmio_regs_write(struct hf_if *net_if, int off, u64 data)
+{
+	__raw_writeq(data, net_if->doorbell + off);
+}
 #endif
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 11/27] HFI: Check window number/assign window number
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

RESERVED windows are reserved by a job scheduler before the application starts.
the application is given a list of windows to use, the DD has to check that
they are opening one of the windows assigned to that jobid.
DYNAMIC windows are used without a job scheduler; the application calls into
the DD and asks for any free window.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_window.c |  161 +++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_internal.h  |   16 ++++
 2 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index f16caf7..cc775e3 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -35,6 +35,153 @@
 #include "hfidd_proto.h"
 #include <linux/hfi/hfidd_requests.h>
 
+/* Validate the type, state and job id for RESERVED window */
+static int hfi_validate_reserve_window_id(struct hfidd_acs *p_acs,
+		struct hfi_client_info *client_p)
+{
+	struct hfidd_window	*win_p;
+
+	/* Check if win is between min_hfi_windows and max_hfi_windows */
+	if ((client_p->window < min_hfi_windows(p_acs)) ||
+	    (client_p->window >= max_hfi_windows(p_acs))) {
+
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_reserve_window_id: window = 0x%x too big\n",
+			client_p->window);
+		return -EINVAL;
+	}
+
+	/* Check if win_p indexed by window is not NULL */
+	win_p = hfi_window(p_acs, client_p->window);
+	if (win_p == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_reserve_window_id: win 0x%x win_p is NULL\n",
+			client_p->window);
+		return -EINVAL;
+	}
+
+	spin_lock(&(win_p->win_lock));
+	/*
+	 * Check if win_p->type is HFIDD_RESERVE_WIN
+	 * win_p->state is WIN_RESERVED,
+	 * job id is matched
+	 */
+	if ((win_p->type != HFIDD_RESERVE_WIN) ||
+	    (win_p->state != WIN_RESERVED) ||
+	    (win_p->job_id != client_p->job_id)) {
+		spin_unlock(&(win_p->win_lock));
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_reserve_window_id: win 0x%x type0x%x/"
+			"state0x%x/jid invalid\n",
+			client_p->window, win_p->type, win_p->state);
+		return -EINVAL;
+	}
+	spin_unlock(&(win_p->win_lock));
+	return 0;
+}
+
+/* Find an available dynamic window for open window request */
+static int hfi_validate_dynamic_window_id(struct hfidd_acs *p_acs,
+		struct hfi_client_info *client_p)
+{
+	int			i;
+	struct hfidd_window	*win_p;
+
+	/* Find out next available dynamic window */
+	for (i = min_hfi_windows(p_acs);
+	     i < max_hfi_windows(p_acs); i++) {
+
+		win_p = hfi_window(p_acs, i);
+		if (win_p == NULL)
+			continue;
+
+		/* if the spinlock is busy, the window is in use */
+		if (!spin_trylock(&(win_p->win_lock)))
+			continue;
+
+		if ((win_p->type == HFIDD_DYNAMIC_WIN) &&
+		    (win_p->state == WIN_AVAILABLE)) {
+			/*
+			 * Fill in the window number into
+			 * client info and update state
+			 */
+			client_p->window = win_p->index;
+			win_p->job_id = client_p->job_id;
+			win_p->state = WIN_RESERVED;
+			win_p->type  = client_p->win_type;
+
+			/* Set isIP flag if came from IP */
+			if (win_p->type == HFIDD_IP_WIN)
+				win_p->is_ip = 1;
+			else
+				win_p->is_ip = 0;
+			spin_unlock(&(win_p->win_lock));
+			return 0;
+		}
+		spin_unlock(&(win_p->win_lock));
+	}
+
+	/* We are out of dynamic windows */
+	if  (i == max_hfi_windows(p_acs)) {
+		client_p->window = 0;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_dynamic_window_id: out of dynamic window\n");
+		return -ENOBUFS;
+	}
+
+	return 0;
+}
+
+/* Validate the window request for RESERVED or DYNAMIC window */
+static inline int hfi_validate_window_id(struct hfidd_acs *p_acs,
+		struct hfi_client_info *client_p, unsigned int is_userspace)
+{
+	int	rc = 0;
+
+	/* Check the type of window request */
+	switch (client_p->win_type) {
+	case HFIDD_RESERVE_WIN:
+		rc = hfi_validate_reserve_window_id(p_acs, client_p);
+		break;
+	case HFIDD_IP_WIN:
+	case HFIDD_KERNEL_WIN:
+		if (is_userspace) {
+			rc = -EINVAL;
+			break;
+		}
+		/* fall thru here....*/
+	case HFIDD_DYNAMIC_WIN:
+		rc = hfi_validate_dynamic_window_id(p_acs, client_p);
+		break;
+	default:
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_window_id: invalid win type 0x%x\n",
+			client_p->win_type);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+/* Validate window number and type for open window request */
+static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfi_client_info *client_p)
+{
+	int			rc = 0;
+
+	/* Validate the window number */
+	rc = hfi_validate_window_id(p_acs, client_p, is_userspace);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_window_parm: hfi_validate_window_id "
+			"failed, rc = 0x%x\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
 /*
  * Allows an user/kernel window to send/receive network traffic thru HFI
  * adapter. This function will allocate the system resources needed to open
@@ -62,9 +209,23 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	if (rc) {
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
 			"open_window_func: hfi_copy_from_user failed\n");
+		goto hfidd_open_window_func_err1;
+	}
+
+	/* Validate the window parms */
+	rc = hfi_validate_window_parm(p_acs, is_userspace, local_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"open_window_func: hfi_validate_window_parm failed, "
+			"rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err1;
 	}
 
 	kfree(local_p);
 	return rc;
+
+hfidd_open_window_func_err1:
+	kfree(local_p);
+	return rc;
 }
 EXPORT_SYMBOL_GPL(hfidd_open_window_func);
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index dd1ce4c..1781d52 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -142,6 +142,22 @@ struct hfidd_global {
 	struct hfidd_acs	*p_acs[MAX_HFIS];
 };
 
+static inline struct hfidd_window *hfi_window(struct hfidd_acs *p,
+		unsigned int idx)
+{
+	return p->win[idx - p->dds.window_start];
+}
+
+static inline unsigned int min_hfi_windows(struct hfidd_acs *p)
+{
+	return p->dds.window_start;
+}
+
+static inline unsigned int max_hfi_windows(struct hfidd_acs *p)
+{
+	return p->dds.window_start + p->dds.window_num;
+}
+
 static inline int hfi_copy_to_user(void *user_p, void *local_p,
 		unsigned int is_userspace, unsigned int size)
 {
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 24/27] HFI: hf network driver
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

It is a separate binary because it is not strictly necessary to use the HFI.
This patch includes module load/unload and the window open/setup with the
hfi device driver.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/Kconfig             |    1 +
 drivers/net/hfi/Makefile        |    1 +
 drivers/net/hfi/ip/Kconfig      |    9 +
 drivers/net/hfi/ip/Makefile     |    6 +
 drivers/net/hfi/ip/hf_if_main.c |  616 +++++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/ip/hf_proto.h   |   48 +++
 include/linux/hfi/hf_if.h       |  156 ++++++++++
 include/linux/if_arp.h          |    1 +
 8 files changed, 838 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/hfi/ip/Kconfig
 create mode 100644 drivers/net/hfi/ip/Makefile
 create mode 100644 drivers/net/hfi/ip/hf_if_main.c
 create mode 100644 drivers/net/hfi/ip/hf_proto.h
 create mode 100644 include/linux/hfi/hf_if.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d4ca094..3ba39c8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3423,5 +3423,6 @@ config VMXNET3
 	  module will be called vmxnet3.
 
 source "drivers/net/hfi/core/Kconfig"
+source "drivers/net/hfi/ip/Kconfig"
 
 endif # NETDEVICES
diff --git a/drivers/net/hfi/Makefile b/drivers/net/hfi/Makefile
index 0440cbe..768f27c 100644
--- a/drivers/net/hfi/Makefile
+++ b/drivers/net/hfi/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_HFI)                += core/
+obj-$(CONFIG_HFI_IP)             += ip/
diff --git a/drivers/net/hfi/ip/Kconfig b/drivers/net/hfi/ip/Kconfig
new file mode 100644
index 0000000..1a2c21d
--- /dev/null
+++ b/drivers/net/hfi/ip/Kconfig
@@ -0,0 +1,9 @@
+config HFI_IP
+	tristate "IP-over-HFI"
+	depends on NETDEVICES && INET && HFI
+	---help---
+	Support for the IP over HFI. It transports IP
+	packets over HFI.
+
+	To compile the driver as a module, choose M here. The module
+	will be called hf.
diff --git a/drivers/net/hfi/ip/Makefile b/drivers/net/hfi/ip/Makefile
new file mode 100644
index 0000000..59eff9b
--- /dev/null
+++ b/drivers/net/hfi/ip/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the HF IP interface for IBM eServer System p
+#
+obj-$(CONFIG_HFI_IP) += hf_if.o
+
+hf_if-objs :=	hf_if_main.o
diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
new file mode 100644
index 0000000..329baa1
--- /dev/null
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -0,0 +1,616 @@
+/*
+ * hf_if_main.c
+ *
+ * HF IP driver for IBM System p
+ *
+ *  Authors:
+ *	Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *	William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *	Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *	Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *	Jian Xiao <jian@linux.vnet.ibm.com>
+ *	Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *	Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/hfi/hf_if.h>
+#include "hf_proto.h"
+
+MODULE_AUTHOR("James Dykman <dykmanj@linux.vnet.ibm.com>, "
+		"Piyush Chaudhary <piyushc@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IP driver v" HF_DRV_VERSION " (" HF_DRV_RELDATE ")"
+		" for IBM eServer HFI for System p");
+MODULE_VERSION(HF_DRV_VERSION);
+MODULE_LICENSE("GPL v2");
+
+struct hf_global_info		hf_ginfo;
+
+static const u8 hfi_bcast_addr[] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static int hf_inet_event(struct notifier_block *this,
+			 unsigned long event,
+			 void *ifa)
+{
+	struct in_device	*in_dev;
+	struct net_device	*netdev;
+
+	in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
+
+	netdev = in_dev->dev;
+
+	if (!net_eq(dev_net(netdev), &init_net))
+		return NOTIFY_DONE;
+
+	if (event == NETDEV_UP) {
+		struct hf_if	*net_if;
+
+		net_if = &(((struct hf_net *)(netdev_priv(netdev)))->hfif);
+		net_if->ip_addr = ntohl(in_dev->ifa_list->ifa_address);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hf_inet_notifier = {
+	.notifier_call = hf_inet_event,
+};
+
+static void hf_free_tx_resource(struct hf_if *net_if)
+{
+	int	i;
+
+	if (net_if->tx_skb) {
+		for (i = 0; i <= net_if->tx_fifo.emax; i++) {
+			if (net_if->tx_skb[i])
+				dev_kfree_skb_any(net_if->tx_skb[i]);
+		}
+
+		free_pages((unsigned long)(net_if->tx_skb),
+				get_order((net_if->tx_fifo.emax + 1) *
+				sizeof(struct sk_buff *)));
+		net_if->tx_skb = 0;
+	}
+	if (net_if->tx_fifo.addr) {
+		free_pages((unsigned long)(net_if->tx_fifo.addr),
+				get_order(net_if->tx_fifo.size + PAGE_SIZE_4K));
+		net_if->tx_fifo.addr = 0;
+	}
+}
+
+static int hf_alloc_tx_resource(struct hf_if *net_if)
+{
+	int	i;
+
+	net_if->tx_fifo.size = HF_SFIFO_SIZE;
+	net_if->tx_fifo.head = 0;
+	net_if->tx_fifo.tail = 0;
+	net_if->tx_fifo.emax = HF_SFIFO_SLOTS - 1;
+	atomic_set(&net_if->tx_fifo.avail, HF_SFIFO_SLOTS - 1);
+
+	net_if->tx_fifo.addr =
+		(void *)__get_free_pages(GFP_KERNEL,
+				get_order(net_if->tx_fifo.size + PAGE_SIZE_4K));
+
+	if (net_if->tx_fifo.addr == 0) {
+		printk(KERN_ERR "%s: hf_alloc_tx_resource: "
+			"tx_fifo fail, size=0x%x\n",
+			net_if->name, net_if->tx_fifo.size);
+
+		return -ENOMEM;
+	}
+	memset(net_if->tx_fifo.addr, 0, net_if->tx_fifo.size + PAGE_SIZE_4K);
+
+	/* Sfifo finish vector locates at very next page of sfifo */
+	net_if->sfifo_finishvec = net_if->tx_fifo.addr + net_if->tx_fifo.size;
+	net_if->sfifo_fv_polarity = 0;
+	net_if->sfifo_slots_per_blk = HF_SFIFO_SLOTS / HF_FV_BIT_CNT;
+
+	/* allocate array to hold the tx skbs */
+	net_if->tx_skb =
+		(struct sk_buff **)__get_free_pages(GFP_KERNEL,
+		get_order((net_if->tx_fifo.emax + 1) *
+		sizeof(struct sk_buff *)));
+
+	if (net_if->tx_skb == 0) {
+		printk(KERN_ERR "%s: hf_alloc_tx_resource: tx_skb failed\n",
+				net_if->name);
+
+		goto err_out;
+	}
+
+	for (i = 0; i <= net_if->tx_fifo.emax; i++)
+		net_if->tx_skb[i] = NULL;
+
+	return 0;
+
+err_out:
+	hf_free_tx_resource(net_if);
+
+	return -ENOMEM;
+}
+
+static void hf_free_rx_resource(struct hf_if *net_if)
+{
+	if (net_if->rx_fifo.addr) {
+		free_pages((unsigned long)(net_if->rx_fifo.addr),
+				get_order(net_if->rx_fifo.size));
+		net_if->rx_fifo.addr = 0;
+	}
+}
+
+static int hf_alloc_rx_resource(struct hf_if *net_if)
+{
+	net_if->rx_fifo.size = HF_RFIFO_SIZE;
+	net_if->rx_fifo.head = 0;
+	net_if->rx_fifo.tail = 0;
+	net_if->rx_fifo.emax = HF_RFIFO_SLOTS - 1;
+
+	net_if->rx_fifo.addr =
+		(void *)__get_free_pages(GFP_KERNEL,
+				get_order(net_if->rx_fifo.size));
+
+	if (net_if->rx_fifo.addr == 0) {
+		printk(KERN_ERR "%s: hf_alloc_rx_resource: fail, size=0x%x\n",
+				net_if->name, net_if->rx_fifo.size);
+
+		return -ENOMEM;
+	}
+
+	memset(net_if->rx_fifo.addr, 0, net_if->rx_fifo.size);
+
+	return 0;
+}
+
+static void hf_free_resource(struct hf_if *net_if)
+{
+	hf_free_rx_resource(net_if);
+
+	hf_free_tx_resource(net_if);
+}
+
+static int hf_alloc_resource(struct hf_net *net)
+{
+	int			rc;
+	struct hf_if		*net_if = &(net->hfif);
+
+	rc = hf_alloc_tx_resource(net_if);
+	if (rc)
+		goto alloc_resource_err0;
+
+	rc = hf_alloc_rx_resource(net_if);
+	if (rc)
+		goto alloc_resource_err1;
+
+	return 0;
+
+alloc_resource_err1:
+	hf_free_tx_resource(net_if);
+alloc_resource_err0:
+	return rc;
+}
+
+static int hf_close_ip_window(struct hf_if *net_if, struct hfidd_acs *p_acs)
+{
+	int		rc;
+
+	if (net_if->doorbell) {
+		iounmap(net_if->doorbell);
+		net_if->doorbell = NULL;
+	}
+
+	/* Fill in the request structure */
+	net_if->client.hdr.req		   = HFIDD_REQ_CLOSE_WINDOW;
+	net_if->client.hdr.req_len	   = sizeof(struct hfi_window_info);
+	net_if->client.hdr.result.use.kptr = &(net_if->client);
+
+	rc = hfidd_close_window_func(HF_ACS(net_if), 0,
+			(struct hfi_window_info *)(&(net_if->client)));
+	if (rc) {
+		printk(KERN_ERR "%s: hf_close_ip_window: fail, rc=0x%x\n",
+				net_if->name, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hf_open_ip_window(struct hf_if *net_if,
+			     struct hfidd_acs *p_acs,
+			     int share_with)
+{
+	int			rc = 0;
+
+	net_if->client.win_type = HFIDD_IP_WIN;
+
+	net_if->client.sfifo.eaddr.use.kptr	 = net_if->tx_fifo.addr;
+	net_if->client.sfifo.size		 = net_if->tx_fifo.size;
+	net_if->client.rfifo.eaddr.use.kptr	 = net_if->rx_fifo.addr;
+	net_if->client.rfifo.size		 = net_if->rx_fifo.size;
+	net_if->client.sfifo_finish_vec.use.kptr = net_if->sfifo_finishvec;
+	net_if->client.job_id			 = HF_IP_JOBID;
+
+	/* Fill in the request structure */
+	net_if->client.hdr.req		   = HFIDD_REQ_OPEN_WINDOW;
+	net_if->client.hdr.req_len	   = sizeof(struct hfi_client_info);
+	net_if->client.hdr.result.use.kptr = &(net_if->client);
+
+	rc = hfidd_open_window_func(p_acs, 0, &(net_if->client), 0,
+			&(net_if->client));
+	if (rc) {
+		printk(KERN_ERR "%s: hf_open_ip_window: fail open rc=0x%x\n",
+				net_if->name, rc);
+		return rc;
+	}
+
+	net_if->doorbell = (ioremap(
+		(u64)(net_if->client.mmio_regs.use.kptr), PAGE_SIZE_64K));
+
+	if (unlikely(net_if->doorbell == NULL)) {
+		printk(KERN_ERR "%s: hf_open_ip_window: fail to map doorbell\n",
+			net_if->name);
+		hf_close_ip_window(net_if, p_acs);
+	}
+
+	net_if->isr_id = net_if->client.local_isrid;
+
+	return 0;
+}
+
+static int hf_set_mac_addr(struct net_device *netdev, void *p)
+{
+	struct hf_net		*net = netdev_priv(netdev);
+	struct hf_if		*net_if = &(net->hfif);
+
+	/* Mac address format: 02:ClusterID:ISR:ISR:HFI_WIN:WIN */
+
+	/* Locally administered MAC address */
+	netdev->dev_addr[0] = 0x2; /* bit6=1, bit7=0 */
+
+	netdev->dev_addr[1] = 0x0; /* cluster id */
+
+	*(u16 *)(&(netdev->dev_addr[2])) = (u16)(net_if->isr_id);
+
+	*(u16 *)(&(netdev->dev_addr[4])) = (u16)
+	(((net_if->ai) << HF_MAC_HFI_SHIFT) | (net_if->client.window));
+
+	return 0;
+}
+
+static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
+{
+	struct net_device	*netdev = (struct net_device *)parm;
+	struct hf_net		*net = netdev_priv(netdev);
+	struct hf_if		*net_if = &(net->hfif);
+	int			rc = 0;
+	int			share_with;
+	struct hfidd_acs	*p_acs = HF_ACS(net_if);
+
+	spin_lock(&(net_if->lock));
+	if (net_if->state != HF_NET_HALF_OPEN) {
+		netdev_err(netdev, "hf_net_delayed_open: net_if state=0x%x\n",
+			net_if->state);
+		spin_unlock(&(net_if->lock));
+		return -EINVAL;
+	}
+
+	rc = hf_alloc_resource(net);
+	if (rc)
+		goto delayed_open_err0;
+
+	rc = hf_open_ip_window(net_if, p_acs, share_with);
+	if (rc)
+		goto delayed_open_err1;
+
+	hf_set_mac_addr(netdev, NULL);
+
+	net_if->state = HF_NET_OPEN;
+	spin_unlock(&(net_if->lock));
+
+	return 0;
+
+delayed_open_err1:
+	hf_free_resource(net_if);
+
+delayed_open_err0:
+	spin_unlock(&(net_if->lock));
+
+	return rc;
+}
+
+static int hf_register_hfi_ready_callback(struct net_device *netdev,
+					  struct hfidd_acs *p_acs,
+					  int flag)
+{
+	struct hfi_reg_events	reg_events;
+	int			rc = 0;
+
+	reg_events.hdr.req    = flag;
+	reg_events.hdr.req_len = sizeof(struct hfi_reg_events);
+	reg_events.hdr.result.use.kptr = NULL;
+	reg_events.type	= FUNCTIONS_FOR_EVENTS;
+
+	reg_events.info.func.index = HFIDD_HFI_READY_REG;
+	reg_events.info.func.function_p.use.kptr = hf_net_delayed_open;
+	reg_events.info.func.parameter.use.kptr  = (void *)(netdev);
+
+	if (flag == HFIDD_REQ_EVENT_REGISTER)
+		rc = hfidd_callback_register(p_acs, &reg_events);
+	else
+		rc = hfidd_callback_unregister(p_acs, &reg_events);
+	if (rc) {
+		netdev_err(netdev, "hf_register_hfi_ready_callback: fail"
+			" flag=0x%x rc=0x%x\n", flag, rc);
+
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hf_net_open(struct net_device *netdev)
+{
+	struct hf_net		*net = netdev_priv(netdev);
+	struct hf_if		*net_if = &(net->hfif);
+	int			rc = 0;
+	struct hfidd_acs	*p_acs = HF_ACS(net_if);
+
+	memset(&(net_if->net_stats), 0, sizeof(struct net_device_stats));
+	net_if->sfifo_packets = 0;
+
+	spin_lock(&(net_if->lock));
+	net_if->state = HF_NET_HALF_OPEN;
+	spin_unlock(&(net_if->lock));
+
+	netif_carrier_off(netdev);
+
+	rc = hf_register_hfi_ready_callback(netdev, p_acs,
+			HFIDD_REQ_EVENT_REGISTER);
+	if (rc != 0) {
+		spin_lock(&(net_if->lock));
+		net_if->state = HF_NET_CLOSE;
+		spin_unlock(&(net_if->lock));
+
+		netdev_err(netdev, "hf_net_open: hf_register_hfi_ready_callback"
+			"fail, rc=0x%x, state=0x%x", rc, net_if->state);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hf_net_close(struct net_device *netdev)
+{
+	struct hf_net		*net = netdev_priv(netdev);
+	struct hf_if		*net_if = &(net->hfif);
+	struct hfidd_acs	*p_acs = HF_ACS(net_if);
+
+	if (net_if->state == HF_NET_CLOSE)
+		return 0;
+
+	spin_lock(&(net_if->lock));
+	if (net_if->state == HF_NET_OPEN) {
+		hf_close_ip_window(net_if, p_acs);
+
+		hf_free_resource(net_if);
+	}
+
+	hf_register_hfi_ready_callback(netdev, p_acs,
+			HFIDD_REQ_EVENT_UNREGISTER);
+
+	net_if->state = HF_NET_CLOSE;
+	spin_unlock(&(net_if->lock));
+
+	return 0;
+}
+
+struct net_device_stats *hf_get_stats(struct net_device *netdev)
+{
+	struct hf_net	*net = netdev_priv(netdev);
+	struct hf_if	*net_if = &(net->hfif);
+
+	return &(net_if->net_stats);
+}
+
+static int hf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	if ((new_mtu <= 0) || (new_mtu > HF_NET_MTU))
+		return -ERANGE;
+
+	netdev->mtu = new_mtu;
+
+	return 0;
+}
+
+static int hf_hard_header(struct sk_buff *skb,
+			  struct net_device *netdev,
+			  u16 type,
+			  const void *daddr,
+			  const void *saddr,
+			  u32 len)
+{
+	struct hf_hwhdr		*hwhdr_p;
+
+	skb_push(skb, HF_HLEN);
+
+	hwhdr_p = (struct hf_hwhdr *)(skb->data);
+	hwhdr_p->h_proto = htons(type);
+
+	if (!saddr)
+		saddr = netdev->dev_addr;
+
+	memcpy(hwhdr_p->h_source, saddr, netdev->addr_len);
+
+	if (daddr) {
+		memcpy(hwhdr_p->h_dest, daddr, netdev->addr_len);
+		return netdev->hard_header_len;
+	}
+
+	if (netdev->flags & IFF_NOARP) {
+		memset(hwhdr_p->h_dest, 0, netdev->addr_len);
+		return netdev->hard_header_len;
+	}
+
+	return -netdev->hard_header_len;
+}
+
+static const struct header_ops hf_header_ops = {
+	.create = hf_hard_header,
+};
+
+static const struct net_device_ops hf_netdev_ops = {
+	.ndo_open		= hf_net_open,
+	.ndo_stop		= hf_net_close,
+	.ndo_change_mtu		= hf_change_mtu,
+	.ndo_set_mac_address	= NULL,
+	.ndo_get_stats		= hf_get_stats,
+};
+
+static void hf_if_setup(struct net_device *netdev)
+{
+	netdev->type		= ARPHRD_HFI;
+	netdev->mtu		= HF_NET_MTU;
+	netdev->tx_queue_len	= 1000;
+	netdev->flags		= IFF_BROADCAST;
+	netdev->hard_header_len	= HF_HLEN;
+	netdev->addr_len	= HF_ALEN;
+	netdev->needed_headroom	= 0;
+
+	netdev->header_ops	= &hf_header_ops;
+	netdev->netdev_ops	= &hf_netdev_ops;
+
+	netdev->features       |= NETIF_F_SG;
+
+	memcpy(netdev->broadcast, hfi_bcast_addr, HF_ALEN);
+}
+
+static struct hf_net *hf_init_netdev(int idx, int ai)
+{
+	struct net_device	*netdev;
+	struct hf_net		*net;
+	int			ii;
+	int			rc;
+	char			ifname[HF_MAX_NAME_LEN];
+
+	ii = (idx * MAX_HFIS) + ai;
+	sprintf(ifname, "hf%d", ii);
+	netdev = alloc_netdev(sizeof(struct hf_net), ifname, hf_if_setup);
+	if (!netdev) {
+		printk(KERN_ERR "hf_init_netdev: "
+				"alloc_netdev for hfi%d:hf%d fail\n", ai, idx);
+		return (struct hf_net *) -ENODEV;
+	}
+
+	net = netdev_priv(netdev);
+	net->netdev = netdev;
+
+	memset(&(net->hfif), 0, sizeof(struct hf_if));
+	net->hfif.idx = ii;	/* interface index */
+	net->hfif.ai  = ai;	/* adapter index */
+	strncpy(net->hfif.name, ifname, HF_MAX_NAME_LEN);
+	net->hfif.state = HF_NET_CLOSE;
+
+	spin_lock_init(&net->hfif.lock);
+
+	rc = register_netdev(netdev);
+	if (rc) {
+		printk(KERN_ERR "hf_init_netdev: "
+				"failed to register netdev=hfi%d:hf%d, "
+				"rc 0x%x\n", ai, idx, rc);
+		free_netdev(netdev);
+		return (struct hf_net *) -ENODEV;
+	}
+
+	return net;
+}
+
+static void hf_del_netdev(struct hf_net *net)
+{
+	struct net_device	*netdev = net->netdev;
+
+	unregister_netdev(netdev);
+
+	free_netdev(netdev);
+}
+
+static int __init hf_init_module(void)
+{
+	u32		idx, ai;
+	struct hf_net	*net;
+
+	memset(&hf_ginfo, 0, sizeof(struct hf_global_info));
+
+	for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+		for (ai = 0; ai < MAX_HFIS; ai++) {
+			net = hf_init_netdev(idx, ai);
+			if (IS_ERR(net)) {
+				printk(KERN_ERR "hf_init_module: hf_init_netdev"
+						" for idx %d ai %d failed rc"
+						" 0x%016llx\n",
+						idx, ai, (u64)(PTR_ERR(net)));
+
+				goto err_out;
+			}
+
+			hf_ginfo.net[idx][ai] = net;
+		}
+	}
+
+	register_inetaddr_notifier(&hf_inet_notifier);
+
+	printk(KERN_INFO "hf module loaded\n");
+	return 0;
+
+err_out:
+	for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+		for (ai = 0; ai < MAX_HFIS; ai++) {
+			net = hf_ginfo.net[idx][ai];
+			if (net != NULL) {
+				hf_del_netdev(net);
+				hf_ginfo.net[idx][ai] = NULL;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void __exit hf_cleanup_module(void)
+{
+	u32		idx, ai;
+	struct hf_net	*net;
+
+	unregister_inetaddr_notifier(&hf_inet_notifier);
+	for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+		for (ai = 0; ai < MAX_HFIS; ai++) {
+			net = hf_ginfo.net[idx][ai];
+			if (net != NULL) {
+				hf_del_netdev(net);
+				hf_ginfo.net[idx][ai] = NULL;
+			}
+		}
+	}
+
+	return;
+}
+
+module_init(hf_init_module);
+module_exit(hf_cleanup_module);
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
new file mode 100644
index 0000000..f2b159e
--- /dev/null
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -0,0 +1,48 @@
+/*
+ * hf_proto.h
+ *
+ * HF IP driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HF_PROTO_H_
+#define _HF_PROTO_H_
+
+extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
+		u32 is_userspace,
+		struct hfi_client_info *user_p,
+		u64 fl, struct hfi_client_info *out_p);
+extern int hfidd_close_window_func(struct hfidd_acs *p_acs,
+		u32 is_userspace,
+		struct hfi_window_info *user_p);
+extern int hfidd_callback_register(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *arg);
+extern int hfidd_callback_unregister(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *arg);
+
+#endif
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
new file mode 100644
index 0000000..d13c6ab
--- /dev/null
+++ b/include/linux/hfi/hf_if.h
@@ -0,0 +1,156 @@
+/*
+ * hf_if.h
+ *
+ * HF IP driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <wcchen@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HF_IF_H_
+#define _HF_IF_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <net/arp.h>
+
+#include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_client.h>
+#include <linux/hfi/hfidd_requests.h>
+#include <linux/hfi/hfidd_pkt_formats.h>
+
+#define HF_DRV_VERSION			"1.0"
+#define HF_DRV_RELDATE			"July 7, 2010"
+#define HF_DRV_NAME			"hf"
+
+#define MAX_HF_PER_HFI			2
+#define	HF_IP_JOBID			0xFFFFFFF0
+#define HF_MAX_NAME_LEN			64
+
+#define HF_SFIFO_SIZE			0x40000	/* 256K */
+#define HF_SFIFO_SLOTS			(HF_SFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+#define HF_RFIFO_SIZE			0x1000000	/* 16M */
+#define HF_RFIFO_SLOTS			(HF_RFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+
+#define HF_FV_BIT_CNT			32
+#define HF_NET_MTU			(2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+
+struct hfi_ip_extended_hdr {            /* 16B */
+	u32		immediate_len:7;/* In bytes */
+	u32		num_desc:3;     /* number of descriptors */
+					/* Logical Port ID: */
+	u32		lpid_valid:1;   /* set by sending HFI */
+	u32		lpid:4;         /* set by sending HFI */
+	/* Ethernet Service Header is 113 bits, which is 14 bytes + 1 bit */
+	u32		ethernet_svc_hdr_hi:1;    /* Not used by HFI */
+	char            ethernet_svc_hdr[12];     /* Not used by HFI */
+	__sum16         bcast_csum;
+} __packed;
+
+struct hfi_ip_with_payload_pkt {
+	struct hfi_hdr			hfi_hdr;
+	struct hfi_ip_extended_hdr	ip_ext;
+	char				payload[2016];
+} __packed;
+
+#define HF_IP_HDR_LEN			((sizeof(struct hfi_hdr) + \
+				sizeof(struct hfi_ip_extended_hdr)))
+#define HF_ALEN				6
+struct hf_hwhdr {
+	u8				h_dest[HF_ALEN];
+	u8				h_source[HF_ALEN];
+	__be16				h_proto;
+};
+
+#define HF_HLEN				sizeof(struct hf_hwhdr)
+#define HF_ALIGN_PAD			2
+
+struct hf_if_proto_hdr {
+	u16			version;
+	u8			msg_type;
+	u8			msg_flag;
+	u32			msg_len;	/* Include HFI header */
+	u32			msg_id;
+};
+
+#define HF_PROTO_LEN		sizeof(struct hf_if_proto_hdr)
+
+struct hf_fifo {
+	void			*addr;
+	u32			size;		/* total bytes	*/
+	u32			head;
+	u32			tail;
+	u32			emax;		/* power 2 mask */
+	atomic_t		avail;		/* for tx	*/
+	atomic_t		outstanding;	/* for rx	*/
+};
+
+#define	HF_NET_CLOSE		0x00
+#define	HF_NET_HALF_OPEN	0xA0
+#define	HF_NET_OPEN		0xA1
+
+struct hf_if {
+	u32			idx;			/* 0, 1, 2, 3 ...   */
+	u32			ai;			/* 0=hfi0, 1=hfi1   */
+	char			name[HF_MAX_NAME_LEN];
+	u32			isr_id;
+	u32			ip_addr;
+	u32			state;			/* CLOSE, OPEN */
+	spinlock_t		lock;			/* lock for state */
+	u32			sfifo_fv_polarity;
+	u32			sfifo_slots_per_blk;
+	u32			sfifo_packets;
+	void __iomem		*doorbell;		/* mapped mmio_regs */
+	struct hf_fifo		tx_fifo;
+	struct hf_fifo		rx_fifo;
+	struct hfi_client_info	client;
+	struct sk_buff		**tx_skb;		/* array to store tx
+							   2k skb */
+	void			*sfifo_finishvec;
+	struct net_device_stats	net_stats;
+};
+
+/* Private structure for HF inetrface */
+struct hf_net {
+	struct net_device	*netdev;
+	struct hf_if		hfif;
+};
+
+extern struct hfidd_global	hfidd_global;
+
+#define HF_ACS(net_if)		(hfidd_global.p_acs[(net_if)->ai])
+
+struct hf_global_info {
+	struct hf_net		*net[MAX_HF_PER_HFI][MAX_HFI_PER_TORRENT];
+};
+
+extern struct hf_global_info	hf_ginfo;
+
+#define HF_MAC_HFI_SHIFT	12
+#endif
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 6d722f4..f2cfdc1 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -41,6 +41,7 @@
 #define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_EUI64	27		/* EUI-64                       */
 #define ARPHRD_INFINIBAND 32		/* InfiniBand			*/
+#define ARPHRD_HFI	37		/* Host Fabric Interface	*/
 
 /* Dummy types for non ARP hardware */
 #define ARPHRD_SLIP	256
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 13/27] HFI: Send and receive fifo address translation
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Prepare for a hypervisor call to set up page tables in the nMMU for the
send and receive fifo.

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_proto.h  |    9 ++
 drivers/net/hfi/core/hfidd_window.c |  132 ++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_xlat.c   |  210 +++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_adpt.h      |   28 +++++
 include/linux/hfi/hfidd_hcalls.h    |    2 +
 include/linux/hfi/hfidd_internal.h  |    1 +
 include/linux/hfi/hfidd_xlat_map.h  |   91 +++++++++++++++
 7 files changed, 473 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/hfi/hfidd_xlat_map.h

diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 66ea5da..001f6d5 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,9 +39,18 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
 void hfidd_free_windows(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 int hfidd_age_hcall(u64 time_start);
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		unsigned int is_userspace, struct hfidd_vlxmem *xlat_p);
 int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr,
 		unsigned int is_userspace, unsigned int length,
 		unsigned long long *page_size);
+int hfidd_get_page_num(struct hfidd_acs *p_acs, void *start_addr,
+		unsigned long long len, unsigned long long page_sz,
+		unsigned int *pg_num_p);
 int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		struct hfi_client_info *user_p,
 		struct hfi_client_info *out_p);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 5a4f395..de2e56d 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,125 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+static int hfi_xlate_fifos(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	/*
+	 * add 4K(finish vector) to the sfifo size then call to
+	 * xlate when return, restore the sfifo size back..............
+	 */
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	rc = hfidd_fifo_xlat(p_acs, &(client_p->sfifo), is_userspace,
+			win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = hfidd_fifo_xlat(p_acs, &(client_p->rfifo), is_userspace,
+			win_p->rfifo_x_tab);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+			"rc = 0x%x\n", rc);
+		goto hfi_xlate_fifos_err1;
+	}
+
+hfi_xlate_fifos_err1:
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	hfidd_fifo_unxlat(p_acs, &(client_p->sfifo), is_userspace,
+			win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+
+	return rc;
+}
+
+int hfi_unxlate_fifos(struct hfidd_acs *p_acs, unsigned int is_userspace,
+		struct hfidd_window *win_p, struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	hfidd_fifo_unxlat(p_acs, &(client_p->rfifo),
+			is_userspace, win_p->rfifo_x_tab);
+
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	hfidd_fifo_unxlat(p_acs, &(client_p->sfifo),
+			is_userspace, win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+
+	return rc;
+}
+
+static inline void hfi_free_xlate_tab(struct hfidd_window *win_p)
+{
+	kfree(win_p->sfifo_x_tab);
+	win_p->sfifo_x_tab	= NULL;
+	kfree(win_p->rfifo_x_tab);
+	win_p->rfifo_x_tab	= NULL;
+}
+
+static int hfi_alloc_xlate_tab(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	win_p->sfifo_x_tab = kzalloc(sizeof(*(win_p->sfifo_x_tab)),
+			GFP_KERNEL);
+	if (win_p->sfifo_x_tab == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_xlate_tab: kzalloc sfifo_x_tab failed\n");
+		return -ENOMEM;
+	}
+
+	win_p->rfifo_x_tab = kzalloc(sizeof(*(win_p->rfifo_x_tab)),
+			GFP_KERNEL);
+	if (win_p->rfifo_x_tab == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_xlate_tab: kzalloc rfifo_x_tab failed\n");
+		goto hfi_alloc_xlate_tab_err1;
+	}
+
+	return 0;
+
+hfi_alloc_xlate_tab_err1:
+	kfree(win_p->sfifo_x_tab);
+	win_p->sfifo_x_tab = NULL;
+	return -ENOMEM;
+}
+
+static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	rc = hfi_alloc_xlate_tab(p_acs, win_p, client_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_win_resource: hfi_alloc_xlate_tab "
+			"failed, rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = hfi_xlate_fifos(p_acs, is_userspace, win_p, client_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_win_resource: hfi_xlate_fifos "
+			"failed, rc = 0x%x\n", rc);
+		hfi_free_xlate_tab(win_p);
+		return rc;
+	}
+
+	return 0;
+}
+
 /*
  * Allows an user/kernel window to send/receive network traffic thru HFI
  * adapter. This function will allocate the system resources needed to open
@@ -371,6 +490,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 {
 	int			rc = 0;
 	struct hfi_client_info	*local_p = NULL;
+	struct hfidd_window	*win_p = NULL;
 
 	/* Allocate local data structure */
 	local_p = kmalloc(sizeof(struct hfi_client_info), GFP_KERNEL);
@@ -398,9 +518,21 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		goto hfidd_open_window_func_err1;
 	}
 
+	win_p = hfi_window(p_acs, local_p->window);
+
+	rc = hfi_alloc_win_resource(p_acs, is_userspace, win_p, local_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_alloc_win_resource "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err2;
+	}
+
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err2:
+	hfi_restore_window_parm(p_acs, win_p);
 hfidd_open_window_func_err1:
 	kfree(local_p);
 	return rc;
diff --git a/drivers/net/hfi/core/hfidd_xlat.c b/drivers/net/hfi/core/hfidd_xlat.c
index 23236cc..760d7e6 100644
--- a/drivers/net/hfi/core/hfidd_xlat.c
+++ b/drivers/net/hfi/core/hfidd_xlat.c
@@ -129,3 +129,213 @@ out1:
 	kfree(page_list);
 	return rc;
 }
+
+int hfidd_get_page_num(struct hfidd_acs *p_acs,
+		void			*start_addr,
+		unsigned long long	len,
+		unsigned long long	page_sz,
+		unsigned int		*pg_num_p)
+{
+	int			rc = 0;
+	int			pg_shift_count;
+	unsigned long long	address_mask;
+	unsigned long long	offset_mask;
+	unsigned long long	offset;
+
+	if (pg_num_p == NULL || len == 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_num: len=%llx pg_num_p=0x%llx\n",
+			len, (unsigned long long)pg_num_p);
+		return -EINVAL;
+	}
+
+	/*
+	 * Pre-Calculate Masks and shift count:
+	 */
+	if (page_sz == PAGE_SIZE_4K) {
+		offset_mask			= PAGE_MASK_4K;
+		pg_shift_count			= PAGE_SHIFT_4K;
+	} else if (page_sz == PAGE_SIZE_64K) {
+		offset_mask			= PAGE_MASK_64K;
+		pg_shift_count			= PAGE_SHIFT_64K;
+	} else if (page_sz == PAGE_SIZE_16M) {
+		offset_mask			= PAGE_MASK_16M;
+		pg_shift_count			= PAGE_SHIFT_16M;
+	} else if (page_sz == PAGE_SIZE_4G) {
+		offset_mask			= PAGE_MASK_4G;
+		pg_shift_count			= PAGE_SHIFT_4G;
+	} else {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_num: invalid page_sz 0x%llx "
+			"return EINVAL\n", page_sz);
+		return -EINVAL;
+	}
+	address_mask = ~offset_mask;
+
+	/*
+	 * Calculate the buffer offsets into the first page:
+	 */
+	offset = (unsigned long long)start_addr & offset_mask;
+	*pg_num_p  = (len + offset + offset_mask) >> pg_shift_count;
+
+	return rc;
+}
+
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+	unsigned int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	unsigned int		num_pages;
+	unsigned long long	page_size;
+	int			rc = 0;
+
+	rc = hfidd_get_page_size(p_acs, fifo_in->eaddr.use.kptr, is_userspace,
+			fifo_in->size, &page_size);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fill_xlat_tab: hfidd_get_page_size failed, "
+			" rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* Get num of pages based in buffer page size */
+	rc = hfidd_get_page_num(p_acs, fifo_in->eaddr.use.kptr,
+			fifo_in->size, page_size, &num_pages);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fill_xlat_tab:: hfidd_get_page_num return "
+			"rc 0x%x\n", rc);
+		return rc;
+	}
+
+	xlat_p->v_addr = (caddr_t)(fifo_in->eaddr.use.kptr);
+	xlat_p->e_addr = (caddr_t)(fifo_in->eaddr.use.allu & ~(page_size - 1));
+	xlat_p->page_sz = page_size;
+	xlat_p->num_page = num_pages;
+	xlat_p->len = num_pages * page_size;
+	xlat_p->num_kpage = (xlat_p->len) / PAGE_SIZE;
+
+	return 0;
+}
+
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	int			rc = 0;
+	int			i;
+	unsigned int		num_pages, pg_code;
+	unsigned long long	page_size;
+	unsigned long long	*l_pages;
+	struct page		**page_list;
+	unsigned int		hw_page = 0;
+
+	if ((fifo_in == NULL) || (xlat_p == NULL)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: Invalid fifo_in 0x%llx\n",
+			(unsigned long long)fifo_in);
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: Invalid xlat_p 0x%llx\n",
+			(unsigned long long)xlat_p);
+		return -EINVAL;
+	}
+
+	rc = hfidd_fill_xlat_tab(p_acs, fifo_in, is_userspace, xlat_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: hfidd_fill_xlat_tab failed, "
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	/* num_page is number of pages of page_sz */
+	num_pages = xlat_p->num_page;
+	page_size = xlat_p->page_sz;
+
+	l_pages = vmalloc(num_pages * sizeof(unsigned long long));
+	if (l_pages == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: vmalloc failed for l_pages\n");
+		return -ENOMEM;
+	}
+
+	if (!is_userspace) {
+		void *curr_addr = xlat_p->e_addr;
+
+		for (i = 0; i < num_pages; i++) {
+			l_pages[i] = __pa(curr_addr);
+			curr_addr += page_size;
+		}
+	} else {
+		/* For page_list use number of kernel pages */
+		page_list = kzalloc(xlat_p->num_kpage * sizeof(struct page *),
+			GFP_KERNEL);
+		if (page_list == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_fifo_xlat: kzalloc failed "
+				"for page_list\n");
+			rc = -ENOMEM;
+			goto out_err0;
+		}
+
+		down_read(&current->mm->mmap_sem);
+		rc = get_user_pages(current, current->mm,
+				(unsigned long long)(xlat_p->e_addr),
+				xlat_p->num_kpage, 1, 0, /* write, !force */
+				page_list, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (rc < xlat_p->num_kpage) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_fifo_xlat: get_user_pages failed, "
+				"rc = 0x%x\n", rc);
+			goto out_err1;
+		}
+
+		for (i = 0; i < num_pages;) {
+			l_pages[hw_page] = page_to_phys(page_list[i]);
+			hw_page++;
+			i += (page_size / PAGE_SIZE);
+		}
+
+		xlat_p->page_list = (void *)page_list;
+	}
+
+	xlat_p->l_pages = (void *)l_pages;
+	xlat_p->map_page_sz = page_size;
+	xlat_p->m_addr = xlat_p->e_addr;
+	xlat_p->num_page_sz.num_code.fields.pg_num = num_pages;
+	encode_pg_sz(page_size, &pg_code);
+	xlat_p->num_page_sz.num_code.fields.pg_code =
+		(pg_code << HFI_PAGE_CODE_SHIFT);
+	return 0;
+
+out_err1:
+	if (rc > 0) {
+		for (i = 0; i < rc; i++)
+			page_cache_release(page_list[i]);
+		rc = -EINVAL;
+	}
+	kfree(page_list);
+out_err0:
+	vfree(l_pages);
+	return rc;
+}
+
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	int		rc = 0;
+	int		i;
+	struct page	**page_list;
+
+	if (!is_userspace)
+		return 0;
+	page_list = (struct page **)xlat_p->page_list;
+	if (page_list != NULL) {
+		/* For page list we used number of kernel pages */
+		for (i = 0; i < xlat_p->num_kpage; i++)
+			page_cache_release(page_list[i]);
+		kfree(page_list);
+		xlat_p->page_list = NULL;
+	}
+	return rc;
+}
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index a41825f..8eab059 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -74,4 +74,32 @@
 #define PAGE_MASK_4G		(PAGE_SIZE_4G - 1)
 #define PAGE_MASK_16G		(PAGE_SIZE_16G - 1)
 
+#define PAGE_CODE_4K	0x00000000
+#define PAGE_CODE_64K	0x00000001
+#define PAGE_CODE_1M	0x00000002
+#define PAGE_CODE_16M	0x00000003
+#define PAGE_CODE_256M	0x00000004
+#define PAGE_CODE_4G	0x00000005
+#define PAGE_CODE_INVAL	0x00000007
+#define PAGE_CODE_MASK	0x00000007
+
+static inline void encode_pg_sz(unsigned long long pg_sz,
+		unsigned int *pg_sz_code)
+{
+	if (pg_sz == PAGE_SIZE_4K)
+		*pg_sz_code = PAGE_CODE_4K;
+	else if (pg_sz == PAGE_SIZE_64K)
+		*pg_sz_code = PAGE_CODE_64K;
+	else if (pg_sz == PAGE_SIZE_1M)
+		*pg_sz_code = PAGE_CODE_1M;
+	else if (pg_sz == PAGE_SIZE_16M)
+		*pg_sz_code = PAGE_CODE_16M;
+	else if (pg_sz == PAGE_SIZE_256M)
+		*pg_sz_code = PAGE_CODE_256M;
+	else if (pg_sz == PAGE_SIZE_4G)
+		*pg_sz_code = PAGE_CODE_4G;
+	else
+		*pg_sz_code = PAGE_CODE_INVAL;
+}
+
 #endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 2a374e6..57140a0 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -42,6 +42,8 @@
 #define H_NMMU_START			0xF028
 #define H_NMMU_STOP			0xF02C
 
+#define HFI_PAGE_CODE_SHIFT	28
+
 #define EEH_QUERY	1
 #define COMP_QUERY	2
 
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 1781d52..216546b 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -63,6 +63,7 @@
 #include <linux/hfi/hfidd_client.h>
 #include <linux/hfi/hfidd_adpt.h>
 #include <linux/hfi/hfidd_hcalls.h>
+#include <linux/hfi/hfidd_xlat_map.h>
 
 #define MAX_D_WIN_PER_HFI	(p_acs->dds.num_d_windows)
 
diff --git a/include/linux/hfi/hfidd_xlat_map.h b/include/linux/hfi/hfidd_xlat_map.h
new file mode 100644
index 0000000..e5d1869
--- /dev/null
+++ b/include/linux/hfi/hfidd_xlat_map.h
@@ -0,0 +1,91 @@
+/*
+ * hfidd_xlat_map.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFIDD_XLAT_MAP_H_
+#define _HFIDD_XLAT_MAP_H_
+
+#include <linux/hfi/hfidd_client.h>
+
+/*
+ * So we can shift rather than divide!
+ */
+#define PAGE_SHIFT_2K		11
+#define PAGE_SHIFT_4K		12
+#define PAGE_SHIFT_64K		16
+#define PAGE_SHIFT_1M		20
+#define PAGE_SHIFT_16M		24
+#define PAGE_SHIFT_4G		32
+
+struct page_num_code {
+	union {
+		unsigned long long	llu_value;
+		struct num_and_code {
+			unsigned int	pg_num;
+			unsigned int	pg_code;
+		} fields;
+	} num_code;
+};
+
+struct hfidd_vlxmem {
+	unsigned long long	page_sz;	/* actual page size */
+	unsigned int		num_page;	/* calculated using actual
+						   page size */
+	unsigned int		rsvd;
+	struct page_num_code	num_page_sz;	/* page num and size code
+						   mapping */
+	unsigned long long	map_page_sz;	/* page size used for mapping */
+	caddr_t			m_addr;		/* aligned address start for
+						   mapping */
+	caddr_t			v_addr;		/* user given vaddr */
+	caddr_t			e_addr;
+
+	unsigned long long	len;
+	unsigned long long	access_flag;
+	void			*l_pages;
+
+	unsigned long long	mr_handle;
+	unsigned int		l_key;
+
+	struct task		*xd;
+
+	int			num_kpage;	/* num of kernel pages */
+	atomic_t		*share_cnt;	/* # of processes sharing this
+						   submr */
+	unsigned int		num_chunks;	/* number of chunks the mr is
+						   divided */
+	caddr_t			mr_addr;	/* aligned submr starting
+						   address */
+	void			*page_list;	/* struct page_list */
+	unsigned int		liobn;		/* logical I/O bus number */
+};
+
+#endif
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 14/27] HFI: Add hypercalls to create/modify/free page tables in the nMMU
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_hcalls.c |  124 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |   15 ++++
 include/linux/hfi/hfidd_hcalls.h    |    3 +
 3 files changed, 142 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
index 2ca1c8a..aabb2a8 100644
--- a/drivers/net/hfi/core/hfidd_hcalls.c
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -45,6 +45,64 @@ static inline long long h_nmmu_stop(int token, u64 torrent_chip_ID)
 	return plpar_hcall_norets(token, torrent_chip_ID);
 }
 
+static inline long long h_nmmu_allocate_resource(int token,
+		u64 torrent_chip_ID,
+		u64 resource_name,
+		u64 eaddr,
+		u64 memory_region_size,
+		u64 access_controls,
+		u64 protection_domain,
+		u64 MR_Handle_In,
+		u64 *MR_Handle_out,
+		u64 *L_Key,
+		u64 *liobn)
+{
+	u64 hyp_outputs[PLPAR_HCALL9_BUFSIZE];
+	long long rc;
+
+	rc = plpar_hcall9(token, (unsigned long *)hyp_outputs,
+			torrent_chip_ID, resource_name, eaddr,
+			memory_region_size, access_controls,
+			protection_domain, MR_Handle_In);
+	*MR_Handle_out = hyp_outputs[0];	/* 1st ret value */
+	*L_Key = hyp_outputs[1];		/* 2nd */
+	*liobn = hyp_outputs[3];		/* 4th */
+
+	return rc;
+}
+
+static inline long long h_nmmu_free_resource(int token,
+		u64 torrent_chip_ID,
+		u64 resource_name,
+		u64 MR_Handle,
+		u64 subregion)
+{
+	return  plpar_hcall_norets(token,
+				torrent_chip_ID,
+				resource_name,
+				MR_Handle,
+				subregion);
+}
+
+static inline long long h_nmmu_modify_resource(int token,
+		u64 torrent_chip_ID,
+		u64 request,
+		u64 MR_Handle,
+		u64 subregion,
+		u64 eaddr,
+		u64 laddr,
+		u64 num_pg_sz)
+{
+	return  plpar_hcall_norets(token,
+				torrent_chip_ID,
+				request,
+				MR_Handle,
+				subregion,
+				eaddr,
+				laddr,
+				num_pg_sz);
+}
+
 static inline long long h_hfi_start_interface(int token,
 		u64 HFI_chip_ID)
 {
@@ -94,6 +152,72 @@ long long hfi_stop_nmmu(u64 chip_id)
 	return hvrc;
 }
 
+long long hfi_allocate_mr(u64 chip_id, u64 res, u64 addr, u64 mr_size,
+		u64 access,
+		u64 job_id,
+		u64 mr_handle_in,
+		u64 *mr_handle_out,
+		u64 *lkey_p,
+		u64 *liobn)
+{
+	return h_nmmu_allocate_resource(H_NMMU_ALLOCATE_RESOURCE,
+			chip_id,
+			res,
+			addr,
+			mr_size,
+			access,
+			job_id,
+			mr_handle_in,
+			mr_handle_out,
+			lkey_p,
+			liobn);
+}
+
+long long hfi_modify_mr(u64 chip_id, u64 request, u64 mr_handle,
+		u64 sub_id,
+		u64 e_addr,
+		u64 l_addr,
+		u64 num_pg_sz)
+{
+	long long  hvrc;
+	u64 start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = h_nmmu_modify_resource(H_NMMU_MODIFY_RESOURCE,
+				chip_id,
+				request,
+				mr_handle,
+				sub_id,
+				e_addr,
+				l_addr,
+				num_pg_sz);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	return hvrc;
+}
+
+long long hfi_free_mr(u64 chip_id, u64 res, u64 mr_handle, u64 sub_region_id)
+{
+	long long	hvrc;
+	u64 start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = h_nmmu_free_resource(H_NMMU_FREE_RESOURCE,
+				chip_id,
+				res,
+				mr_handle,
+				sub_region_id);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	return hvrc;
+}
+
 long long hfi_hquery_interface(u64 unit_id, u64 subtype,
 			       u64 query_p, u64 *state)
 {
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 001f6d5..fb9c8c8 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -64,6 +64,21 @@ int hfidd_start_interface(struct hfidd_acs *p_acs);
 int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
 long long hfi_start_nmmu(u64 chip_id, void *nmmu_info);
 long long hfi_stop_nmmu(u64 chip_id);
+long long hfi_allocate_mr(u64 chip_id, u64 res, u64 addr,
+		u64 mr_size,
+		u64 access,
+		u64 job_id,
+		u64 mr_handle_in,
+		u64 *mr_handle_out,
+		u64 *lkey_p,
+		u64 *liobn);
+long long hfi_modify_mr(u64 chip_id, u64 request, u64 mr_handle,
+		u64 sub_id,
+		u64 e_addr,
+		u64 l_addr,
+		u64 num_pg_sz);
+long long hfi_free_mr(u64 chip_id, u64 res, u64 mr_handle,
+		u64 sub_region_id);
 long long hfi_hquery_interface(u64 unit_id, u64 subtype, u64 query_p,
 		u64 *state);
 long long hfi_start_interface(u64 unit_id);
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 57140a0..9fa87c5 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -41,6 +41,9 @@
 #define H_HFI_STOP_INTERFACE		0xF008
 #define H_NMMU_START			0xF028
 #define H_NMMU_STOP			0xF02C
+#define H_NMMU_ALLOCATE_RESOURCE	0xF030
+#define H_NMMU_FREE_RESOURCE		0xF034
+#define H_NMMU_MODIFY_RESOURCE		0xF03C
 
 #define HFI_PAGE_CODE_SHIFT	28
 
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 15/27] HFI: Set up nMMU page tables for the send and receive fifos
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_proto.h  |    3 +
 drivers/net/hfi/core/hfidd_window.c |  259 ++++++++++++++++++++++++++++++++++-
 include/linux/hfi/hfidd_hcalls.h    |   16 ++
 include/linux/hfi/hfidd_internal.h  |    2 +
 4 files changed, 279 insertions(+), 1 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index fb9c8c8..ff39a02 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -54,6 +54,9 @@ int hfidd_get_page_num(struct hfidd_acs *p_acs, void *start_addr,
 int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		struct hfi_client_info *user_p,
 		struct hfi_client_info *out_p);
+int hfi_register_rpages(struct hfidd_acs *p_acs, unsigned long long mr_handle,
+		unsigned int submr, struct hfidd_vlxmem *xtab_p,
+		unsigned int *mapped_pages);
 int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
 	caddr_t *laddr, int size);
 void hfidd_release_phyp_page(caddr_t page, int size);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index de2e56d..6d90af6 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,220 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+
+/*
+ * Map the Effective Address pages for Memory Regions.
+ * If more than one page, need to setup a page containing
+ * all the effective address pages
+ */
+int hfi_register_rpages(struct hfidd_acs *p_acs,
+			unsigned long long mr_handle,
+			unsigned int submr,
+			struct hfidd_vlxmem *xtab_p,
+			unsigned int *mapped_pages)
+{
+	unsigned int		map_num;
+	long long		hvrc = 0;
+	unsigned int		num_page_left, num_page_total;
+	char			*effective_addr;
+	void			*l_pages;
+	void			*hcall_array = NULL;
+	unsigned long long	logical_hcall_array = 0;
+	unsigned long long	logical_addr = 0;
+	struct page_num_code	num_page_sz;
+	int			rc = 0;
+
+	effective_addr = xtab_p->m_addr;
+	num_page_total = xtab_p->num_page_sz.num_code.fields.pg_num;
+	num_page_sz.num_code.fields.pg_code =
+			xtab_p->num_page_sz.num_code.fields.pg_code;
+	l_pages = xtab_p->l_pages;
+
+	if (num_page_total > MIN_NUM_PAGES_NMMU_HCALL) {
+		hcall_array = (void *)__get_free_pages(GFP_KERNEL,
+			get_order(PAGE_SIZE_4K));
+		if (hcall_array == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfi_register_rpages: __get_free_pages "
+				"failed\n");
+			return -ENOMEM;
+		}
+
+		logical_hcall_array = __pa(hcall_array);
+		memset(hcall_array, 0, PAGE_SIZE_4K);
+	}
+
+	num_page_left = num_page_total;
+	while (num_page_left > 0) {
+		if (num_page_left > MAX_NUM_PAGES_NMMU_HCALL)
+			map_num = MAX_NUM_PAGES_NMMU_HCALL;
+		else
+			map_num = num_page_left;
+
+		num_page_sz.num_code.fields.pg_num = map_num;
+
+		if (map_num == MIN_NUM_PAGES_NMMU_HCALL) {
+			logical_addr = *(unsigned long long *)(l_pages);
+		} else {
+		memcpy(hcall_array, l_pages,
+				sizeof(unsigned long long) *
+				map_num);
+			logical_addr = logical_hcall_array;
+		}
+
+		hvrc = hfi_modify_mr(p_acs->dds.torr_id,
+				(unsigned long long)NMMU_MAP,
+				(unsigned long long)mr_handle,
+				(unsigned long long)submr,
+				(unsigned long long)effective_addr,
+				logical_addr,
+				(unsigned long long)
+				num_page_sz.num_code.llu_value);
+
+		if (hvrc != H_SUCCESS) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfi_register_rpages: HFI_MODIFY_MR "
+				"failed, map_num=0x%x, m_addr=0x%llx\n",
+				map_num, (unsigned long long)effective_addr);
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfi_register_rpages: HFI_MODIFY_MR "
+				"failed, page_sz=0x%llx, hvrc=0x%llx\n",
+				xtab_p->page_sz, hvrc);
+			rc = -EINVAL;
+			break;
+		}
+
+		effective_addr   += map_num * (xtab_p->map_page_sz);
+		l_pages  += map_num * sizeof(unsigned long long);
+		num_page_left -= map_num;
+	}
+
+	/* pass back the number of pages successfully mapped */
+	if (mapped_pages)
+		*mapped_pages = num_page_total - num_page_left;
+	if (num_page_total > MIN_NUM_PAGES_NMMU_HCALL)
+		free_pages((unsigned long)hcall_array, get_order(PAGE_SIZE_4K));
+
+	vfree(xtab_p->l_pages);
+	xtab_p->l_pages = NULL;
+	return rc;
+}
+
+/*
+ * Setup Memory regions for FIFOs. First call
+ * ALLOCATE MR hcall and then MODIFY MR hcall with MAP flag.
+ */
+static int hfi_register_MMU(struct hfidd_acs *p_acs, unsigned int win_index,
+		unsigned int jid, struct hfidd_vlxmem *xtab_p)
+{
+	long long		hvrc = 0;
+	int			rc = 0;
+	unsigned long long	access_ctl;
+	unsigned int		page_code;
+	unsigned long long	l_key = 0;
+	unsigned long long	liobn = 0;
+	caddr_t			addr;
+
+	page_code = (xtab_p->num_page_sz.num_code.fields.pg_code >>
+			HFI_PAGE_CODE_SHIFT) & PAGE_CODE_MASK;
+
+	/* primary and second must be same size */
+	access_ctl = (page_code << HFI_PRI_PAGE_SIZE_SHIFT) |
+		     (page_code << HFI_SEC_PAGE_SIZE_SHIFT) |
+		     (1 << HFI_ELWA_SHIFT);
+	access_ctl = access_ctl << HFI_ACCESS_CTL_SHIFT;
+
+	hvrc = hfi_allocate_mr(p_acs->dds.torr_id,
+			NMMU_MR,
+			(unsigned long long)
+			(xtab_p->e_addr), /* aligned userinput addr */
+			(unsigned long long)
+			(xtab_p->num_page * xtab_p->page_sz),
+			access_ctl,
+			(unsigned long long)jid,
+			(unsigned long long)xtab_p->mr_handle,
+			(unsigned long long *)&(xtab_p->mr_handle),
+			&l_key,
+			&liobn);
+
+	xtab_p->l_key = (unsigned int)l_key;
+	addr = xtab_p->e_addr;
+	if (hvrc != H_SUCCESS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_register_MMU: HFI_ALLOCATE_MR failed, "
+			"hvrc = 0x%llx\n", hvrc);
+		return -EINVAL;
+	}
+
+	rc = hfi_register_rpages(p_acs, xtab_p->mr_handle, 0, xtab_p, NULL);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_register_MMU: hfi_register_rpages failed, "
+			"rc = 0x%x\n", rc);
+
+		hvrc = hfi_free_mr(p_acs->dds.torr_id,
+				NMMU_MR,
+				(unsigned long long)xtab_p->mr_handle,
+				0);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Call FREE MR hcall to free the FIFOs and RDMA context memory regions */
+static int hfi_unregister_MMU(struct hfidd_acs *p_acs,
+		struct hfidd_vlxmem *xtab_p)
+{
+	long long hvrc = 0;
+	int rc = 0;
+
+	hvrc = hfi_free_mr(p_acs->dds.torr_id,
+			NMMU_MR,
+			(unsigned long long)xtab_p->mr_handle,
+			0);
+	if (hvrc != H_SUCCESS) {
+		rc = -EIO;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_unregister_MMU: HFI_FREE_MR failed, "
+			"hvrc = 0x%llx\n", hvrc);
+	}
+	return rc;
+}
+
+/* Setup all the window Memory Regions needed for network traffic  */
+static int hfi_setup_window_in_MMU(struct hfidd_acs *p_acs,
+		unsigned int is_userspace, struct hfidd_window *win_p)
+{
+	int			rc = 0;
+
+	/* Register sfifo and finish vector  memory in MMU */
+	rc = hfi_register_MMU(p_acs, win_p->index, win_p->job_id,
+			win_p->sfifo_x_tab);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_setup_window_in_MMU: sfifo register "
+			"failed, rc = 0x%x\n", rc);
+		goto sfifo_err;
+	}
+
+	/* Register rfifo */
+	rc = hfi_register_MMU(p_acs, win_p->index, win_p->job_id,
+			win_p->rfifo_x_tab);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_setup_window_in_MMU: rfifo register "
+			"failed, rc = 0x%x\n", rc);
+		goto rfifo_err;
+	}
+
+	return 0;
+
+rfifo_err:
+	hfi_unregister_MMU(p_acs, win_p->sfifo_x_tab);
+sfifo_err:
+	return rc;
+}
+
 static int hfi_xlate_fifos(struct hfidd_acs *p_acs,
 		unsigned int is_userspace,
 		struct hfidd_window *win_p,
@@ -399,7 +613,7 @@ hfi_xlate_fifos_err1:
 	return rc;
 }
 
-int hfi_unxlate_fifos(struct hfidd_acs *p_acs, unsigned int is_userspace,
+static int hfi_unxlate_fifos(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		struct hfidd_window *win_p, struct hfi_client_info *client_p)
 {
 	int	rc = 0;
@@ -451,6 +665,15 @@ hfi_alloc_xlate_tab_err1:
 	return -ENOMEM;
 }
 
+static void hfi_free_win_resource(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	hfi_unxlate_fifos(p_acs, is_userspace, win_p, client_p);
+	hfi_free_xlate_tab(win_p);
+}
+
 static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
 		unsigned int is_userspace,
 		struct hfidd_window *win_p,
@@ -478,6 +701,30 @@ static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+static int hfi_setup_window_parm(struct hfidd_acs *p_acs,
+			unsigned int is_userspace,
+			struct hfidd_window *win_p,
+			struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	/* Copy client info into window */
+	memcpy(&(win_p->client_info), client_p, sizeof(struct hfi_client_info));
+
+	/* Call hcall to allocate/map MR in the MMU */
+	rc = hfi_setup_window_in_MMU(p_acs, is_userspace, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_setup_window_parm: hfi_setup_window_in_MMU "
+			"failed, rc = 0x%x\n", rc);
+		goto setup_window_parm_err1;
+	}
+	return 0;
+
+setup_window_parm_err1:
+	return rc;
+}
+
 /*
  * Allows an user/kernel window to send/receive network traffic thru HFI
  * adapter. This function will allocate the system resources needed to open
@@ -528,9 +775,19 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		goto hfidd_open_window_func_err2;
 	}
 
+	rc = hfi_setup_window_parm(p_acs, is_userspace, win_p, local_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_setup_window_parm "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err3;
+	}
+
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err3:
+	hfi_free_win_resource(p_acs, is_userspace, win_p, local_p);
 hfidd_open_window_func_err2:
 	hfi_restore_window_parm(p_acs, win_p);
 hfidd_open_window_func_err1:
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 9fa87c5..3c9f556 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -45,7 +45,23 @@
 #define H_NMMU_FREE_RESOURCE		0xF034
 #define H_NMMU_MODIFY_RESOURCE		0xF03C
 
+#define NMMU_MR		0
+
+#define NMMU_MAP	1
+#define NMMU_UNMAP	0
+#define NMMU_CHECK	2
+
 #define HFI_PAGE_CODE_SHIFT	28
+#define HFI_PRI_PAGE_SIZE_SHIFT	24
+#define HFI_ELWA_SHIFT		23
+#define HFI_ERWA_SHIFt		22
+#define HFI_ERRA_SHIFT		21
+#define HFI_ERAO_SHIFT		20
+#define HFI_ESMR_SHIFT		18
+#define HFI_SEC_PAGE_SIZE_SHIFT	14
+#define HFI_SUBMR_NUM_SHIFT	11
+
+#define HFI_ACCESS_CTL_SHIFT	32
 
 #define EEH_QUERY	1
 #define COMP_QUERY	2
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 216546b..0d6b77b 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -66,6 +66,8 @@
 #include <linux/hfi/hfidd_xlat_map.h>
 
 #define MAX_D_WIN_PER_HFI	(p_acs->dds.num_d_windows)
+#define MAX_NUM_PAGES_NMMU_HCALL 512
+#define MIN_NUM_PAGES_NMMU_HCALL 1
 
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 16/27] HFI: Add window open hypervisor call
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_hcalls.c |   50 +++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |    6 +++
 include/linux/hfi/hfidd_hcalls.h    |   69 +++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
index aabb2a8..1915336 100644
--- a/drivers/net/hfi/core/hfidd_hcalls.c
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -131,6 +131,28 @@ static inline long long h_hfi_query_interface(int token,
 	return rc;
 }
 
+static inline long long h_hfi_open_window(int token,
+		u64 HFI_chip_ID,
+		u64 win_num,
+		u64 flag,
+		u64 win_info_ptr,
+		u64 *user_mmio,
+		u64 *kernel_mmio,
+		u64 *send_int_num,
+		u64 *recv_int_num)
+{
+	long long rc;
+	u64 hyp_outputs[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(token, (unsigned long *)hyp_outputs, HFI_chip_ID,
+			win_num, flag, win_info_ptr);
+	*user_mmio = hyp_outputs[0];	/* 1st ret value */
+	*kernel_mmio = hyp_outputs[1];	/* 2nd */
+	*send_int_num = hyp_outputs[2];		/* 3rd */
+	*recv_int_num = hyp_outputs[3];		/* 4th */
+	return rc;
+}
+
 long long hfi_start_nmmu(u64 chip_id, void *nmmu_info)
 {
 	return h_nmmu_start(H_NMMU_START, chip_id, nmmu_info);
@@ -152,6 +174,34 @@ long long hfi_stop_nmmu(u64 chip_id)
 	return hvrc;
 }
 
+long long hfi_open_window(u64 unit_id, u64 win_id, u64 flag,
+		u64 win_info_p,
+		u64 *ummio_addr_p,
+		u64 *pmmio_addr_p,
+		u64 *send_intr,
+		u64 *recv_intr)
+{
+	long long  hvrc;
+	u64 start_time = get_jiffies_64();
+
+	while (1) {
+		hvrc = h_hfi_open_window(H_HFI_OPEN_WINDOW,
+				unit_id,
+				win_id,
+				flag,
+				win_info_p,
+				ummio_addr_p,
+				pmmio_addr_p,
+				send_intr,
+				recv_intr);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+	return hvrc;
+}
+
 long long hfi_allocate_mr(u64 chip_id, u64 res, u64 addr, u64 mr_size,
 		u64 access,
 		u64 job_id,
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index ff39a02..c4ed215 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -67,6 +67,12 @@ int hfidd_start_interface(struct hfidd_acs *p_acs);
 int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
 long long hfi_start_nmmu(u64 chip_id, void *nmmu_info);
 long long hfi_stop_nmmu(u64 chip_id);
+long long hfi_open_window(u64 unit_id, u64 win_id, u64 flag,
+		u64 win_info_p,
+		u64 *ummio_addr_p,
+		u64 *pmmio_addr_p,
+		u64 *send_intr,
+		u64 *recv_intr);
 long long hfi_allocate_mr(u64 chip_id, u64 res, u64 addr,
 		u64 mr_size,
 		u64 access,
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 3c9f556..a97bb5e 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -39,12 +39,19 @@
 #define H_HFI_START_INTERFACE		0xF000
 #define H_HFI_QUERY_INTERFACE		0xF004
 #define H_HFI_STOP_INTERFACE		0xF008
+#define H_HFI_OPEN_WINDOW		0xF00C
 #define H_NMMU_START			0xF028
 #define H_NMMU_STOP			0xF02C
 #define H_NMMU_ALLOCATE_RESOURCE	0xF030
 #define H_NMMU_FREE_RESOURCE		0xF034
 #define H_NMMU_MODIFY_RESOURCE		0xF03C
 
+#define H_OPEN		0x8000000000000000
+#define H_RESUME	0x0000000000000000
+#define H_SUSPEND	0x0000000000000000
+#define H_CLOSE		0x0000000000000001
+#define H_CHECK_CLOSED	0x0000000000000002
+
 #define NMMU_MR		0
 
 #define NMMU_MAP	1
@@ -63,6 +70,68 @@
 
 #define HFI_ACCESS_CTL_SHIFT	32
 
+struct win_open_info {
+	/* Hyp Feedback */
+	unsigned long long	hypervisor_capabilities;
+	unsigned int		error_offset;
+
+	/* Window Control */
+	unsigned int		job_id;			/* send & recv jobid */
+	unsigned int		protection_domain;
+
+	/* Immediate Send Context */
+	unsigned int		immediate_send_pid;
+	unsigned int		immediate_send_slots;
+	unsigned int		immediate_send_update_freq;
+	unsigned long long	immediate_send_finish_vec;
+
+	/* Send Fifo */
+	unsigned long long	sfifo_base_eaddr;
+	unsigned int		sfifo_lkey;
+	unsigned int		sfifo_size;		/* in bytes */
+	unsigned long long	sfifo_finish_vec;
+
+	/* Full RDMA Send Fifo */
+	unsigned long long	fullrdma_fifo_base_eaddr;
+	unsigned int		fullrdma_fifo_lkey;
+	unsigned int		fullrdma_fifo_size;	/* in bytes */
+	unsigned int		fullrdma_msg_breakup_count;
+	unsigned long long	fullrdma_fifo_finish_vec;
+
+	/* Receive Fifo */
+	unsigned long long	rfifo_base_eaddr;
+	unsigned int		rfifo_lkey;
+	unsigned int		rfifo_size;		/* in bytes */
+
+	/* IP2k Free Space Decriptor Fifo */
+	unsigned long long	ip2kfifo_base_eaddr;
+	unsigned int		ip2kfifo_lkey;
+	unsigned int		ip2kfifo_size;		/* in bytes */
+
+	/* RDMA Pending Fifo */
+	unsigned long long      rdmapending_base_eaddr;
+	unsigned int            rdmapending_lkey;
+	unsigned int            rdmapending_size;       /* in bytes */
+	unsigned int            rdmapending_read_req_thresh;
+
+	/* SendSpecial Fifo */
+	unsigned long long	specialfifo_base_eaddr;
+	unsigned int		specialfifo_lkey;
+	unsigned int		specialfifo_size;	/* in bytes */
+
+	/* IP Context */
+	unsigned int		is_ip_window;
+	unsigned int		multicast_enable;
+	unsigned int		disable_src_isr_id_stamp;
+	unsigned int		logical_port_id_valid;
+	unsigned int		logical_port_id;
+
+	/* RDMA Context */
+	unsigned long long	rcxt_base_eaddr;
+	unsigned int		rcxt_lkey;
+	unsigned int		rdma_payload_lkey;
+};
+
 #define EEH_QUERY	1
 #define COMP_QUERY	2
 
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 23/27] HFI: Define packet header formats and window register offsets
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 include/linux/hfi/hfidd_pkt_formats.h |  338 +++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_regs.h        |  212 +++++++++++++++++++++
 2 files changed, 550 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/hfi/hfidd_pkt_formats.h
 create mode 100644 include/linux/hfi/hfidd_regs.h

diff --git a/include/linux/hfi/hfidd_pkt_formats.h b/include/linux/hfi/hfidd_pkt_formats.h
new file mode 100644
index 0000000..ee8d385
--- /dev/null
+++ b/include/linux/hfi/hfidd_pkt_formats.h
@@ -0,0 +1,338 @@
+/*
+ * hfidd_pkt_formats.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _HFI_PKT_FORMATS_H
+#define _HFI_PKT_FORMATS_H
+
+#define HFI_HW_DIRECT_ROUTE		0
+#define HFI_SW_INDIRECT_ROUTE		1
+#define HW_DIRECT_STRIPING_ROUTE	2
+#define HW_INDIRECT_STRIPING_ROUTE	3
+
+/* HFI packet header format */
+
+struct immediate_send_hdr {
+	unsigned int	reserved1:8;
+	unsigned int	cop_type:8;	/* HFI coprocessor type is 0x3A */
+	unsigned int	reserved2:7;
+	unsigned int	src_win:9;	/* Hi bit is hfi# */
+} __packed;
+
+struct packet_type_hdr {
+	unsigned int	header_type:7;	/* See hfi_packet_type for types */
+	unsigned int	send_origin:1;	/*  0: from Send/RDMA FIFO */
+					/*  1: from Immediate Send */
+} __packed;
+
+struct base_hdr {
+	unsigned int	reserve1:1;
+	unsigned int	dst_isr:14;	/* destination ISR */
+	unsigned int	dst_win:9;	/* destination window.
+					   Hi bit is hfi num */
+	unsigned int	reserve2:1;
+
+	unsigned int	src_isr:14;	/* src ISR, Set by hardware */
+	unsigned int	src_win:9;	/* src window, Set by hardware.
+					   Hi bit is hfi num */
+	unsigned int	src_cau:1;
+	unsigned int	dst_cau:1;
+	unsigned int	reserve3:2;
+
+	unsigned int	pkt_len:4;	/* In cache lines. 0 means 16 */
+	unsigned int	reserve4:8;
+	unsigned int	trc_enable:1;	/* Request ISR trace info
+					   send/recv, IP packest only */
+	unsigned int	ctr_incr:1;	/* Request send and receive
+					   counter increments */
+	unsigned int	sii:1;		/* Source Side Immediate Int */
+	unsigned int	dii:1;		/* Dest Side Immediate Int */
+	unsigned int	reserve5:3;
+	unsigned int	pkt_valid:1;	/* Set by hardware
+					   Toggles when rFIFO wraps */
+	unsigned int	status:5;	/* Set by hardware completion status */
+	unsigned int	route_control:2;/* ISR use only	*/
+	unsigned int	ind_node:9;	/* ISR use only	*/
+} __packed;
+
+struct hfi_rdma_extended_hdr {			/* 48B */
+	unsigned long long	source_ea;	/* Full RDMA only, byte
+						   boundary */
+	unsigned long long	dest_ea;	/* byte boundary, independent of
+						   source data boundary	*/
+	unsigned int	pkt_len:4;		/* In cache lines, with
+						   exceptions */
+	unsigned int	reserved1:3;
+	unsigned int	msg_len:25;		/* In bytes.
+						   FullRDMA: Max 32MB
+						   (encoded as 0)
+						   HalfRDMA: Max 2kB
+						   SmallRDMA: Max 16B */
+	unsigned int	reserved2:5;
+	unsigned int	rcxt_offset:20;		/* into window's rcxt area */
+	unsigned int	reserved3:1;
+	unsigned int	breakup:6;		/* Message Breakup count */
+	unsigned int	epoch:32;
+	unsigned int	seq_num:14;
+	unsigned int	pkt_cnt:18;		/* FullRDMA only */
+	unsigned int	reserved4:3;
+	unsigned int	rcxt_index:5;		/* 1-31 allowed */
+	unsigned int	read_indicator:1;	/* 1 for FULL RDMA reads */
+	unsigned int	src_completion:1;
+	unsigned int	src_completion_notify:1;
+	unsigned int	dst_completion_notify:1;
+	unsigned int	status:5;		/* Notification packet only. */
+	unsigned int	reserved6:3;
+	unsigned int	fetch:1;		/* SmallRDMA only. */
+	unsigned int	opcode:3;
+	unsigned int	reserved7:8;
+	unsigned int	reserved8:32;
+	unsigned long long	cookie;		/* Protocol cookie */
+} __packed;
+
+struct gups_rdma_element {			/* 32B. Used without Base
+						   header */
+	unsigned int	job_id:32;
+	unsigned int	header_type:7;		/* Use GUPS types only */
+	unsigned int	reserved1:2;
+	unsigned int	dst_isr:14;		/* destination ISR */
+	unsigned int	dst_win:9;		/* destination window.
+						   Hi bit is hfi# */
+	unsigned int	reserved2:15;
+	unsigned int	ctr_incr:1;		/* Request send and receive
+						   counter increments */
+	unsigned int	isr_route_hdr:16;	/* ISR use only	*/
+	unsigned int	reserved3:32;
+
+	union {
+		unsigned long long	addr;
+		struct {
+			unsigned int	dest_ea_hi:32;
+			unsigned int	dest_ea_lo:29;	/* 8-byte align */
+			unsigned int	opcode:3;	/* Use HFI_OPCODE* */
+		} bits;
+	} dest_ea;
+
+	unsigned long long     payload;
+} __packed;
+
+struct hfi_cau_extended_hdr {		/* 32B */
+	unsigned int		group_id:27;
+	unsigned int		dst_sub_id:9;
+	unsigned int		src_sub_id:9;
+	unsigned int		reserved1:3;
+	unsigned int		op_attr_unsigned:1;	/* 0->Signed */
+	unsigned int		op_attr_64bit:1;	/* 0->32 bit */
+	unsigned int		op_attr_float:1;	/* 0->Fixed  */
+	unsigned int		function:5;
+	unsigned int		payload_cnt:8;		/* bitmask */
+	unsigned int		seq_num:32;
+	unsigned int		reserved2:6;
+	unsigned int		entry:1;		/* 0->A, 1->B */
+	unsigned int		reserved3:25;
+	unsigned long long	cookie_left;		/* Protocol Cookie */
+	unsigned long long	cookie_right;
+} __packed;
+
+struct hfi_hdr {
+	union {
+		struct immediate_send_hdr immediate_hdr;
+		unsigned int		job_id;
+	} id;
+
+	struct packet_type_hdr		type;
+	struct base_hdr			base_hdr;
+} __packed;
+
+struct hfi_rdma_hdr {
+	struct hfi_hdr		hfi_hdr;
+	struct hfi_rdma_extended_hdr rdma_ext;
+	/*
+	 * Pad enough for the payload to be aligned with the dest address.
+	 * SmallRDMA: no padding FullRDMA: packets 2-N pad 64 bytes
+	 */
+} __packed;
+
+
+struct hfi_rdma_pkt {
+	struct hfi_hdr		hfi_hdr;
+	struct hfi_rdma_extended_hdr rdma_ext;
+	/*
+	 * Pad enough for the payload to be aligned with the dest address.
+	 * SmallRDMA: no padding FullRDMA: packets 2-N pad 64 bytes
+	 */
+	char			padding_slash_payload[1984];
+} __packed;
+
+
+#define CACHE_LINE_SIZE 0x80
+#define CACHE_LINE_SHIFT 0x7
+/*
+ * Encode/Decode macros/inlines for bit fields
+ */
+static inline unsigned int hfi_bytes_to_cacheline(unsigned int bytes)
+{
+	return (bytes + (CACHE_LINE_SIZE - 1)) >> CACHE_LINE_SHIFT;
+}
+
+static inline unsigned int HFI_CACHELINES_TO_BYTES(unsigned int cache_lines)
+{
+	return cache_lines << CACHE_LINE_SHIFT;
+}
+
+static inline unsigned int hfi_cachelines_to_pktlen(unsigned int cachelines)
+{
+	return cachelines & 0xf;  /* No overflow checking */
+}
+
+static inline unsigned int hfi_pktlen_to_cachelines(unsigned int pktlen)
+{
+	return pktlen ? pktlen : 16;	/* 0 pktlen == 16 cache lines */
+}
+
+struct hfi_gups_rdma_pkt {
+	struct gups_rdma_element element[4];
+} __packed;
+
+struct hfi_collective_pkt {
+	struct hfi_hdr		hfi_hdr;
+	struct hfi_cau_extended_hdr cau_ext;
+	char			payload[64];
+	char			pad[16];
+} __packed;
+
+/*
+ * Opcodes for RDMA Extended Headers and GUPS-RDMA Elements
+ */
+#define HFI_OPCODE_ADD			0x0
+#define HFI_OPCODE_AND			0x1
+#define HFI_OPCODE_OR			0x2
+#define HFI_OPCODE_XOR			0x3
+#define HFI_OPCODE_RESERVED		0x4
+#define HFI_OPCODE_CMP_SWAP_NOT_EQUAL	0x5
+#define HFI_OPCODE_CMP_SWAP_EQUAL	0x6
+#define HFI_OPCODE_SWAP			0x7
+/* Fetch can be OR'd with any of the above Opcodes (SmallRDMA only) */
+#define HFI_OPCODE_FETCH		0x8
+
+enum hfi_cau_type {
+	HFI_CAU_TYPE_FLOAT			= 0x01,
+	HFI_CAU_TYPE_64BIT			= 0x02,
+	HFI_CAU_TYPE_UNSIGNED			= 0x04
+};
+
+enum hfi_cau_function {
+	HFI_CAU_FUNCTION_NOP			= 0x00,
+	HFI_CAU_FUNCTION_SUM			= 0x01,
+	HFI_CAU_FUNCTION_MIN			= 0x02,
+	HFI_CAU_FUNCTION_MAX			= 0x03,
+	HFI_CAU_FUNCTION_AND			= 0x11,
+	HFI_CAU_FUNCTION_XOR			= 0x16,
+	HFI_CAU_FUNCTION_OR			= 0x17
+};
+
+enum hfi_pkt_status {
+	HFI_PKT_STATUS_GOOD			= 0x0,
+	HFI_PKT_STATUS_DESCRIPTOR_FAILURE	= 0x1,
+	HFI_PKT_STATUS_PACKET_KILLED		= 0x2,
+	HFI_PKT_STATUS_UNEXPECTED_LAST_FLIT	= 0x4,
+	HFI_PKT_STATUS_POWERBUS_MASTER		= 0x8,
+	HFI_PKT_STATUS_TRANSLATION_FAULT	= 0x10
+
+};
+
+enum hfi_rdma_pkt_status {
+	HFI_RDMA_PKT_STATUS_GOOD		= 0x0,
+	HFI_RDMA_PKT_STATUS_MIGRATION_CONFLICT	= 0x1,
+	HFI_RDMA_PKT_STATUS_PACKET_KILLED	= 0x4,
+	HFI_RDMA_PKT_STATUS_POWERBUS_MASTER	= 0x8,
+	HFI_RDMA_PKT_STATUS_TRANSLATION_FAULT	= 0x10
+
+};
+
+enum hfi_packet_type {
+	HFI_SEND_RECEIVE			= 0x00,	/* send FIFO -> receive
+							   FIFO */
+
+	HFI_IP_WITH_PAYLOAD			= 0x08,	/* send FIFO -> receive
+							   FIFO for IP */
+	HFI_IP_MULTICAST_WITH_PAYLOAD		= 0x09,	/* ISR use only */
+	HFI_IP_WITH_DESCRIPTORS			= 0x0C,	/* IP send/recv with
+							   indirection */
+	HFI_IP_MULTICAST_WITH_DESCRIPTORS	= 0x0D,	/* IP send/recv with
+							   indirection */
+
+	HFI_FULL_RDMA_WRITE			= 0x10,
+	HFI_FULL_RDMA_READ			= 0x11,
+	HFI_FULL_RDMA_COMPLETION		= 0x12,	/* Completion
+							   notification */
+	HFI_FULL_RDMA_PREFENCE			= 0x13,	/* Guarantee RDMA FIFO
+							   processing is
+							   complete */
+	HFI_FULL_RDMA_FENCE			= 0x14,	/* Guarantee RDMA FIFO
+							   processing is
+							   complete */
+	HFI_FULL_RMDA_WRITE_ALIAS		= 0x15,	/* HW use only */
+
+	HFI_HALF_RDMA_WRITE			= 0x18,	/* send FIFO to target
+							   EA */
+	HFI_HALF_RDMA_READ			= 0x19,	/* target EA to receive
+							   FIFO */
+	HFI_HALF_RDMA_COMPLETION		= 0x1A,	/* Completion
+							   notification */
+	HFI_HALF_RDMA_READ_ALIAS		= 0x1D,	/* HW use only */
+
+	HFI_SMALL_RDMA_WRITE			= 0x20,	/* Remote atomic
+							   operations */
+	HFI_SMALL_RDMA_COMPLETION		= 0x22,	/* Completion
+							   notification */
+	HFI_SMALL_RDMA_COMPLETION_WITH_FETCH	= 0x23,	/* Completion
+							   notification */
+
+	HFI_GUPS_RDMA_1ELEMENT			= 0x28,	/* GUPS-RDMA, 1
+							   element */
+	HFI_GUPS_RDMA_2ELEMENT			= 0x29,	/* GUPS-RDMA,
+							   2 element */
+	HFI_GUPS_RDMA_3ELEMENT			= 0x2A,	/* GUPS-RDMA, 3
+							   element */
+	HFI_GUPS_RDMA_4ELEMENT			= 0x2B,	/* GUPS-RDMA, 4
+							   element */
+
+	HFI_CAU_REDUCE				= 0x30,	/* Collective Reduce */
+	HFI_CAU_MULTICAST			= 0x31,	/* Collective
+							   Multicast */
+	HFI_CAU_ACK				= 0x32,	/* Collective Ack */
+	HFI_CAU_RETRANS_REQ			= 0x33,	/* Collective
+							   Retransmit Req */
+	HFI_LAST_HEADER
+};
+
+#endif /* _HFI_PKT_FORMATS_H */
diff --git a/include/linux/hfi/hfidd_regs.h b/include/linux/hfi/hfidd_regs.h
new file mode 100644
index 0000000..864e0e6
--- /dev/null
+++ b/include/linux/hfi/hfidd_regs.h
@@ -0,0 +1,212 @@
+/*
+ * hfidd_regs.h
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef HFIDD_REGS_H
+#define HFIDD_REGS_H
+
+/* MMIO Registers */
+/* These are the registers with User Privilege Level */
+
+/* Window Control */
+#define HFI_JOB_ID_SEND		0x0000	/* 32: Send Side Job ID */
+#define HFI_JOB_ID_RECV		0x0008	/* 32: Send Side Job ID */
+#define HFI_WINDOW_STATE	0x0010	/*  1: 0=closed, 1=active */
+#define HFI_SEND_BUSY		0x0020	/* Send Window Busy */
+#define HFI_RECV_BUSY		0x0028	/* Rcv Window Busy */
+
+/* Addr Translation */
+#define HFI_LPAR_ID		0x0040	/* 10: Partition ID */
+#define HFI_PROTECTION_DOMAIN	0x0048	/* 32: used for addr xlat */
+#define HFI_XLAT_BYPASS		0x0050	/*  1:			  */
+
+/* Imm Send */
+#define HFI_IMM_SEND_BUF_ATTRBS	0x0080	/* 40: Immed Send Buffer Attributes */
+#define HFI_IMM_BUF_INUSE	0x0090	/* Immed Send Buffers In Use */
+#define HFI_IMM_FINI_COUNT	0x00A0	/* Immed Send Buffer Finished Count */
+#define HFI_IMM_FINI_FREQUENCY	0x00A8	/* Immed Send Finished Frequency */
+
+/* Send Fifo */
+#define HFI_SFIFO_DB_REG	0x0110	/* 16: Send Fifo Doorbell */
+#define HFI_SFIFO_BASE_ADDR	0x0120	/* 64: Send Fifo Effective Addr */
+#define HFI_SFIFO_LKEY		0x0128	/* 32: Send Fifo Local Key */
+#define HFI_SFIFO_PULL_OFF	0x0140	/* 64: Send Fifo Pull Offset */
+#define HFI_SFIFO_SIZE		0x0148	/*  4: size from 4K to 8M   */
+#define HFI_SFIFO_PEND_COUNT	0x0150	/* 16: Send Fifo Pending Count */
+#define HFI_SFIFO_FINI_POLARITY	0x0158	/*  1: Send Fifo Finish Polarity Bit */
+#define HFI_SFIFO_FINI_ADDR	0x0180	/* 64: Send Fifo Finish Effective
+					   Addr */
+#define HFI_IMM_FINI_ADDR	0x0188	/* Immed Send Finished Address */
+#define HFI_SFIFO_INTR_CNTL	0x01C8	/* xx: Send Fifo Interrupt Control */
+
+/* Full-RDMA Send Fifo */
+#define HFI_FRDMA_DB_REG	0x0210	/* Full-RDMA Send Fifo Doorbell */
+#define HFI_FRDMA_BASE_ADDR	0x0220	/* Full-RDMA Send Fifo Effective
+					   Address */
+#define HFI_FRDMA_LKEY		0x0228	/* Full-RDMA Send Fifo Local Key */
+#define HFI_FRDMA_PULL_REG	0x0240	/* Full-RDMA Send Fifo Pull Offset */
+#define HFI_FRDMA_SIZE		0x0248	/* Full-RDMA Send Size */
+#define HFI_FRDMA_PEND_REG	0x0250	/* Full-RDMA Send Fifo Pending Count */
+#define HFI_FRDMA_FINI_POLARITY	0x0248	/* Full-RDMA Send Fifo Finished
+					   Polarity */
+#define HFI_FRDMA_BREAKUP_REG	0x0260	/* Full-RDMA Send Fifo Breakup Count */
+#define HFI_FRDMA_FINI_ADDR	0x0280	/* Full-RDMA Send Fifo Finished
+					   Address */
+#define HFI_FRDMA_INTR_REG	0x02C8	/* Full-RDMA Send Fifo Interrupt
+					   Control */
+#define HFI_FRDMA_FENCE_CNT	0x0578	/* Full-RDMA Send Fifo Fence Count */
+
+/* Send Interrupts */
+#define HFI_SINTR_CONTROL_REG	0x02E0	/* Send Force Interrupt Control */
+#define HFI_SINTR_STATUS_REG	0x02E8	/* Send Intr Status */
+
+/* Receive Fifo */
+#define HFI_RFIFO_INC_FSLOT_REG	0x0310	/* Receive Fifo Inc Free Slot Count */
+#define HFI_RFIFO_BASE_ADDR	0x0320	/* Receive Fifo Effective Address */
+#define HFI_RFIFO_LKEY		0x0328	/* Receive Fifo Local Key */
+#define HFI_RFIFO_PUSH_REG	0x0340	/* Receive Fifo Push Offset */
+#define HFI_RFIFO_SIZE		0x0348	/*  4: range from 4K to 8M   */
+#define HFI_RFIFO_FSLOT_CNT_REG	0x0350	/* Receive Fifo Free Slot Count */
+#define	HFI_RFIFO_FINI_POLARITY	0x0358	/* Receive Fifo Finished Polarity */
+#define HFI_RFIFO_INJ_TH_REG	0x0360	/* Receive Fifo Cache Injection
+					   Threshold */
+#define HFI_RFIFO_OUT_TH_REG	0x0368	/* Receive Fifo Out-of-Order
+					   Threshold */
+#define HFI_RFIFO_OUT_EVENT_REG	0x03C0	/* Receive Fifo Out-of-Order Event
+					   Control */
+#define HFI_RFIFO_INTR_REG	0x03C8	/* Receive Fifo Intr Control */
+
+/* Receive Interrupts */
+#define HFI_RINTR_CONTROL_REG	0x03E0	/* Receive Force Intr Control */
+#define HFI_RINTR_STATUS_REG	0x03E8	/* Receivce Intr Status */
+
+/* IP 2K Free Space Descriptor Fifo */
+#define HFI_IP2K_INC_AVAIL_REG	0x0410	/* IP 2k FSD Fifo Inc Avail Slot
+					   Count */
+#define HFI_IP2K_BASE_ADDR	0x0420	/* IP 2k FSD Fifo Effective Address */
+#define HFI_IP2K_LKEY		0x0428	/* IP 2k FSD Fifo Local Key */
+#define HFI_IP2K_PULL_REG	0x0440	/* IP 2k FSD Fifo Pull Offset */
+#define HFI_IP2K_SIZE		0x0448	/* IP 2k FSD Fifo Size */
+#define HFI_IP2K_ASLOT_CNT_REG	0x0450	/* IP 2k FSD Fifo Avail Slot Count */
+
+/* RDMA Pending Fifo */
+#define HFI_RDMAP_BASE_ADDR	0x0520	/* RDMA Pending Fifo Efective Address */
+#define HFI_RDMAP_LKEY		0x0528	/* RDMA Pending Fifo Local Key */
+#define HFI_RDMAP_PULL_REG	0x0540	/* RDMA Pending Fifo Pull Offset */
+#define HFI_RDMAP_SIZE		0x0548	/* RDMA Pending Fifo Size */
+#define HFI_RDMAP_READ_TH_REG	0x0568	/* RDMA Pending Fifo Read Request
+					   Threshold */
+#define HFI_RDMAP_PUSH_REG	0x0570	/* RDMA Pending Fifo Push Offset */
+#define HFI_RDMAP_PEND_REG	0x0550	/* RDMA Pending Fifo Pending Count */
+
+/* Send Special Fifo */
+#define HFI_SSFIFO_BASE_ADDR	0x0620	/* Send Special Fifo Effective
+					   Address */
+#define HFI_SSFIFO_LKEY		0x0628	/* Send Special Fifo Local Key */
+#define HFI_SSFIFO_PULL_REG	0x0640	/* Send Special Fifo Pull Offset */
+#define HFI_SSFIFO_SIZE		0x0648	/* Send Special Fifo Size */
+#define HFI_SSFIFO_PUSH_REG	0x0670	/* Send Special Fifo Push Offset */
+#define HFI_SSFIFO_PENG_REG	0x0650	/* Send Special Fifo Pending Count */
+
+/* IP Context */
+#define HFI_IP_MCAST_ENABLE_REG	0x0820	/* IP Send - Multi-cast Enable */
+#define HFI_IP_DISABLE_ISR_REG	0x0828	/* IP Send - Disable Src_ISR_ID
+					   Stamp */
+#define HFI_IP_PORT_VALID_REG	0x0830	/* IP Logical Port ID Valid */
+#define	HFI_IP_PORT_REG		0x0838	/* IP Logical Port ID */
+#define HFI_IP_RECV_SIZE	0x0860	/* IP Recv with Payload Max Size */
+#define HFI_IP_RCV_IMM_REG	0x0868	/* IP RCV-Immediate Max Size */
+
+/* RDMA Context */
+#define HFI_RDMA_RCXT_BASE_ADDR	0x0920	/* RDMA Rcv RCxt Effective Address */
+#define HFI_RDMA_RCXT_LKEY	0x0928	/* RDMA RCxt Local Key */
+#define	HFI_RDMA_RCXT_PAY_LKEY	0x0058	/* RDMA Payload Local Key
+					   (no-sequential) */
+#define HFI_RDMA_RCXT_EPOCH	0x0980	/* RCxt Update Epoch */
+#define HFI_RDMA_RCXT_CACHE	0x0990	/* RCxt Cache Entry Flush Request */
+
+/* Counters */
+#define HFI_PACKETS_SENT_REG	0x0C00	/* Packets Sent */
+#define HFI_PSENT_DROP_REG	0x0C08	/* Packets Dropped from Sending */
+#define HFI_PIND_SENT_CNT_REG	0x0C10	/* Packet-Indicated Send Count */
+#define HFI_IMM_SEND_CNT_REG	0x0C18	/* Immed Send Packet Count */
+#define HFI_PACKETS_RCV_REG	0x0C40	/* Packets Received */
+#define HFI_PRCV_DROP_REG	0x0C48	/* Packets Dropped from Receiving */
+#define HFI_PIND_RCV_CNT_REG	0x0C50	/* Packet-Indicated Receive Count */
+#define HFI_SBIT_EEC_CNT_REG	0x0C60	/* Single-Bit ECC Count */
+#define HFI_SBIT_EEC_TH_REG	0x0C68	/* Single-Bit ECC Threshold for Error */
+#define HFI_ADDR_XLAT_CNT_REG	0x0C80	/* Addr Xlat Wait Count */
+
+/* Misc Non-Window Registers */
+#define	HFI_NUM_WINDOWS_REG	0x0000	/* Number of Windows */
+#define HFI_AGGR_PSENT_CNT_REG	0x0100	/* Aggregate Packet Sent Count */
+#define HFI_AGGR_PSENT_DROP_REG	0x0108	/* Aggregate Packet Dropped from
+					   Sending Count */
+#define HFI_AGGR_PRCV_CNT_REG	0x0110	/* Aggregate Packet Receive Count */
+#define HFI_AGGR_PRCV_DROP_REG	0x0118	/* Aggregate Packet Dropped from
+					   Receive Count */
+#define HFI_AGGR_ISEND_CNT_REG	0x0120	/* Aggregate Immediate Send Packet
+					   Sent Count */
+#define HFI_AGGR_SR_CNT_REG	0x0128	/* Aggregate Send/Rcv Packet Send
+					   Count */
+#define HFI_AGGR_FRDMA_CNT_REG	0x0130	/* Aggregate Full-RDMA Packet Sent
+					   Count */
+#define HFI_AGGR_HRDMA_CNT_REG	0x0138	/* Aggregate Half-RDMA Packet Sent
+					   Count */
+#define HFI_AGGR_SRDMA_CNT_REG	0x0140	/* Aggregate Small-RDMA Packet Sent
+					   Count */
+#define HFI_AGGR_IP_CNT_REG	0x0148	/* Aggregate IP Packet Sent Count */
+#define HFI_AGGR_CAU_CNT_REG	0x0150	/* Aggregate CAU Packet Sent Count */
+#define HFI_AGGR_GUPS_CNT_REG	0x0158	/* Aggregate GUPS Packet Sent Count */
+#define HFI_AGGR_NOTIFS_CNT_REG 0x0170  /* Aggregate Notifications Packet Sent
+						Count*/
+
+#define HFI_RCXT_FLUSH_REG	0x0600	/* RCxt Cache Window Flush Request */
+#define HFI_PG_MIGR1_REG	0x0708	/* Page Migration Register 1 */
+#define HFI_PG_MIGR2_REG	0x0710	/* Page Migration Register 2 */
+#define HFI_PG_MIGR3_REG	0x0718	/* Page Migration Register 3 */
+#define HFI_PG_MIGR4_REG	0x0720	/* Page Migration Register 4 */
+#define HFI_PG_MIGR5_REG	0x0728	/* Page Migration Register 5 */
+#define HFI_PG_MIGR6_REG	0x0730	/* Page Migration Register 6 */
+#define HFI_PG_MIGR7_REG	0x0738	/* Page Migration Register 7 */
+#define HFI_PG_MIGR1_RESV_REG	0x0808	/* Page Migration Reservation 1 */
+#define HFI_PG_MIGR2_RESV_REG	0x0810	/* Page Migration Reservation 2 */
+#define HFI_PG_MIGR3_RESV_REG	0x0818	/* Page Migration Reservation 3 */
+#define HFI_PG_MIGR4_RESV_REG	0x0820	/* Page Migration Reservation 4 */
+#define HFI_PG_MIGR5_RESV_REG	0x0828	/* Page Migration Reservation 5 */
+#define HFI_PG_MIGR6_RESV_REG	0x0830	/* Page Migration Reservation 6 */
+#define HFI_PG_MIGR7_RESV_REG	0x0838	/* Page Migration Reservation 7 */
+#define HFI_ADDR_XLAT_WCNT_REG	0x0A20	/* Addr Xlat Wait Count */
+
+#define MASK_56_BITS	0x00ffffffffffffff
+#define MASK_40_BITS	0x000000ffffffffff
+
+#endif /* HFIDD_REGS_H */
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 26/27] HFI: hf fifo receive path
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/ip/hf_if_main.c |  328 ++++++++++++++++++++++++++++++++++++++-
 drivers/net/hfi/ip/hf_proto.h   |    2 +
 include/linux/hfi/hf_if.h       |   25 +++-
 3 files changed, 352 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
index ea4579e..10dc1da 100644
--- a/drivers/net/hfi/ip/hf_if_main.c
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -177,6 +177,9 @@ static int hf_alloc_rx_resource(struct hf_if *net_if)
 
 	memset(net_if->rx_fifo.addr, 0, net_if->rx_fifo.size);
 
+	net_if->rx_fslot_debt = 0;
+	net_if->rx_pkt_valid = 1;
+
 	return 0;
 }
 
@@ -232,8 +235,18 @@ static int hf_send_intr_callback(void *parm, u32 win, u32 ext)
 	return 0;
 }
 
+static int hf_recv_intr_callback(void *parm, u32 win, u32 ext)
+{
+	struct hf_net	*net = (struct hf_net *)parm;
+
+	napi_schedule(&(net->napi));
+
+	return 0;
+}
+
 struct hf_events_cb hf_events[HF_EVENT_NUM] = {
 	{HFIDD_SEND,		(void *)hf_send_intr_callback},
+	{HFIDD_RECV,		(void *)hf_recv_intr_callback},
 };
 
 static int hf_register_ip_events(struct hf_net *net,
@@ -376,14 +389,50 @@ static int hf_set_mac_addr(struct net_device *netdev, void *p)
 	return 0;
 }
 
+static void hf_set_recv_intr(struct hf_if *net_if)
+{
+	int			offset;
+	struct hfi_hdr		*rx_pkt;
+
+	/* enable recv intr and set threshold to next packet */
+	offset = net_if->rx_fifo.head;
+
+	hf_mmio_regs_write_then_read(net_if, HFI_RFIFO_INTR_REG,
+		(HF_ENA_RECV_INTR + (offset << HF_RECV_INTR_MATCH_SHIFT)));
+
+	/* check if there is packet received in the mean time */
+	rx_pkt = net_if->rx_fifo.addr + (offset << HFI_CACHE_LINE_SHIFT);
+
+	if ((rx_pkt->id.job_id == HF_IP_JOBID) &&
+		(rx_pkt->base_hdr.pkt_valid == net_if->rx_pkt_valid)) {
+
+		/* force an immediate recv intr */
+		hf_mmio_regs_write(net_if, HFI_RFIFO_INTR_REG,
+		(HF_IMM_RECV_INTR + (offset << HF_RECV_INTR_MATCH_SHIFT)));
+	}
+}
+
 static void hf_init_hw_regs(struct hf_if *net_if)
 {
 	/* setup IP with payload threshold in cache line size */
 	hf_mmio_regs_write(net_if, HFI_IP_RECV_SIZE,
 		(HF_PAYLOAD_RX_THRESHOLD << HF_PAYLOAD_RX_THRESH_SHIFT));
 
+	/* setup recv fifo out of order intr control to disable */
+	hf_mmio_regs_write(net_if, HFI_RFIFO_OUT_EVENT_REG,
+			HF_RFIFO_OUT_CNTL_REARM);
+
+	/* setup recv fifo out of order threshold */
+	hf_mmio_regs_write(net_if, HFI_RFIFO_OUT_TH_REG, HF_RFIFO_OUT_THRESH);
+
 	/* initialize SEND INTR STATUS */
 	hf_mmio_regs_write(net_if, HFI_SINTR_STATUS_REG, 0);
+
+	hf_mmio_regs_write(net_if, HFI_RFIFO_INJ_TH_REG,
+			(HF_RFIFO_CACHE_INJ_TH << HF_RFIFO_CACHE_INJ_TH_SHIFT));
+
+	/* enable and set receive intr */
+	hf_set_recv_intr(net_if);
 }
 
 static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
@@ -422,6 +471,7 @@ static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
 	net_if->state = HF_NET_OPEN;
 	spin_unlock(&(net_if->lock));
 
+	napi_enable(&net->napi);
 	netif_carrier_on(netdev);
 	netif_start_queue(netdev);
 
@@ -511,6 +561,7 @@ static int hf_net_close(struct net_device *netdev)
 
 	spin_lock(&(net_if->lock));
 	if (net_if->state == HF_NET_OPEN) {
+		napi_disable(&net->napi);
 		netif_stop_queue(netdev);
 		netif_carrier_off(netdev);
 
@@ -530,6 +581,247 @@ static int hf_net_close(struct net_device *netdev)
 	return 0;
 }
 
+/* Invalidate the jobid field of each cache line before advancing head.
+ * The first cache line is protected by the valid bit, so we skip it. */
+static inline void hf_advance_rx_head(struct hf_if *net_if, u32 len)
+{
+	int		i, h;
+	u32		*cache_p;
+
+	h = (net_if->rx_fifo.head + 1) & (net_if->rx_fifo.emax);
+
+	for (i = 1; i < len; i++) {
+		cache_p = (u32 *)((char *)(net_if->rx_fifo.addr) +
+				(h << HFI_CACHE_LINE_SHIFT));
+		if (*cache_p == HF_IP_JOBID)
+			*cache_p = 0;
+		h = (h + 1) & (net_if->rx_fifo.emax);
+	}
+
+	if (net_if->rx_fifo.head > h)
+		net_if->rx_pkt_valid ^= 0x1;
+
+	net_if->rx_fifo.head = h;
+}
+
+void hf_construct_hwhdr(struct hf_if *net_if,
+			struct sk_buff *skb,
+			struct base_hdr *b_hdr)
+{
+	struct hf_hwhdr		*hwhdr_p;
+
+	hwhdr_p = (struct hf_hwhdr *)(skb->data);
+
+	/* MAC byte 1, bits6 = 1, locally admin MAC */
+	hwhdr_p->h_dest[0] = 0x2;
+	/* MAC byte 2, bits2-7 = cluster id */
+	hwhdr_p->h_dest[1] = 0x0;
+	*(u16 *)(&(hwhdr_p->h_dest[2])) = (u16)(b_hdr->dst_isr);
+	*(u16 *)(&(hwhdr_p->h_dest[4])) =
+			(u16)hf_get_mac(b_hdr->dst_win);
+
+	hwhdr_p->h_source[0] = 0x2;
+	hwhdr_p->h_source[1] = 0x0;
+	*(u16 *)(&(hwhdr_p->h_source[2])) = (u16)(b_hdr->src_isr);
+	*(u16 *)(&(hwhdr_p->h_source[4])) =
+				(u16)hf_get_mac(b_hdr->src_win);
+
+	hwhdr_p->h_proto = skb->protocol;
+}
+
+static inline int hf_check_hdr_version(struct hf_if *net_if,
+				struct hf_if_proto_hdr *hf_hdr)
+{
+	if (hf_hdr->version != HF_PROTO_HDR_VERSION) {
+		printk(KERN_ERR
+			"%s: hf_check_hdr_version: hdr version 0x%x "
+			"does not match 0x%x\n",
+			net_if->name, hf_hdr->version, HF_PROTO_HDR_VERSION);
+		net_if->net_stats.rx_dropped++;
+
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hf_recv_ip_with_payload(struct hf_net *net,
+				    struct hfi_ip_with_payload_pkt *pkt,
+				    u32 pkt_len)
+{
+	u32			len, resid;
+	struct hf_if		*net_if = &(net->hfif);
+	struct hf_if_proto_hdr	*hf_hdr;
+	struct sk_buff		*skb;
+	void			*src, *dst;
+	u32			cache_ln_num = 0;
+	u16			proto;
+
+	/* retrieve the protocol header pointer */
+	hf_hdr = (struct hf_if_proto_hdr *)(pkt->payload);
+
+	if (hf_check_hdr_version(net_if, hf_hdr) != 0)
+		return;
+
+	switch (hf_hdr->msg_type) {
+	case HF_IF_ARP:
+		proto = htons(ETH_P_ARP);
+		break;
+
+	case HF_IF_FIFO:
+		proto = htons(ETH_P_IP);
+		break;
+
+	default:
+		netdev_err(net->netdev,
+			"hf_recv_ip_with_payload: unknown msg_type 0x%x\n",
+			hf_hdr->msg_type);
+		net_if->net_stats.rx_dropped++;
+		return;
+	}
+
+	len = hf_hdr->msg_len - HF_PROTO_LEN;
+
+	skb = netdev_alloc_skb_ip_align(net->netdev,
+				len + HF_HLEN + HF_ALIGN_PAD);
+	if (!skb) {
+		netdev_err(net->netdev, "hf_recv_ip_with_payload: "
+				"netdev_alloc_skb_ip_align fail\n");
+		net_if->net_stats.rx_dropped++;
+		BUG();
+		return;
+	}
+
+	skb_reserve(skb, HF_ALIGN_PAD);
+	skb->protocol = proto;
+
+	skb_put(skb, len + HF_HLEN);
+
+	/* construct hf_hwhdr from base hdr */
+	hf_construct_hwhdr(net_if, skb, &(pkt->hfi_hdr.base_hdr));
+
+	skb_reset_mac_header(skb);
+
+	skb_pull(skb, HF_HLEN);
+
+	src = (void *)(hf_hdr + 1);
+	dst = (void *)skb->data;
+
+	/* check if the payload wrapped the rx_fifo */
+	if ((net_if->rx_fifo.head + (pkt_len - 1)) > net_if->rx_fifo.emax) {
+		/* Wrapped */
+		cache_ln_num = net_if->rx_fifo.emax - net_if->rx_fifo.head + 1;
+		resid  = cache_ln_num << HFI_CACHE_LINE_SHIFT;
+		resid -= (HF_IP_HDR_LEN + HF_PROTO_LEN);
+
+		/* For netboot, pkt_len maybe larger than len */
+		if (resid > len)
+			resid = len;
+
+		memcpy(dst, src, resid);
+
+		src = (void *)net_if->rx_fifo.addr;
+		dst = (void *)skb->data + resid;
+		len -= resid;
+	}
+
+	/* copy the rest of payload */
+	if (len > 0)
+		memcpy(dst, src, len);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	net_if->net_stats.rx_packets++;
+	net_if->net_stats.rx_bytes += skb->len;
+
+	netif_receive_skb(skb);
+}
+
+static void hf_recv_ip_good(struct hf_net *net,
+			    struct hfi_hdr *rx_curr,
+			    u32 pkt_len)
+{
+	struct hf_if	*net_if = &(net->hfif);
+
+	switch (rx_curr->type.header_type) {
+
+	case  HFI_IP_WITH_PAYLOAD:
+	case  HFI_IP_MULTICAST_WITH_PAYLOAD:
+		hf_recv_ip_with_payload(net,
+			(struct hfi_ip_with_payload_pkt *)rx_curr, pkt_len);
+		break;
+
+	default:
+		netdev_err(net->netdev, "hf_rx: receive unknown "
+			"headerType = 0x%x, pkt_len = 0x%x\n",
+			rx_curr->type.header_type, pkt_len);
+
+		/* unknown packet, drop it */
+		net_if->net_stats.rx_dropped++;
+		break;
+	}
+}
+
+static int hf_rx(struct hf_net *net, int budget)
+{
+	int		num = 0;
+	struct hf_if	*net_if = &(net->hfif);
+	u32		pkt_len, status;
+	struct hfi_hdr	*rx_curr;
+	u32		job_id, pkt_valid;
+
+	rx_curr = (struct hfi_hdr *) (net_if->rx_fifo.addr +
+			(net_if->rx_fifo.head << HFI_CACHE_LINE_SHIFT));
+
+	while (budget != 0) {
+		job_id = rx_curr->id.job_id;
+		pkt_valid = rx_curr->base_hdr.pkt_valid;
+
+		isync();
+		if ((job_id != HF_IP_JOBID) ||
+		    (pkt_valid != net_if->rx_pkt_valid))
+			break;
+
+		pkt_len = hfi_pktlen_to_cachelines(rx_curr->base_hdr.pkt_len);
+
+		status = rx_curr->base_hdr.status;
+		if (status == HFI_PKT_STATUS_GOOD) {
+			hf_recv_ip_good(net, rx_curr, pkt_len);
+		} else {
+			/* bad packet */
+			netdev_err(net->netdev, "hf_rx: receive bad "
+				"status = 0x%x, pkt_len = 0x%x\n",
+				status, pkt_len);
+
+			net_if->net_stats.rx_dropped++;
+		}
+
+		net->netdev->last_rx = jiffies;
+
+		hf_advance_rx_head(net_if, pkt_len);
+
+		/* Make sure the jobid is invalidated before posting to hw */
+		wmb();
+
+		net_if->rx_fslot_debt += pkt_len;
+		if (net_if->rx_fslot_debt >= HF_INC_FSLOT_WATERMARK) {
+			hf_mmio_regs_write(net_if, HFI_RFIFO_INC_FSLOT_REG,
+					net_if->rx_fslot_debt);
+			net_if->rx_fslot_debt = 0;
+		}
+
+		budget--;
+		num++;
+		rx_curr = net_if->rx_fifo.addr +
+			(net_if->rx_fifo.head << HFI_CACHE_LINE_SHIFT);
+
+	}
+
+	netdev_dbg(net->netdev, "hf_rx: exit, head = 0x%x, recv 0x%x pkts\n",
+			net_if->rx_fifo.head, num);
+
+	return num;
+}
+
 static void hf_tx_recycle(struct hf_if *net_if)
 {
 	u32		head, head_idx, slots_per_blk;
@@ -935,6 +1227,30 @@ static void hf_if_setup(struct net_device *netdev)
 	memcpy(netdev->broadcast, hfi_bcast_addr, HF_ALEN);
 }
 
+static int hf_poll(struct napi_struct *napi, int budget)
+{
+	int			work_done;
+	struct net_device	*netdev;
+	struct hf_net		*net;
+	struct hf_if		*net_if;
+
+	net	= container_of(napi, struct hf_net, napi);
+	net_if	= &(net->hfif);
+	netdev	= net->netdev;
+
+	work_done = hf_rx(net, budget);
+
+	/* Always assume we have received all available packets */
+	/*  and set recv intr for next packet */
+	if (work_done < budget) {
+		napi_complete(napi);
+		isync();
+		hf_set_recv_intr(net_if);
+	}
+
+	return work_done;
+}
+
 static struct hf_net *hf_init_netdev(int idx, int ai)
 {
 	struct net_device	*netdev;
@@ -953,6 +1269,7 @@ static struct hf_net *hf_init_netdev(int idx, int ai)
 	}
 
 	net = netdev_priv(netdev);
+	netif_napi_add(netdev, &(net->napi), hf_poll, HF_NAPI_WEIGHT);
 	net->netdev = netdev;
 
 	memset(&(net->hfif), 0, sizeof(struct hf_if));
@@ -968,11 +1285,16 @@ static struct hf_net *hf_init_netdev(int idx, int ai)
 		printk(KERN_ERR "hf_init_netdev: "
 				"failed to register netdev=hfi%d:hf%d, "
 				"rc = 0x%x\n", ai, idx, rc);
-		free_netdev(netdev);
-		return (struct hf_net *) -ENODEV;
+		goto err_out1;
 	}
 
 	return net;
+
+err_out1:
+	netif_napi_del(&(net->napi));
+	free_netdev(netdev);
+
+	return (struct hf_net *) -ENODEV;
 }
 
 static void hf_del_netdev(struct hf_net *net)
@@ -981,6 +1303,8 @@ static void hf_del_netdev(struct hf_net *net)
 
 	unregister_netdev(netdev);
 
+	netif_napi_del(&(net->napi));
+
 	free_netdev(netdev);
 }
 
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
index b7c6d3c..b70ecdd 100644
--- a/drivers/net/hfi/ip/hf_proto.h
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -34,6 +34,8 @@
 #define _HF_PROTO_H_
 
 int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls);
+void hf_construct_hwhdr(struct hf_if *net_if, struct sk_buff *skb,
+			struct base_hdr *b_hdr);
 extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
 		u32 is_userspace,
 		struct hfi_client_info *user_p,
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
index 90b6331..39bcdae 100644
--- a/include/linux/hfi/hf_if.h
+++ b/include/linux/hfi/hf_if.h
@@ -53,8 +53,15 @@
 #define MAX_HF_PER_HFI			2
 #define	HF_IP_JOBID			0xFFFFFFF0
 #define HF_TX_TIMEOUT			(500 * HZ)
+#define HF_NAPI_WEIGHT			256
 #define HF_MAX_NAME_LEN			64
 
+/* rfifo intr */
+#define HF_RFIFO_OUT_CNTL_REARM		0	/* 0 to disable interrupt */
+#define HF_IMM_RECV_INTR		0xf0000000	/* bit 32-35 on */
+#define HF_ENA_RECV_INTR		0xc0000000	/* bit 32-33 on */
+#define HF_RECV_INTR_MATCH_SHIFT	7	/* bit 37-56 */
+
 /* sfifo intr: bit 39-55 is threshold */
 /*             bit 34 enable, bit 35 unmask */
 #define HF_SFIFO_INTR_ENABLE		(0x3 << (63 - 35))
@@ -73,11 +80,17 @@
 #define HF_FV_BIT_MAX			31
 #define HF_SEND_ONE			1
 
+#define HF_RFIFO_CACHE_INJ_TH		7ULL
+#define HF_RFIFO_CACHE_INJ_TH_SHIFT	61
+#define HF_RFIFO_OUT_THRESH		0
+
 #define HF_PAYLOAD_MAX			(2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
 #define HF_NET_MTU			HF_PAYLOAD_MAX
 #define HF_PAYLOAD_RX_THRESHOLD		0x10ULL
 #define HF_PAYLOAD_RX_THRESH_SHIFT	59
 
+#define HF_INC_FSLOT_WATERMARK		(HF_RFIFO_SLOTS >> 3)
+
 struct hfi_ip_extended_hdr {            /* 16B */
 	u32		immediate_len:7;/* In bytes */
 	u32		num_desc:3;     /* number of descriptors */
@@ -98,6 +111,7 @@ struct hfi_ip_with_payload_pkt {
 
 #define HF_IP_HDR_LEN			((sizeof(struct hfi_hdr) + \
 				sizeof(struct hfi_ip_extended_hdr)))
+
 #define HF_ALEN				6
 struct hf_hwhdr {
 	u8				h_dest[HF_ALEN];
@@ -154,7 +168,10 @@ struct hf_if {
 	u32			sfifo_fv_polarity;
 	u32			sfifo_slots_per_blk;
 	u32			sfifo_packets;
+	u32			rx_pkt_valid;		/* Polarity of recv
+							   packet valid bit */
 	u32			msg_id;
+	u32			rx_fslot_debt;
 	void __iomem		*doorbell;		/* mapped mmio_regs */
 	struct hf_fifo		tx_fifo;
 	struct hf_fifo		rx_fifo;
@@ -168,6 +185,7 @@ struct hf_if {
 /* Private structure for HF inetrface */
 struct hf_net {
 	struct net_device	*netdev;
+	struct napi_struct	napi;
 	struct hf_if		hfif;
 };
 
@@ -181,7 +199,7 @@ struct hf_global_info {
 
 extern struct hf_global_info	hf_ginfo;
 
-#define HF_EVENT_NUM		1
+#define HF_EVENT_NUM		2
 
 struct hf_events_cb {
 	enum hfi_event_type	type;
@@ -191,6 +209,11 @@ struct hf_events_cb {
 #define HF_MAC_HFI_SHIFT	12
 #define HF_HDR_HFI_SHIFT	8
 
+static inline u32 hf_get_mac(u32 w)
+{
+	return ((w >> HF_HDR_HFI_SHIFT) << HF_MAC_HFI_SHIFT) | (w & 0xFF);
+}
+
 static inline u32 hf_get_win(u16 id)
 {
 	return ((id >> HF_MAC_HFI_SHIFT) << HF_HDR_HFI_SHIFT) | (id & 0xFF);
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 12/27] HFI:  Sanity check send and receive fifo parameters
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/Makefile       |    1 +
 drivers/net/hfi/core/hfidd_proto.h  |    3 +
 drivers/net/hfi/core/hfidd_window.c |  177 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_xlat.c   |  131 ++++++++++++++++++++++++++
 include/linux/hfi/hfidd_adpt.h      |   17 ++++
 5 files changed, 329 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_xlat.c

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 0224a57..8d5558d 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -4,5 +4,6 @@
 hfi_core-objs:=	hfidd_adpt.o \
 		hfidd_window.o \
 		hfidd_init.o \
+		hfidd_xlat.o \
 		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index e7f2901..66ea5da 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,6 +39,9 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
 void hfidd_free_windows(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 int hfidd_age_hcall(u64 time_start);
+int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr,
+		unsigned int is_userspace, unsigned int length,
+		unsigned long long *page_size);
 int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		struct hfi_client_info *user_p,
 		struct hfi_client_info *out_p);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index cc775e3..5a4f395 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -35,6 +35,153 @@
 #include "hfidd_proto.h"
 #include <linux/hfi/hfidd_requests.h>
 
+#define FINISH_VECTOR_LENGTH 1
+/* Validate send fifo parameters needed for open window */
+static int hfi_check_sfifo_parm(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int			rc = 0;
+	unsigned long long	page_sz;
+	unsigned long long	fv_page_sz;
+
+	/* Validate the sfifo size */
+	if ((client_p->sfifo.size < HFI_SFIFO_SIZE_MIN) ||
+	    (client_p->sfifo.size > HFI_SFIFO_SIZE_MAX)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: invalid sfifo "
+			"size = 0x%llx\n",
+			client_p->sfifo.size);
+		return -EINVAL;
+	}
+
+	/*
+	 * Validate the address of sfifo is 4k aligned, and finish vector
+	 * is cache-line aligned
+	 */
+	if ((client_p->sfifo.eaddr.use.allu) & PAGE_MASK_4K) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: not page aligned, "
+			"sfifo_addr = 0x%llx\n",
+			client_p->sfifo.eaddr.use.allu);
+		return -EINVAL;
+	}
+
+	if ((client_p->sfifo_finish_vec.use.allu) & HFI_CACHE_LINE_MASK) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: not cache aligned, "
+			"sfifo_finishvec = 0x%llx\n",
+			client_p->sfifo_finish_vec.use.allu);
+		return -EINVAL;
+	}
+	/*
+	 * Validate the send finish vector are within 4K bytes of end of sfifo
+	 */
+	if (((client_p->sfifo_finish_vec.use.kptr -
+	     (client_p->sfifo.eaddr.use.kptr +
+	      client_p->sfifo.size)) >= PAGE_SIZE_4K)) {
+
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: fv too far away, "
+			"sfifo_addr = 0x%llx\n",
+			client_p->sfifo.eaddr.use.allu);
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: fv too far away, "
+			"sfifo_finishvec = 0x%llx\n",
+			client_p->sfifo_finish_vec.use.allu);
+		return -EINVAL;
+	}
+
+	/* Validate page size of sFifo */
+	rc = hfidd_get_page_size(p_acs, client_p->sfifo.eaddr.use.kptr,
+			is_userspace, client_p->sfifo.size, &page_sz);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: fail in sfifo page size, "
+			"rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* Find out the page size of send finish vector */
+	rc = hfidd_get_page_size(p_acs, client_p->sfifo_finish_vec.use.kptr,
+			is_userspace, FINISH_VECTOR_LENGTH, &fv_page_sz);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: fail in fv page size, "
+			"rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* The page size of finish vector must be the same as sfifo */
+	if (page_sz != fv_page_sz) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_sfifo_parm: diff page sz sf=0x%llx, "
+			"fv0=0x%llx\n", page_sz, fv_page_sz);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int hfi_check_rfifo_parm(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int			rc = 0;
+	unsigned long long	page_sz;
+
+	/* Validate the rfifo size */
+	if ((client_p->rfifo.size < HFI_RFIFO_SIZE_MIN) ||
+	    (client_p->rfifo.size > HFI_RFIFO_SIZE_MAX)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_rfifo_parm: invalid rfifo size = 0x%llx\n",
+			client_p->rfifo.size);
+		return -EINVAL;
+	}
+
+	/* Validate the address of rfifo is 4K aligned */
+	if ((client_p->rfifo.eaddr.use.allu) & PAGE_MASK_4K) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_rfifo_parm: not cache aligned, "
+			"rfifo_addr = 0x%llx\n",
+			client_p->rfifo.eaddr.use.allu);
+		return -EINVAL;
+	}
+
+	/* Validate page size of rFifo */
+	rc = hfidd_get_page_size(p_acs, client_p->rfifo.eaddr.use.kptr,
+			is_userspace, client_p->rfifo.size, &page_sz);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_check_rfifo_parm: fail in rfifo page size, "
+			"rc=0x%x\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+/* Validate window parameters to setup the fifos and RDMA function */
+static int hfi_validate_window_request(struct hfidd_acs *p_acs,
+	unsigned int is_userspace, struct hfi_client_info *client_p)
+{
+	int			rc = 0;
+	struct hfidd_window	*win_p;
+
+	/* Check every input parameters..... */
+	win_p = hfi_window(p_acs, client_p->window);
+
+	/* Check the request of sFifo */
+	rc = hfi_check_sfifo_parm(p_acs, is_userspace, win_p, client_p);
+	if (rc)
+		return rc;
+	/* Check the request of rFifo */
+	rc = hfi_check_rfifo_parm(p_acs, is_userspace, win_p, client_p);
+	if (rc)
+		return rc;
+	return rc;
+}
+
 /* Validate the type, state and job id for RESERVED window */
 static int hfi_validate_reserve_window_id(struct hfidd_acs *p_acs,
 		struct hfi_client_info *client_p)
@@ -164,12 +311,29 @@ static inline int hfi_validate_window_id(struct hfidd_acs *p_acs,
 	return rc;
 }
 
+static inline void hfi_restore_window_parm(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p)
+{
+	if (win_p->type != HFIDD_RESERVE_WIN) {
+		win_p->type   = HFIDD_DYNAMIC_WIN;
+		win_p->job_id = 0;
+		if (win_p->state != WIN_HERROR)
+			win_p->state = WIN_AVAILABLE;
+	} else {
+		if (win_p->state != WIN_HERROR)
+			win_p->state = WIN_RESERVED;
+	}
+	win_p->pid   = 0;
+	win_p->is_ip = 0;
+}
+
 /* Validate window number and type for open window request */
 static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 		unsigned int is_userspace,
 		struct hfi_client_info *client_p)
 {
 	int			rc = 0;
+	struct hfidd_window	*win_p;
 
 	/* Validate the window number */
 	rc = hfi_validate_window_id(p_acs, client_p, is_userspace);
@@ -179,6 +343,19 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 			"failed, rc = 0x%x\n", rc);
 		return rc;
 	}
+
+	rc = hfi_validate_window_request(p_acs, is_userspace, client_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_validate_window_parm: "
+			"hfi_validate_window_request failed, rc = 0x%x\n", rc);
+		win_p = hfi_window(p_acs, client_p->window);
+		spin_lock(&(win_p->win_lock));
+		hfi_restore_window_parm(p_acs, win_p);
+		spin_unlock(&(win_p->win_lock));
+		return rc;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/hfi/core/hfidd_xlat.c b/drivers/net/hfi/core/hfidd_xlat.c
new file mode 100644
index 0000000..23236cc
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_xlat.c
@@ -0,0 +1,131 @@
+/*
+ * hfidd_xlat.c
+ *
+ * HFI device driver for IBM System p
+ *
+ *  Authors:
+ *      Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *      William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *      Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *      Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *      Jian Xiao <jian@linux.vnet.ibm.com>
+ *      Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *      Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <asm/page.h>
+
+#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
+
+int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr,
+	unsigned int is_userspace,
+	unsigned int length,
+	unsigned long long *page_size)
+{
+	int			rc = 0;
+	int			i;
+	int			num_pages;
+	struct page		**page_list;
+	struct vm_area_struct	**vma_list;
+	unsigned long long	offset;
+
+	if (!is_userspace) {
+		*page_size = PAGE_SIZE;
+		return 0;
+	}
+
+	offset = (unsigned long long)addr & ~PAGE_MASK;
+	num_pages = PAGE_ALIGN(length + offset) >> PAGE_SHIFT;
+
+	page_list = kzalloc(num_pages * sizeof(struct page *),
+			GFP_KERNEL);
+	if (page_list == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_size: kzalloc failed for page_list\n");
+		return -ENOMEM;
+	}
+
+	vma_list = kzalloc(num_pages * sizeof(struct vm_area_struct **),
+			GFP_KERNEL);
+	if (vma_list == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_size: kzalloc failed for vma_list\n");
+		rc = -ENOMEM;
+		goto out1;
+	}
+
+	down_read(&current->mm->mmap_sem);
+	rc = get_user_pages(current, current->mm,
+			(unsigned long long)addr,
+			num_pages, 1, 0,	/* yes write, no force */
+			page_list, vma_list);
+	up_read(&current->mm->mmap_sem);
+
+	if (rc < num_pages) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_size: get_user_pages failed rc = %d "
+			"and numpages %d\n", rc, num_pages);
+		if (rc < 0)
+			goto out2;
+		num_pages = rc;
+		rc = -ENOMEM;
+		goto out3;
+	}
+
+	rc = 0;
+	*page_size = PAGE_SIZE;
+	for (i = 0; i < num_pages; i++) {
+		/* check for huge pages */
+		if (is_vm_hugetlb_page(vma_list[i])) {
+			/* Find huge page size */
+			*page_size = huge_page_size(hstate_vma(vma_list[i]));
+			break;
+		}
+	}
+
+	/* If memory has huge page size, check if all pages are huge pages */
+	if (*page_size != PAGE_SIZE) {
+		for (i = 0; i < num_pages; i++) {
+			/* if not huge page, set to PAGE_SIZE */
+			if (!is_vm_hugetlb_page(vma_list[i])) {
+				*page_size = PAGE_SIZE;
+				break;
+			}
+		}
+	}
+	if (*page_size == PAGE_SIZE_16G) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_size: Large page size "
+			"0x%llx use 4G\n", *page_size);
+		*page_size = PAGE_SIZE_4G;
+	}
+
+out3:
+	for (i = 0; i < num_pages; i++)
+		page_cache_release(page_list[i]);
+out2:
+	kfree(vma_list);
+out1:
+	kfree(page_list);
+	return rc;
+}
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index babdb14..a41825f 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -36,6 +36,16 @@
 #include <linux/hfi/hfidd_client.h>
 
 
+#define HFI_SFIFO_SIZE_MIN	0x10000		/* min =  64K software limit */
+#define HFI_SFIFO_SIZE_MAX	0x800000	/* max =  8M */
+
+#define HFI_RFIFO_SIZE_MIN	0x1000		/* min =  4K */
+#define HFI_RFIFO_SIZE_MAX	0x8000000	/* max =  128M */
+
+#define HFI_CACHE_LINE_SIZE	0x80
+#define HFI_CACHE_LINE_MASK	(HFI_CACHE_LINE_SIZE - 1)
+#define HFI_CACHE_LINE_SHIFT	7
+
 #define HFI_WNUM_SHIFT		32
 #define HFI_CAUNUM_SHIFT	32
 #define HFI_SHIFT_OCTANT	3
@@ -57,4 +67,11 @@
 #define WIN_PENDING		6
 #define WIN_FAIL_CLOSE		7
 
+#define PAGE_MASK_4K		(PAGE_SIZE_4K - 1)
+#define PAGE_MASK_64K		(PAGE_SIZE_64K - 1)
+#define PAGE_MASK_1M		(PAGE_SIZE_1M - 1)
+#define PAGE_MASK_16M		(PAGE_SIZE_16M - 1)
+#define PAGE_MASK_4G		(PAGE_SIZE_4G - 1)
+#define PAGE_MASK_16G		(PAGE_SIZE_16G - 1)
+
 #endif /* _HFIDD_ADPT_H_ */
-- 
1.7.3.1


^ permalink raw reply related

* [PATCH 27/27] HFI: hf ethtool support
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
  To: netdev, netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/ip/Makefile     |    2 +-
 drivers/net/hfi/ip/hf_ethtool.c |  136 +++++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/ip/hf_if_main.c |   34 +++++++++-
 drivers/net/hfi/ip/hf_proto.h   |    1 +
 include/linux/hfi/hf_if.h       |   32 +++++++++
 5 files changed, 200 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/hfi/ip/hf_ethtool.c

diff --git a/drivers/net/hfi/ip/Makefile b/drivers/net/hfi/ip/Makefile
index 59eff9b..2909b00 100644
--- a/drivers/net/hfi/ip/Makefile
+++ b/drivers/net/hfi/ip/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_HFI_IP) += hf_if.o
 
-hf_if-objs :=	hf_if_main.o
+hf_if-objs :=	hf_if_main.o hf_ethtool.o
diff --git a/drivers/net/hfi/ip/hf_ethtool.c b/drivers/net/hfi/ip/hf_ethtool.c
new file mode 100644
index 0000000..8fd48d0
--- /dev/null
+++ b/drivers/net/hfi/ip/hf_ethtool.c
@@ -0,0 +1,136 @@
+/*
+ * hf_ethtool.c
+ *
+ * HF IP driver for IBM System p
+ *
+ *  Authors:
+ *	Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ *	William S. Cadden <wscadden@linux.vnet.ibm.com>
+ *	Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ *	Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ *	Jian Xiao <jian@linux.vnet.ibm.com>
+ *	Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ *	Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ *  (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/ethtool.h>
+
+#include <linux/hfi/hf_if.h>
+
+static char hf_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+	{"sfifo_packets"},
+	{"rdma_packets"},
+	{"tx_timeout"},
+	{"tx_queue_stop"},
+	{"tx_drop"},
+	{"tx_err_headlen"},
+	{"rx_version_mismatch"},
+	{"rx_err_restore"},
+	{"rx_err_cookie"},
+	{"rx_err_skb"},
+	{"rx_err_hdr_type"},
+	{"rx_err_msg_type"},
+	{"rx_err_status"},
+	{"rx_err_bcast_csum"},
+	{"rx_fslot_debt"},
+	{"mmio_rx_inc_avail"},
+	{"mmio_rx_post_desc"},
+	{"payload_sent"},
+	{"desc_sent"},
+	{"large_bcast_sent"},
+	{"super_sent"},
+	{"payload_recv"},
+	{"desc_recv"},
+	{"rdma_write"},
+	{"rdma_write_fail"},
+	{"rdma_cancel"},
+	{"rdma_cancel_fail"},
+	{"rdma_cancel_already"},
+	{"rdma_rndz_request_sent"},
+	{"rdma_rndz_request_fail"},
+	{"rdma_rndz_reply_recv"},
+	{"rdma_rndz_reply_fail"},
+	{"rdma_rndz_request_recv"},
+	{"rdma_rndz_reply_sent"},
+	{"bad_rdma_notification"},
+	{"bad_rdma_first_notification"},
+	{"rdma_src_completion"},
+	{"rdma_sink_completion"},
+	{"rdma_send_timeout"},
+	{"rdma_recv_timeout"},
+	{"sfifo_send_intr_armed"},
+	{"rdma_send_intr_armed"},
+	{"recv_intr_armed"},
+	{"recv_intr_offset"},
+	{"recv_imm_intr_armed"},
+	{"recv_imm_intr_offset"},
+	{"send_intr_fired"},
+	{"recv_intr_fired"},
+	{"in_poll"},
+	{"max_poll_recv"},
+};
+
+static void hf_get_drvinfo(struct net_device *netdev,
+		struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, HF_DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, HF_DRV_VERSION, sizeof(info->version));
+}
+
+static void hf_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(data, &hf_ethtool_stats_keys,
+				sizeof(hf_ethtool_stats_keys));
+		break;
+	}
+}
+
+static int hf_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(hf_ethtool_stats_keys);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void hf_get_ethtool_stats(struct net_device *netdev,
+		struct ethtool_stats *stats, u64 *data)
+{
+	struct hf_net	*net = netdev_priv(netdev);
+	struct hf_if	*net_if = &(net->hfif);
+
+	memcpy(data, &(net_if->eth_stats), sizeof(struct hf_ethtool_stats));
+}
+
+static const struct ethtool_ops hf_ethtool_ops = {
+	.get_drvinfo		= hf_get_drvinfo,
+	.get_strings		= hf_get_strings,
+	.get_sset_count		= hf_get_sset_count,
+	.get_ethtool_stats	= hf_get_ethtool_stats,
+};
+
+void hf_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &hf_ethtool_ops);
+}
diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
index 10dc1da..e45b48f 100644
--- a/drivers/net/hfi/ip/hf_if_main.c
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -231,6 +231,7 @@ static int hf_send_intr_callback(void *parm, u32 win, u32 ext)
 	mb();
 
 	netif_wake_queue(net->netdev);
+	net->hfif.eth_stats.send_intr_fired++;
 
 	return 0;
 }
@@ -241,6 +242,7 @@ static int hf_recv_intr_callback(void *parm, u32 win, u32 ext)
 
 	napi_schedule(&(net->napi));
 
+	net->hfif.eth_stats.recv_intr_fired++;
 	return 0;
 }
 
@@ -400,6 +402,9 @@ static void hf_set_recv_intr(struct hf_if *net_if)
 	hf_mmio_regs_write_then_read(net_if, HFI_RFIFO_INTR_REG,
 		(HF_ENA_RECV_INTR + (offset << HF_RECV_INTR_MATCH_SHIFT)));
 
+	net_if->eth_stats.recv_intr_offset = offset;
+	net_if->eth_stats.recv_intr_armed++;
+
 	/* check if there is packet received in the mean time */
 	rx_pkt = net_if->rx_fifo.addr + (offset << HFI_CACHE_LINE_SHIFT);
 
@@ -409,6 +414,9 @@ static void hf_set_recv_intr(struct hf_if *net_if)
 		/* force an immediate recv intr */
 		hf_mmio_regs_write(net_if, HFI_RFIFO_INTR_REG,
 		(HF_IMM_RECV_INTR + (offset << HF_RECV_INTR_MATCH_SHIFT)));
+
+		net_if->eth_stats.recv_imm_intr_offset = offset;
+		net_if->eth_stats.recv_imm_intr_armed++;
 	}
 }
 
@@ -527,7 +535,7 @@ static int hf_net_open(struct net_device *netdev)
 	struct hfidd_acs	*p_acs = HF_ACS(net_if);
 
 	memset(&(net_if->net_stats), 0, sizeof(struct net_device_stats));
-	net_if->sfifo_packets = 0;
+	memset(&(net_if->eth_stats), 0, sizeof(struct hf_ethtool_stats));
 
 	spin_lock(&(net_if->lock));
 	net_if->state = HF_NET_HALF_OPEN;
@@ -637,6 +645,7 @@ static inline int hf_check_hdr_version(struct hf_if *net_if,
 			"%s: hf_check_hdr_version: hdr version 0x%x "
 			"does not match 0x%x\n",
 			net_if->name, hf_hdr->version, HF_PROTO_HDR_VERSION);
+		net_if->eth_stats.rx_version_mismatch++;
 		net_if->net_stats.rx_dropped++;
 
 		return -EINVAL;
@@ -733,6 +742,7 @@ static void hf_recv_ip_with_payload(struct hf_net *net,
 	net_if->net_stats.rx_packets++;
 	net_if->net_stats.rx_bytes += skb->len;
 
+	net_if->eth_stats.payload_recv++;
 	netif_receive_skb(skb);
 }
 
@@ -756,6 +766,7 @@ static void hf_recv_ip_good(struct hf_net *net,
 			rx_curr->type.header_type, pkt_len);
 
 		/* unknown packet, drop it */
+		net_if->eth_stats.rx_err_hdr_type++;
 		net_if->net_stats.rx_dropped++;
 		break;
 	}
@@ -792,6 +803,7 @@ static int hf_rx(struct hf_net *net, int budget)
 				"status = 0x%x, pkt_len = 0x%x\n",
 				status, pkt_len);
 
+			net_if->eth_stats.rx_err_status++;
 			net_if->net_stats.rx_dropped++;
 		}
 
@@ -807,6 +819,7 @@ static int hf_rx(struct hf_net *net, int budget)
 			hf_mmio_regs_write(net_if, HFI_RFIFO_INC_FSLOT_REG,
 					net_if->rx_fslot_debt);
 			net_if->rx_fslot_debt = 0;
+			net_if->eth_stats.mmio_rx_inc_avail++;
 		}
 
 		budget--;
@@ -816,6 +829,7 @@ static int hf_rx(struct hf_net *net, int budget)
 
 	}
 
+	net_if->eth_stats.rx_fslot_debt = net_if->rx_fslot_debt;
 	netdev_dbg(net->netdev, "hf_rx: exit, head = 0x%x, recv 0x%x pkts\n",
 			net_if->rx_fifo.head, num);
 
@@ -885,9 +899,10 @@ int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls)
 			u64		intr_thresh;
 
 			netif_stop_queue(netdev);
+			net_if->eth_stats.tx_queue_stop++;
 
 			/* turn on transmit interrupt */
-			intr_thresh = (net_if->sfifo_packets -
+			intr_thresh = (net_if->eth_stats.sfifo_packets -
 			HF_SFIFO_INTR_WATERMARK) & HF_SFIFO_INTR_MASK;
 
 			intr_cntl = HF_SFIFO_INTR_ENABLE |
@@ -896,6 +911,7 @@ int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls)
 			hf_mmio_regs_write_then_read(net_if,
 					HFI_SFIFO_INTR_CNTL, intr_cntl);
 
+			net_if->eth_stats.sfifo_send_intr_armed++;
 			return -EBUSY;
 		}
 	}
@@ -978,6 +994,7 @@ static char *hf_build_payload_hdr(struct hf_net *net,
 			" not supported\n", hwhdr_p->h_proto);
 
 		dev_kfree_skb_any(skb);
+		net_if->eth_stats.tx_drop++;
 		return NULL;
 	}
 
@@ -1072,7 +1089,8 @@ static int hf_payload_tx(struct sk_buff *skb, struct hf_net *net, u32 is_bcast)
 		(net_if->tx_fifo.tail + xmit_cls) & (net_if->tx_fifo.emax);
 	atomic_sub(xmit_cls, &(net_if->tx_fifo.avail));
 
-	net_if->sfifo_packets++;
+	net_if->eth_stats.sfifo_packets++;
+	net_if->eth_stats.payload_sent++;
 	net_if->net_stats.tx_packets++;
 	net_if->net_stats.tx_bytes += msg_len;
 
@@ -1100,6 +1118,7 @@ static int hf_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 		netdev_err(netdev, "hf_start_xmit: invalid skb->len 0x%x\n",
 						skb->len);
 		dev_kfree_skb_any(skb);
+		net_if->eth_stats.tx_drop++;
 		return NETDEV_TX_OK;
 	}
 
@@ -1140,8 +1159,12 @@ static int hf_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 static void hf_tx_timeout(struct net_device *netdev)
 {
+	struct hf_net	*net = netdev_priv(netdev);
+	struct hf_if	*net_if = &(net->hfif);
+
 	netdev_warn(netdev, "hf_tx_timeout: queue_stopped is %d\n",
 			netif_queue_stopped(netdev));
+	net_if->eth_stats.tx_timeout++;
 }
 
 struct net_device_stats *hf_get_stats(struct net_device *netdev)
@@ -1238,6 +1261,7 @@ static int hf_poll(struct napi_struct *napi, int budget)
 	net_if	= &(net->hfif);
 	netdev	= net->netdev;
 
+	net_if->eth_stats.in_poll++;
 	work_done = hf_rx(net, budget);
 
 	/* Always assume we have received all available packets */
@@ -1246,7 +1270,8 @@ static int hf_poll(struct napi_struct *napi, int budget)
 		napi_complete(napi);
 		isync();
 		hf_set_recv_intr(net_if);
-	}
+	} else
+		net_if->eth_stats.max_poll_recv++;
 
 	return work_done;
 }
@@ -1279,6 +1304,7 @@ static struct hf_net *hf_init_netdev(int idx, int ai)
 	net->hfif.state = HF_NET_CLOSE;
 
 	spin_lock_init(&net->hfif.lock);
+	hf_set_ethtool_ops(netdev);
 
 	rc = register_netdev(netdev);
 	if (rc) {
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
index b70ecdd..6f53959 100644
--- a/drivers/net/hfi/ip/hf_proto.h
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -36,6 +36,7 @@
 int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls);
 void hf_construct_hwhdr(struct hf_if *net_if, struct sk_buff *skb,
 			struct base_hdr *b_hdr);
+void hf_set_ethtool_ops(struct net_device *netdev);
 extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
 		u32 is_userspace,
 		struct hfi_client_info *user_p,
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
index 39bcdae..85aa90f 100644
--- a/include/linux/hfi/hf_if.h
+++ b/include/linux/hfi/hf_if.h
@@ -38,9 +38,11 @@
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
 #include <net/arp.h>
 
 #include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_adpt.h>
 #include <linux/hfi/hfidd_client.h>
 #include <linux/hfi/hfidd_requests.h>
 #include <linux/hfi/hfidd_regs.h>
@@ -157,6 +159,35 @@ struct hf_fifo {
 #define	HF_NET_HALF_OPEN	0xA0
 #define	HF_NET_OPEN		0xA1
 
+struct hf_ethtool_stats {
+	u64		sfifo_packets;	/* total packets send through sfifo */
+	u64		tx_timeout;
+	u64		tx_queue_stop;
+	u64		tx_drop;
+	u64		tx_err_headlen;
+	u64		rx_version_mismatch;
+	u64		rx_err_skb;
+	u64		rx_err_hdr_type;
+	u64		rx_err_msg_type;
+	u64		rx_err_status;
+	u64		rx_err_bcast_csum;
+	u64		rx_fslot_debt;
+	u64		mmio_rx_inc_avail;
+	u64		payload_sent;	/* packets from IP send with payload
+					   mode */
+	u64		payload_recv;	/* packets delivered to IP with payload
+					   mode */
+	u64		sfifo_send_intr_armed;
+	u64		recv_intr_armed;
+	u64		recv_intr_offset;
+	u64		recv_imm_intr_armed;
+	u64		recv_imm_intr_offset;
+	u64		send_intr_fired;
+	u64		recv_intr_fired;
+	u64		in_poll;
+	u64		max_poll_recv;
+};
+
 struct hf_if {
 	u32			idx;			/* 0, 1, 2, 3 ...   */
 	u32			ai;			/* 0=hfi0, 1=hfi1   */
@@ -180,6 +211,7 @@ struct hf_if {
 							   2k skb */
 	void			*sfifo_finishvec;
 	struct net_device_stats	net_stats;
+	struct hf_ethtool_stats eth_stats;
 };
 
 /* Private structure for HF inetrface */
-- 
1.7.3.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox