* 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, ®_events);
+ else
+ rc = hfidd_callback_unregister(p_acs, ®_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(¤t->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(¤t->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(¤t->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(¤t->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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox