All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/27] HFI: skeleton driver
@ 2011-03-02 21:09 dykmanj
  2011-03-02 21:09 ` [PATCH 02/27] HFI: Add HFI adapter control structure dykmanj
                   ` (26 more replies)
  0 siblings, 27 replies; 38+ messages in thread
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	[flat|nested] 38+ messages in thread

* [PATCH 02/27] HFI: Add HFI adapter control structure
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 22:21   ` Stephen Hemminger
  2011-03-02 21:09 ` [PATCH 03/27] HFI: Add device_create/device_destroy calls for HFI devices dykmanj
                   ` (25 subsequent siblings)
  26 siblings, 1 reply; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 03/27] HFI:  Add device_create/device_destroy calls for HFI devices.
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
  2011-03-02 21:09 ` [PATCH 02/27] HFI: Add HFI adapter control structure dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 04/27] HFI: Find HFI devices in the device tree dykmanj
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 04/27] HFI: Find HFI devices in the device tree
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
  2011-03-02 21:09 ` [PATCH 02/27] HFI: Add HFI adapter control structure dykmanj
  2011-03-02 21:09 ` [PATCH 03/27] HFI: Add device_create/device_destroy calls for HFI devices dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls dykmanj
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (2 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 04/27] HFI: Find HFI devices in the device tree dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs dykmanj
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (3 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls dykmanj
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (4 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 08/27] HFI: DD request framework and first HFI DD request dykmanj
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 08/27] HFI: DD request framework and first HFI DD request
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (5 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 09/27] HFI: Add HFI window resource tracking dykmanj
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

We use an ioctl-ish mechanism similar to the one found in the HEA driver.
Some of our requests have very large parameter lists, this method allows
us to get the parms into the DD quickly.

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  |   94 +++++++++++++++++++++++++++++++++++-
 include/linux/hfi/Kbuild           |    1 +
 include/linux/hfi/hfidd_client.h   |   40 +++++++++++++++
 include/linux/hfi/hfidd_internal.h |   23 ++++++++-
 include/linux/hfi/hfidd_requests.h |   38 ++++++++++++++
 5 files changed, 192 insertions(+), 4 deletions(-)
 create mode 100644 include/linux/hfi/hfidd_requests.h

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 448349d..a57f247 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -37,6 +37,7 @@
 #include <linux/of.h>
 
 #include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_requests.h>
 #include "hfidd_proto.h"
 
 MODULE_VERSION("1.0");
@@ -60,11 +61,102 @@ static ssize_t hfidd_read(struct file *filep, char *buf, size_t count,
 	return 0;
 }
 
+/* Query firmare level and use abi version to users */
+static int hfidd_query_dd_info(struct hfidd_acs *p_acs,
+			struct hfi_query_dd_info *user_p)
+{
+	struct hfi_query_dd_info req;
+	int rc;
+
+	req.fw_ec_level = p_acs->dds.fw_ec_level;
+	req.abi_version = HFIDD_USER_ABI_VERSION;
+
+	rc = copy_to_user(user_p, &req, sizeof(struct hfi_query_dd_info));
+	if (rc)
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_query_dd_info: copy_to_user failed\n");
+
+	return rc;
+}
+
 /* 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;
+	struct hfidd_acs	*p_acs;
+	int			ai;
+	int			cnt = 0;
+	int			rc = 0;
+	struct hfi_req_hdr	cmd;
+	int			is_userspace;
+
+	ai = iminor(filep->f_path.dentry->d_inode);
+	if (ai >= MAX_HFIS) {
+		printk(KERN_ERR "%s: hfidd_cmd_write: wrong ai = %d\n",
+				HFIDD_DEV_NAME, ai);
+		return -ENODEV;
+	}
+
+	p_acs = hfidd_global.p_acs[ai];
+	if (p_acs == NULL) {
+		printk(KERN_ERR "%s: hfidd_cmd_write: p_acs is NULL\n",
+				HFIDD_DEV_NAME);
+		return -EINVAL;
+	}
+
+	if (count < sizeof(cmd)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_cmd_write: Invalid count: 0x%lx expected "
+			"count: 0x%lx\n", count, sizeof(cmd));
+		return -EINVAL;
+	}
+
+	is_userspace = 1;
+	if (segment_eq(get_fs(), KERNEL_DS))
+		is_userspace = 0;
+
+	if (copy_from_user(&cmd, buf, sizeof(cmd))) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_cmd_write: copy_from_user failed\n");
+		return -EINVAL;
+	}
+
+	if (cmd.abi_version != HFIDD_USER_ABI_VERSION) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_cmd_write: wrong abi_version %d, "
+			"should be %d for cmd 0x%x\n",
+			cmd.abi_version, HFIDD_USER_ABI_VERSION, cmd.req);
+		return -EINVAL;
+	}
+
+	switch (cmd.req) {
+	case HFIDD_REQ_QUERY_DD_INFO:
+		if (cmd.req_len != sizeof(struct hfi_query_dd_info)) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_cmd_write: hdr.reqlen 0x%x expected "
+				"0x%x for cmd req 0x%x\n",
+				cmd.req_len, (unsigned int)
+				sizeof(struct hfi_query_dd_info), cmd.req);
+			return -EINVAL;
+		}
+		rc = hfidd_query_dd_info(p_acs, (struct hfi_query_dd_info *)
+			cmd.result.use.kptr);
+		break;
+
+	default:
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_cmd_write: invalid cmd = 0x%x\n", cmd.req);
+		return -EINVAL;
+	}
+
+	if (rc == 0)
+		cnt = count;
+	else
+		cnt = rc;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_cmd_write: Exit cmd = 0x%x rc = 0x%x\n", cmd.req, rc);
+	return cnt;
 }
 
 static const struct file_operations hfidd_fops = {
diff --git a/include/linux/hfi/Kbuild b/include/linux/hfi/Kbuild
index 3a742ce..6637c65 100644
--- a/include/linux/hfi/Kbuild
+++ b/include/linux/hfi/Kbuild
@@ -1 +1,2 @@
 header-y += hfidd_client.h
+header-y += hfidd_requests.h
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 2714a27..b2ebd01 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -33,11 +33,51 @@
 #ifndef _HFIDD_CLIENT_H_
 #define _HFIDD_CLIENT_H_
 
+
+#define HFIDD_USER_ABI_VERSION  1
+
+
+/*
+ * New ioctls are not allowed.  We will use write() calls to pass
+ * in an ioctl-looking request, with struct hfi_req_hdr giving the
+ * information we used to get from the ioctl() parameter list.  The
+ * write() call will copy out the request structure to the buffer pointed
+ * to by result, which is probably the original request.
+ */
+
+struct hfi_64b {
+	union {
+		unsigned long long	allu;	/* APPLICATION Long long
+						   Unsigned 64 bit address
+						   container */
+		void			*kptr;	/* KERNEL Pointer 64 bit
+						   container */
+	} use;
+};
+
+/* Request header: first structure in each of the HFI DD requests */
+struct hfi_req_hdr {
+	unsigned int	req;			/* HFIDD_REQ_* */
+	unsigned int	req_len;		/* length of req, in bytes */
+	unsigned int	abi_version;		/* ABI version */
+	struct hfi_64b	result;			/* user eaddr for output */
+};
+#define HFIDD_REQ_HDR_SIZE			sizeof(struct hfi_req_hdr)
+
 #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
 
+/*
+ * HFIDD_REQ_QUERY_DD_INFO
+ */
+struct hfi_query_dd_info {
+	struct hfi_req_hdr	hdr;
+	unsigned long long	fw_ec_level;	/* Hardware Version */
+	unsigned int	abi_version;	/* ABI Version */
+};
+
 #define HFI_DYN_WINS_DEFAULT	32
 
 #define PAGE_SIZE_4K		0x1000
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 8fe313d..311f906 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -36,12 +36,29 @@
 #include <linux/fs.h>
 #include <linux/kobject.h>
 #include <linux/cdev.h>
+#include <linux/compat.h>
+#include <linux/compiler.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/poll.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/device.h>
-
+#include <linux/vermagic.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <asm/cputable.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <linux/mmu_context.h>
+#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>
diff --git a/include/linux/hfi/hfidd_requests.h b/include/linux/hfi/hfidd_requests.h
new file mode 100644
index 0000000..b6e255f
--- /dev/null
+++ b/include/linux/hfi/hfidd_requests.h
@@ -0,0 +1,38 @@
+/*
+ * hfidd_requests.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_REQUESTS_H_
+#define _HFIDD_REQUESTS_H_
+
+#define HFIDD_REQ_QUERY_DD_INFO			0x00001004
+
+#endif /* _HFIDD_REQUESTS_H_ */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/27] HFI: Add HFI window resource tracking
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (6 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 08/27] HFI: DD request framework and first HFI DD request dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request dykmanj
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (7 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 09/27] HFI: Add HFI window resource tracking dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 11/27] HFI: Check window number/assign window number dykmanj
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 11/27] HFI: Check window number/assign window number
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (8 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 12/27] HFI: Sanity check send and receive fifo parameters dykmanj
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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	[flat|nested] 38+ messages in thread

* [PATCH 12/27] HFI:  Sanity check send and receive fifo parameters
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (9 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 11/27] HFI: Check window number/assign window number dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:09 ` [PATCH 13/27] HFI: Send and receive fifo address translation dykmanj
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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

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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 13/27] HFI: Send and receive fifo address translation
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (10 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 12/27] HFI: Sanity check send and receive fifo parameters dykmanj
@ 2011-03-02 21:09 ` dykmanj
  2011-03-02 21:10 ` [PATCH 14/27] HFI: Add hypercalls to create/modify/free page tables in the nMMU dykmanj
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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>

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

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

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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 14/27] HFI: Add hypercalls to create/modify/free page tables in the nMMU
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (11 preceding siblings ...)
  2011-03-02 21:09 ` [PATCH 13/27] HFI: Send and receive fifo address translation dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 15/27] HFI: Set up nMMU page tables for the send and receive fifos dykmanj
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 15/27] HFI: Set up nMMU page tables for the send and receive fifos
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (12 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 14/27] HFI: Add hypercalls to create/modify/free page tables in the nMMU dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 16/27] HFI: Add window open hypervisor call dykmanj
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 16/27] HFI: Add window open hypervisor call
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (13 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 15/27] HFI: Set up nMMU page tables for the send and receive fifos dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 17/27] HFI: Set up and call the open window hypercall dykmanj
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 17/27] HFI: Set up and call the open window hypercall
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (14 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 16/27] HFI: Add window open hypervisor call dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 18/27] HFI: Map window registers into user process dykmanj
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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_window.c |  180 +++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_hcalls.h    |    2 +
 2 files changed, 182 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 6d90af6..3a9fea9 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,106 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+/*
+ * Setup a page for phyp with the window parameters needed for
+ * OPEN WINDOW hcall
+ */
+int hfi_build_window_info(struct hfidd_acs *p_acs, struct hfidd_window *win_p)
+{
+	caddr_t		laddr;
+
+#define WIN_INFO	(win_p->win_open_info_p)
+#define CLIENT_INFO	(win_p->client_info)
+
+	/* OPEN WINDOW hcall requires a page to pass arguments */
+	win_p->win_open_info_p = (struct win_open_info *)
+			__get_free_pages(GFP_KERNEL, get_order(PAGE_SIZE_4K));
+	if (win_p->win_open_info_p == NULL) {
+
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_build_window_info: ___get_free_pages failed\n");
+		return -ENOMEM;
+	}
+	memset((void *)(win_p->win_open_info_p), 0, PAGE_SIZE_4K);
+
+	/* Translate virtual adress into logical addres */
+	laddr = (caddr_t)__pa((caddr_t)win_p->win_open_info_p);
+
+	win_p->win_open_info_laddr = laddr;
+	WIN_INFO->job_id = CLIENT_INFO.job_id;
+	WIN_INFO->protection_domain = win_p->job_id;
+
+	WIN_INFO->sfifo_base_eaddr = CLIENT_INFO.sfifo.eaddr.use.allu;
+	WIN_INFO->sfifo_lkey       = win_p->sfifo_x_tab->l_key;
+	WIN_INFO->sfifo_size       = CLIENT_INFO.sfifo.size;
+	WIN_INFO->sfifo_finish_vec = CLIENT_INFO.sfifo_finish_vec.use.allu;
+
+	WIN_INFO->rfifo_base_eaddr = CLIENT_INFO.rfifo.eaddr.use.allu;
+	WIN_INFO->rfifo_lkey       = win_p->rfifo_x_tab->l_key;
+	WIN_INFO->rfifo_size       = CLIENT_INFO.rfifo.size;
+
+	/* Save IP context */
+	WIN_INFO->is_ip_window = win_p->is_ip;
+	if (win_p->is_ip) {
+		WIN_INFO->multicast_enable	   = HFI_MULTICAST_ENABLE;
+		WIN_INFO->disable_src_isr_id_stamp = 0;
+		WIN_INFO->logical_port_id_valid	   = 0;
+		WIN_INFO->logical_port_id	   = 0;
+	}
+
+	return 0;
+}
+
+/* Free the phyp page used at OPEN WINDOW hcall */
+static inline void hfi_destroy_window_info(struct hfidd_acs *p_acs,
+					struct hfidd_window *win_p)
+{
+	free_pages((unsigned long)win_p->win_open_info_p,
+			get_order(PAGE_SIZE_4K));
+	win_p->win_open_info_p = NULL;
+	return;
+}
+
+/* Call to OPEN WINDOW hcall */
+static int hfi_hcall_to_open_window(struct hfidd_acs *p_acs,
+				struct hfidd_window *win_p)
+{
+	int		rc = 0;
+	long long	hvrc = 0;
+	u64		ummio_regs;
+	u64		pmmio_regs;
+	u64		send_intr;
+	u64		recv_intr;
+
+	hvrc = hfi_open_window(p_acs->dds.hfi_id,
+			win_p->index,
+			H_OPEN,
+			(u64)win_p->win_open_info_laddr,
+			&ummio_regs,
+			&pmmio_regs,
+			&send_intr,
+			&recv_intr);
+
+	if (hvrc != H_SUCCESS) {
+		if (hvrc == H_HARDWARE) {
+			win_p->state = WIN_HERROR;
+			rc = -EIO;
+		} else {
+			rc = -EINVAL;
+		}
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_hcall_to_open_window: OPEN WINDOW failed, "
+			"hvrc=0x%llx\n", hvrc);
+		return rc;
+	}
+
+	/* Copy mmio_regs logical page from OPEN_WINDOW hcall */
+	win_p->mmio_regs = ummio_regs;
+	win_p->send_intr  = (unsigned int)send_intr;
+	win_p->recv_intr  = (unsigned int)recv_intr;
+
+	return 0;
+}
 
 /*
  * Map the Effective Address pages for Memory Regions.
@@ -573,6 +673,31 @@ sfifo_err:
 	return rc;
 }
 
+/* Free all the window memory regions */
+static int hfi_takedown_window_in_MMU(struct hfidd_acs *p_acs,
+		unsigned int is_userspace, struct hfidd_window *win_p)
+{
+	int	rc = 0;
+
+	rc = hfi_unregister_MMU(p_acs, win_p->rfifo_x_tab);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_takedown_window_in_MMU: rfifo mr failed,"
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = hfi_unregister_MMU(p_acs, win_p->sfifo_x_tab);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_takedown_window_in_MMU: sfifo mr failed,"
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
 static int hfi_xlate_fifos(struct hfidd_acs *p_acs,
 		unsigned int is_userspace,
 		struct hfidd_window *win_p,
@@ -701,6 +826,19 @@ static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+static int hfi_destroy_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;
+
+	hfi_destroy_window_info(p_acs, win_p);
+
+	rc = hfi_takedown_window_in_MMU(p_acs, is_userspace, win_p);
+	return rc;
+}
+
 static int hfi_setup_window_parm(struct hfidd_acs *p_acs,
 			unsigned int is_userspace,
 			struct hfidd_window *win_p,
@@ -719,8 +857,20 @@ static int hfi_setup_window_parm(struct hfidd_acs *p_acs,
 			"failed, rc = 0x%x\n", rc);
 		goto setup_window_parm_err1;
 	}
+
+	/* Build window information for OPEN WINDOW hcall */
+	rc = hfi_build_window_info(p_acs, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_setup_window_parm: hfi_build_window_info "
+			"failed, rc = 0x%x\n", rc);
+		goto setup_window_parm_err2;
+	}
+
 	return 0;
 
+setup_window_parm_err2:
+	hfi_takedown_window_in_MMU(p_acs, is_userspace, win_p);
 setup_window_parm_err1:
 	return rc;
 }
@@ -783,9 +933,39 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		goto hfidd_open_window_func_err3;
 	}
 
+	rc = hfi_hcall_to_open_window(p_acs, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_hcall_to_open_window "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err4;
+	}
+
+	/* tell user the local ISR id */
+	local_p->local_isrid = p_acs->isr;
+	win_p->client_info.local_isrid = p_acs->isr;
+
+	/* Copy out the client info back to user */
+	rc = hfi_copy_to_user((void *)out_p, (void *)local_p,
+			is_userspace, sizeof(struct hfi_client_info));
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_copy_to_user "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err4;
+	}
+
+	spin_lock(&(win_p->win_lock));
+	/* Update the window information */
+	win_p->pid = current->tgid;
+	win_p->state = WIN_OPENED;
+	spin_unlock(&(win_p->win_lock));
+
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err4:
+	hfi_destroy_window_parm(p_acs, is_userspace, win_p, local_p);
 hfidd_open_window_func_err3:
 	hfi_free_win_resource(p_acs, is_userspace, win_p, local_p);
 hfidd_open_window_func_err2:
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index a97bb5e..1e007c5 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -70,6 +70,8 @@
 
 #define HFI_ACCESS_CTL_SHIFT	32
 
+#define HFI_MULTICAST_ENABLE	1
+
 struct win_open_info {
 	/* Hyp Feedback */
 	unsigned long long	hypervisor_capabilities;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 18/27] HFI: Map window registers into user process
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (15 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 17/27] HFI: Set up and call the open window hypercall dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 19/27] HFI: Add window close request dykmanj
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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

User-space applications send and receive without kernel involvement, once
the window is open. A page of hardware registers controlling the appropriate
window is mapped into the user's address space.

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_map.c    |   99 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |    4 ++
 drivers/net/hfi/core/hfidd_window.c |   51 ++++++++++++++++++-
 4 files changed, 154 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_map.c

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 8d5558d..3adf07e 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -5,5 +5,6 @@ hfi_core-objs:=	hfidd_adpt.o \
 		hfidd_window.o \
 		hfidd_init.o \
 		hfidd_xlat.o \
+		hfidd_map.o \
 		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_map.c b/drivers/net/hfi/core/hfidd_map.c
new file mode 100644
index 0000000..816e7ae
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_map.c
@@ -0,0 +1,99 @@
+/*
+ * hfidd_map.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/io.h>
+#include <linux/hfi/hfidd_internal.h>
+
+int hfidd_mmap(struct hfidd_acs *p_acs, void **eaddr, int size,
+		unsigned long vm_flag, unsigned long long busaddr,
+		unsigned long long offset)
+{
+	struct vm_area_struct	*vma;
+	unsigned long		vsize;
+	int			rc;
+
+	down_write(&current->mm->mmap_sem);
+	*eaddr = (void *)do_mmap(NULL, (unsigned long)*eaddr, size, PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS,
+			offset);
+	up_write(&current->mm->mmap_sem);
+	if (*eaddr) {
+		vma = find_vma(current->mm, (u64) *eaddr);
+		if (!vma) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_mmap: find_vma failed\n");
+			return -ENOMEM;
+		}
+	} else {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_mmap: do_mmap failed\n");
+		return -ENOMEM;
+	}
+
+	vsize = vma->vm_end - vma->vm_start;
+	if (vsize != size) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_mmap: Wrong sizes: vsize = %ld "
+			"size = %d\n", vsize, size);
+		return -EINVAL;
+	}
+
+	if (vm_flag == VM_RESERVED)
+		vma->vm_page_prot = pgprot_val(vma->vm_page_prot);
+	else
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	vma->vm_flags |= vm_flag;
+
+	rc = remap_pfn_range(vma, vma->vm_start, busaddr >> PAGE_SHIFT, size,
+			vma->vm_page_prot);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_mmap: remap_pfn_range failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int hfidd_unmap(void *addr, int size)
+{
+	int rc = 0;
+	struct mm_struct *mm = current->mm;
+
+	if (mm && (addr != NULL)) {
+		down_write(&mm->mmap_sem);
+		rc = do_munmap(mm, (unsigned long)addr, size);
+		up_write(&mm->mmap_sem);
+	}
+
+	return rc;
+}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index c4ed215..1f7fe80 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -57,6 +57,10 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 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_mmap(struct hfidd_acs *p_acs, void **eaddr, int size,
+		unsigned long vm_flag, unsigned long long busaddr,
+		unsigned long long offset);
+int hfidd_unmap(void *addr, int size);
 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 3a9fea9..4ee96f8 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -875,6 +875,44 @@ setup_window_parm_err1:
 	return rc;
 }
 
+/* Map the window mmio registers - only user space window */
+static int hfi_map_mmio_regs(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	offset;
+	void			*tmp_eaddr;
+
+	if (!is_userspace) {
+		/* No translation, just pass back the logical address */
+		client_p->mmio_regs.use.kptr = (void *)win_p->mmio_regs;
+		win_p->client_info.mmio_regs.use.kptr =
+				(void *)win_p->mmio_regs;
+	} else {
+		/*
+		 * Translate mmio_regs from logical to effective address: 1st
+		 * page
+		 */
+		tmp_eaddr = 0;
+		offset = (client_p->window) << PAGE_SHIFT_64K;
+		rc = hfidd_mmap(p_acs, &tmp_eaddr, PAGE_SIZE_64K,
+				VM_RESERVED | VM_IO,
+				(long long)win_p->mmio_regs, offset);
+		if (rc) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfi_map_mmio_regs: hfidd_mmap mmio_regs "
+				"failed, rc = 0x%x, mmio_regs = 0x%llx\n",
+				rc, (unsigned long long)win_p->mmio_regs);
+			return rc;
+		}
+		client_p->mmio_regs.use.kptr = tmp_eaddr;
+		win_p->client_info.mmio_regs.use.kptr = tmp_eaddr;
+	}
+	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
@@ -941,6 +979,14 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		goto hfidd_open_window_func_err4;
 	}
 
+	rc = hfi_map_mmio_regs(p_acs, is_userspace, win_p, local_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_map_mmio_regs "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err4;
+	}
+
 	/* tell user the local ISR id */
 	local_p->local_isrid = p_acs->isr;
 	win_p->client_info.local_isrid = p_acs->isr;
@@ -952,7 +998,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
 			"hfidd_open_window_func: hfi_copy_to_user "
 			"failed, rc = 0x%x\n", rc);
-		goto hfidd_open_window_func_err4;
+		goto hfidd_open_window_func_err5;
 	}
 
 	spin_lock(&(win_p->win_lock));
@@ -964,6 +1010,9 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err5:
+	if (is_userspace)
+		hfidd_unmap(local_p->mmio_regs.use.kptr, PAGE_SIZE_64K);
 hfidd_open_window_func_err4:
 	hfi_destroy_window_parm(p_acs, is_userspace, win_p, local_p);
 hfidd_open_window_func_err3:
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 19/27] HFI: Add window close request
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (16 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 18/27] HFI: Map window registers into user process dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 20/27] HFI: Close window hypervisor call dykmanj
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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   |   36 +++++++++
 drivers/net/hfi/core/hfidd_proto.h  |    4 +
 drivers/net/hfi/core/hfidd_window.c |  148 +++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfidd_client.h    |    8 ++
 include/linux/hfi/hfidd_hcalls.h    |    1 +
 include/linux/hfi/hfidd_requests.h  |    1 +
 6 files changed, 198 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 1008260..603feb8 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -79,6 +79,20 @@ static int hfidd_query_dd_info(struct hfidd_acs *p_acs,
 	return rc;
 }
 
+/*
+ * This function is to check which command will be allowed after we got
+ * hfi error.
+ */
+static inline int valid_cmd_for_hfi_error(int cmd)
+{
+	switch (cmd) {
+	case HFIDD_REQ_CLOSE_WINDOW:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
 /* 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)
@@ -129,6 +143,15 @@ static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
 		return -EINVAL;
 	}
 
+	if (p_acs->state != HFI_AVAIL) {
+		if (valid_cmd_for_hfi_error(cmd.req)) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_write_cmd: hfi%d not avail, "
+				"state 0x%x for cmd 0x%x\n",
+				p_acs->index, p_acs->state, cmd.req);
+			return -EIO;
+		}
+	}
 	switch (cmd.req) {
 	case HFIDD_REQ_OPEN_WINDOW:
 		if (cmd.req_len != sizeof(struct hfi_client_info)) {
@@ -144,6 +167,19 @@ static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
 			(struct hfi_client_info *) cmd.result.use.kptr);
 		break;
 
+	case HFIDD_REQ_CLOSE_WINDOW:
+		if (cmd.req_len != sizeof(struct hfi_window_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_window_info), cmd.req);
+			return -EINVAL;
+		}
+		rc = hfidd_close_window_func(p_acs, is_userspace,
+				(struct hfi_window_info *) buf);
+		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 1f7fe80..e065d56 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -54,6 +54,10 @@ 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 hfidd_close_window_internal(struct hfidd_acs *p_acs,
+		unsigned int is_userspace, unsigned int win_num);
+int hfidd_close_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+		struct hfi_window_info *user_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);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 4ee96f8..1724c30 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -875,6 +875,28 @@ setup_window_parm_err1:
 	return rc;
 }
 
+/* Unmap the window mmio registers - only user space window */
+static int hfi_unmap_mmio_regs(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p,
+		unsigned int is_userspace)
+{
+	int	rc = 0;
+
+	if (is_userspace) {
+		rc = hfidd_unmap((void *)
+				(win_p->client_info.mmio_regs.use.kptr),
+				PAGE_SIZE_64K);
+		if (rc) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfi_unmap_mmio_regs: hfidd_unmap failed "
+				"rc = 0x%x\n", rc);
+			return rc;
+		}
+		win_p->client_info.mmio_regs.use.kptr = NULL;
+	}
+	return 0;
+}
+
 /* Map the window mmio registers - only user space window */
 static int hfi_map_mmio_regs(struct hfidd_acs *p_acs,
 		unsigned int is_userspace,
@@ -1024,3 +1046,129 @@ hfidd_open_window_func_err1:
 	return rc;
 }
 EXPORT_SYMBOL_GPL(hfidd_open_window_func);
+
+/*
+ * Close an user/kernel window to stop send/receive network traffic thru
+ * HFI adapter. This function will call PHYP to close the window and
+ * release the system resources allocated during open time. This function
+ * is called by hfidd_close_window_func or by abnormal end handler when
+ * the process goes away.
+ */
+int hfidd_close_window_internal(struct hfidd_acs *p_acs,
+		unsigned int is_userspace, unsigned int win_num)
+{
+	struct hfidd_window	*win_p;
+	int			rc = 0;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"close_window_internal: win_num=0x%x\n", win_num);
+
+	if ((win_num <  min_hfi_windows(p_acs)) ||
+	    (win_num >= max_hfi_windows(p_acs))) {
+		rc = -EINVAL;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"close_window_internal: window too large - "
+			"0x%x rc = 0x%x\n", win_num, rc);
+		goto hfidd_close_window_internal_err0;
+	}
+
+	win_p = hfi_window(p_acs, win_num);
+	if (win_p == NULL) {
+		rc = -ENOENT;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"close_window_internal: win_p is NULL rc=0x%x\n", rc);
+		goto hfidd_close_window_internal_err0;
+	}
+
+	spin_lock(&(win_p->win_lock));
+
+	/* Make sure state is open or error state. */
+	if ((win_p->state != WIN_OPENED) &&
+	    (win_p->state != WIN_SUSPENDED) &&
+	    (win_p->state != WIN_ERROR)  &&
+	    (win_p->state != WIN_HERROR)) {
+		rc = -EFAULT;
+		spin_unlock(&(win_p->win_lock));
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_internal: bad window state=0x%x, "
+			"rc = 0x%x\n",  win_p->state, rc);
+		goto hfidd_close_window_internal_err0;
+	}
+	spin_unlock(&(win_p->win_lock));
+
+	rc = hfi_unmap_mmio_regs(p_acs, win_p, is_userspace);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_internal: hfi_unmap_mmio_regs "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_close_window_internal_err0;
+	}
+
+	hfi_destroy_window_info(p_acs, win_p);
+
+	/* Call hcall to unregister MR in the MMU */
+	rc = hfi_takedown_window_in_MMU(p_acs, is_userspace, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_internal: hfi_takedown_window_in_MMU "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_close_window_internal_err0;
+	}
+
+	hfi_free_win_resource(p_acs, is_userspace, win_p,
+		&(win_p->client_info));
+
+	spin_lock(&win_p->win_lock);
+	/* Update the window information */
+	hfi_restore_window_parm(p_acs, win_p);
+	spin_unlock(&win_p->win_lock);
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"close_window_internal: type=0x%x state=0x%x JobID=0x%x\n",
+		win_p->type, win_p->state, win_p->job_id);
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"close_window_internal: rc=0x%x\n", rc);
+	return rc;
+
+hfidd_close_window_internal_err0:
+	return rc;
+}
+
+/*
+ * This function is called by the kernel users directly or a write
+ * system call by the kernel users. It will call hfidd_close_window_internal
+ * to close a specific window.
+ */
+int hfidd_close_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+	struct hfi_window_info *user_p)
+{
+	unsigned int		win_num;
+	int			rc = 0;
+	struct hfi_window_info	win_info;
+
+	/* Copy in win num from user */
+	rc = hfi_copy_from_user(&win_info, user_p,
+			is_userspace, sizeof(struct hfi_window_info));
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_func: hfi_copy_from_user "
+			"failed, rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	win_num = win_info.window;
+
+	rc = hfidd_close_window_internal(p_acs, is_userspace, win_num);
+	if (rc) {
+		rc = -EINVAL;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_func: close_window_internal "
+			"failed, win=0x%x rc=0x%x\n", win_num, rc);
+		return rc;
+	}
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"close_window_func: rc=0x%x\n", rc);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(hfidd_close_window_func);
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 7e4c1a7..11c8973 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -113,6 +113,14 @@ struct hfi_client_info {
 	struct hfi_64b		mmio_regs;		/* Output	*/
 };
 
+/*
+ * HFIDD_REQ_CLOSE_WINDOW: close window
+ */
+struct hfi_window_info {
+	struct hfi_req_hdr	hdr;
+	unsigned int		window;
+};
+
 #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_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 1e007c5..777de8f 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -40,6 +40,7 @@
 #define H_HFI_QUERY_INTERFACE		0xF004
 #define H_HFI_STOP_INTERFACE		0xF008
 #define H_HFI_OPEN_WINDOW		0xF00C
+#define H_HFI_CLOSE_WINDOW		0xF014
 #define H_NMMU_START			0xF028
 #define H_NMMU_STOP			0xF02C
 #define H_NMMU_ALLOCATE_RESOURCE	0xF030
diff --git a/include/linux/hfi/hfidd_requests.h b/include/linux/hfi/hfidd_requests.h
index 4f1c74d..a7a38da 100644
--- a/include/linux/hfi/hfidd_requests.h
+++ b/include/linux/hfi/hfidd_requests.h
@@ -35,5 +35,6 @@
 
 #define HFIDD_REQ_OPEN_WINDOW			0x00000a01
 #define HFIDD_REQ_QUERY_DD_INFO			0x00001004
+#define HFIDD_REQ_CLOSE_WINDOW			0x00000a02
 
 #endif /* _HFIDD_REQUESTS_H_ */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 20/27] HFI: Close window hypervisor call
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (17 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 19/27] HFI: Add window close request dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 21/27] HFI: Add send and receive interrupts dykmanj
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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 |   22 ++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |    1 +
 drivers/net/hfi/core/hfidd_window.c |   53 +++++++++++++++++++++++++++++++++--
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
index 1915336..4bc6525 100644
--- a/drivers/net/hfi/core/hfidd_hcalls.c
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -153,6 +153,17 @@ static inline long long h_hfi_open_window(int token,
 	return rc;
 }
 
+static inline long long h_hfi_close_window(int token,
+		u64 HFI_chip_ID,
+		u64 win_num,
+		u64 flag)
+{
+	return plpar_hcall_norets(token,
+		HFI_chip_ID,
+		win_num,
+		flag);
+}
+
 long long hfi_start_nmmu(u64 chip_id, void *nmmu_info)
 {
 	return h_nmmu_start(H_NMMU_START, chip_id, nmmu_info);
@@ -249,6 +260,17 @@ long long hfi_modify_mr(u64 chip_id, u64 request, u64 mr_handle,
 	return hvrc;
 }
 
+long long hfi_close_window(u64 unit_id, u64 win_id, u64 flag)
+{
+	long long hvrc;
+
+	hvrc = h_hfi_close_window(H_HFI_CLOSE_WINDOW,
+			unit_id,
+			win_id,
+			flag);
+			return hvrc;
+}
+
 long long hfi_free_mr(u64 chip_id, u64 res, u64 mr_handle, u64 sub_region_id)
 {
 	long long	hvrc;
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index e065d56..f531dcd 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -94,6 +94,7 @@ long long hfi_modify_mr(u64 chip_id, u64 request, u64 mr_handle,
 		u64 e_addr,
 		u64 l_addr,
 		u64 num_pg_sz);
+long long hfi_close_window(u64 unit_id, u64 win_id, u64 flag);
 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,
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 1724c30..ff8b9f0 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -460,6 +460,43 @@ static int hfi_hcall_to_open_window(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+/* Call to CLOSE WINDOW hcall */
+static int hfi_hcall_to_close_window(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p)
+{
+	int	rc = 0;
+	long long hvrc = 0;
+	u64	start_time = get_jiffies_64();
+
+	hvrc = hfi_close_window(p_acs->dds.hfi_id,
+			win_p->index,
+			H_CLOSE);
+
+	/*
+	 * Need to call CLOSE WINDOW with flag H_CHECK_CLOSED
+	 * to check when the window is completely closed
+	 */
+	while (hvrc == H_BUSY) {
+		hvrc = hfi_close_window(p_acs->dds.hfi_id,
+				win_p->index,
+				H_CHECK_CLOSED);
+		if (hvrc != H_BUSY)
+			break;
+		if (hfidd_age_hcall(start_time))
+			break;
+	}
+
+	if (hvrc != H_SUCCESS) {
+		win_p->state = WIN_FAIL_CLOSE;
+		rc = -EIO;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_hcall_to_close_window: CLOSE WINDOW failed, "
+			"hvrc=0x%llx\n", hvrc);
+	}
+
+	return rc;
+}
+
 /*
  * Map the Effective Address pages for Memory Regions.
  * If more than one page, need to setup a page containing
@@ -1006,7 +1043,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
 			"hfidd_open_window_func: hfi_map_mmio_regs "
 			"failed, rc = 0x%x\n", rc);
-		goto hfidd_open_window_func_err4;
+		goto hfidd_open_window_func_err5;
 	}
 
 	/* tell user the local ISR id */
@@ -1020,7 +1057,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
 			"hfidd_open_window_func: hfi_copy_to_user "
 			"failed, rc = 0x%x\n", rc);
-		goto hfidd_open_window_func_err5;
+		goto hfidd_open_window_func_err6;
 	}
 
 	spin_lock(&(win_p->win_lock));
@@ -1032,9 +1069,11 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	kfree(local_p);
 	return rc;
 
-hfidd_open_window_func_err5:
+hfidd_open_window_func_err6:
 	if (is_userspace)
 		hfidd_unmap(local_p->mmio_regs.use.kptr, PAGE_SIZE_64K);
+hfidd_open_window_func_err5:
+	hfi_hcall_to_close_window(p_acs, win_p);
 hfidd_open_window_func_err4:
 	hfi_destroy_window_parm(p_acs, is_userspace, win_p, local_p);
 hfidd_open_window_func_err3:
@@ -1104,6 +1143,14 @@ int hfidd_close_window_internal(struct hfidd_acs *p_acs,
 		goto hfidd_close_window_internal_err0;
 	}
 
+	rc = hfi_hcall_to_close_window(p_acs, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_close_window_internal: hfi_hcall_to_close_window "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_close_window_internal_err0;
+	}
+
 	hfi_destroy_window_info(p_acs, win_p);
 
 	/* Call hcall to unregister MR in the MMU */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 21/27] HFI: Add send and receive interrupts
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (18 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 20/27] HFI: Close window hypervisor call dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 22/27] HFI: Add event notifications dykmanj
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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

Each window has its own interrupt for send interrupts and another for receive
interrupts.

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_intr.c   |  127 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_proto.h  |    3 +
 drivers/net/hfi/core/hfidd_window.c |   16 ++++-
 include/linux/hfi/hfidd_client.h    |   17 +++++
 include/linux/hfi/hfidd_internal.h  |    2 +
 6 files changed, 165 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_intr.c

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 3adf07e..d2ed86f 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -6,5 +6,6 @@ hfi_core-objs:=	hfidd_adpt.o \
 		hfidd_init.o \
 		hfidd_xlat.o \
 		hfidd_map.o \
+		hfidd_intr.o \
 		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_intr.c b/drivers/net/hfi/core/hfidd_intr.c
new file mode 100644
index 0000000..253de27
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_intr.c
@@ -0,0 +1,127 @@
+/*
+ * hfidd_intr.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 irqreturn_t send_intr_handler(int irq, void *data)
+{
+	struct hfidd_window *win_p = data;
+	struct hfidd_acs *p_acs;
+
+	p_acs = hfidd_global.p_acs[win_p->ai];
+	if (p_acs == NULL)
+		return IRQ_HANDLED;
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t recv_intr_handler(int irq, void *data)
+{
+	struct hfidd_window *win_p = data;
+	struct hfidd_acs *p_acs;
+
+	p_acs = hfidd_global.p_acs[win_p->ai];
+	if (p_acs == NULL)
+		return IRQ_HANDLED;
+
+	return IRQ_HANDLED;
+}
+
+static inline void hfidd_clear_interrupt(unsigned int int_level,
+			struct hfidd_window *win_p)
+{
+	ibmebus_free_irq(int_level, win_p);
+}
+
+static int hfidd_init_interrupt(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p ,
+		irqreturn_t (*handler)(int, void *),
+		const char *name,
+		unsigned int int_level)
+{
+	int rc;
+
+	rc = ibmebus_request_irq(int_level, handler, IRQF_DISABLED, name,
+			win_p);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_init_interrupt: request_irq failed for "
+			"int_level 0x%x rc %d\n", int_level, rc);
+		return rc;
+	}
+	return rc;
+}
+
+int hfidd_init_win_interrupt(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p)
+{
+	int rc;
+
+	/* init send interrupt handler */
+	snprintf(win_p->send_name, IRQ_NAME_SIZE - 1, "%s%d-send%d",
+		HFIDD_DEV_NAME, p_acs->index, win_p->index);
+	rc = hfidd_init_interrupt(p_acs, win_p, send_intr_handler,
+		win_p->send_name, win_p->send_intr);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_init_win_interrupt: send int failed, "
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	/* init recv interrupt handler */
+	snprintf(win_p->recv_name, IRQ_NAME_SIZE - 1, "%s%d-recv%d",
+		HFIDD_DEV_NAME, p_acs->index, win_p->index);
+	rc = hfidd_init_interrupt(p_acs, win_p, recv_intr_handler,
+		win_p->recv_name, win_p->recv_intr);
+	if (rc != 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_init_win_interrupt: recv int failed, "
+			"rc = 0x%x\n", rc);
+		hfidd_clear_interrupt(win_p->send_intr, win_p);
+		return rc;
+	}
+	return 0;
+}
+
+void hfidd_clear_win_interrupt(struct hfidd_window *win_p)
+{
+	if (win_p->send_intr != 0) {
+		hfidd_clear_interrupt(win_p->send_intr, win_p);
+		win_p->send_intr = 0;
+	}
+	if (win_p->recv_intr != 0) {
+		hfidd_clear_interrupt(win_p->recv_intr, win_p);
+		win_p->recv_intr = 0;
+	}
+}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index f531dcd..af88f0b 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -73,6 +73,9 @@ int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
 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);
+int hfidd_init_win_interrupt(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p);
+void hfidd_clear_win_interrupt(struct hfidd_window *win_p);
 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,
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index ff8b9f0..752cd11 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -1050,6 +1050,15 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	local_p->local_isrid = p_acs->isr;
 	win_p->client_info.local_isrid = p_acs->isr;
 
+	/* Init the send and recv interrupt handlers */
+	rc = hfidd_init_win_interrupt(p_acs, win_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfidd_init_win_interrupt "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err6;
+	}
+
 	/* Copy out the client info back to user */
 	rc = hfi_copy_to_user((void *)out_p, (void *)local_p,
 			is_userspace, sizeof(struct hfi_client_info));
@@ -1057,7 +1066,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
 			"hfidd_open_window_func: hfi_copy_to_user "
 			"failed, rc = 0x%x\n", rc);
-		goto hfidd_open_window_func_err6;
+		goto hfidd_open_window_func_err7;
 	}
 
 	spin_lock(&(win_p->win_lock));
@@ -1069,6 +1078,8 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err7:
+	hfidd_clear_win_interrupt(win_p);
 hfidd_open_window_func_err6:
 	if (is_userspace)
 		hfidd_unmap(local_p->mmio_regs.use.kptr, PAGE_SIZE_64K);
@@ -1135,6 +1146,9 @@ int hfidd_close_window_internal(struct hfidd_acs *p_acs,
 	}
 	spin_unlock(&(win_p->win_lock));
 
+	/* Clear the send and recv interrupt handlers */
+	hfidd_clear_win_interrupt(win_p);
+
 	rc = hfi_unmap_mmio_regs(p_acs, win_p, is_userspace);
 	if (rc) {
 		dev_printk(KERN_ERR, p_acs->hfidd_dev,
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 11c8973..3b2d032 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -121,6 +121,23 @@ struct hfi_window_info {
 	unsigned int		window;
 };
 
+/* Event Notification */
+enum hfi_event_type {
+	HFIDD_SEND		= 0,
+	HFIDD_RECV		= 1,
+	HFIDD_WIN_ERROR		= 2,
+	HFIDD_HFI_ERROR		= 3,
+	HFIDD_TERMINATE		= 4,
+	HFIDD_RELEASE_WINDOW	= 5,
+	HFIDD_CAU_ERROR		= 6,
+	HFIDD_ICS_ERROR		= 7,
+	HFIDD_HFI_READY_REG	= 8,
+	HFIDD_ROUTE_CHANGE	= 9,
+	HFIDD_IP_TRC_LVL	= 10,	/* IP Window only */
+	HFIDD_POOL_SIZE		= 11,	/* IP Window only */
+	HFIDD_NUM_EVENT_TYPES	= 12
+};
+
 #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 0d6b77b..e96142a 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -145,6 +145,8 @@ struct hfidd_global {
 	struct hfidd_acs	*p_acs[MAX_HFIS];
 };
 
+extern struct hfidd_global hfidd_global;
+
 static inline struct hfidd_window *hfi_window(struct hfidd_acs *p,
 		unsigned int idx)
 {
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 22/27] HFI: Add event notifications
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (19 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 21/27] HFI: Add send and receive interrupts dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 23/27] HFI: Define packet header formats and window register offsets dykmanj
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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

Interrupts and some error notifications get passed to window users through
events.  User-space applications can register for a signal to be delivered
or can spawn a thread to call into the HFI DD and wait.
Kernel windows can register callbacks.

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_adpt.c   |    5 +
 drivers/net/hfi/core/hfidd_events.c | 1106 +++++++++++++++++++++++++++++++++++
 drivers/net/hfi/core/hfidd_init.c   |   35 ++
 drivers/net/hfi/core/hfidd_intr.c   |   40 ++-
 drivers/net/hfi/core/hfidd_proto.h  |   16 +-
 drivers/net/hfi/core/hfidd_window.c |   24 +
 include/linux/hfi/hfidd_client.h    |   64 ++
 include/linux/hfi/hfidd_internal.h  |   69 +++
 include/linux/hfi/hfidd_requests.h  |    3 +
 10 files changed, 1361 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/hfi/core/hfidd_events.c

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index d2ed86f..da71824 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -3,6 +3,7 @@
 #
 hfi_core-objs:=	hfidd_adpt.o \
 		hfidd_window.o \
+		hfidd_events.o \
 		hfidd_init.o \
 		hfidd_xlat.o \
 		hfidd_map.o \
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index 372eeec..9ef99c9 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -118,6 +118,7 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs)
 
 		/* Initialize window fields */
 		spin_lock_init(&(p_acs->win[i]->win_lock));
+		spin_lock_init(&(p_acs->win[i]->event_lock));
 
 		p_acs->win[i]->ai = p_acs->index;
 		p_acs->win[i]->index = p_acs->dds.window_start + i;
@@ -138,6 +139,8 @@ void hfidd_free_windows(struct hfidd_acs *p_acs)
 	int		i;
 
 	for (i = 0; i < p_acs->dds.window_num; i++) {
+		if (p_acs->win[i])
+			hfidd_events_clean(p_acs, p_acs->win[i]);
 		kfree(p_acs->win[i]);
 		p_acs->win[i] = NULL;
 	}
@@ -211,6 +214,8 @@ int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
 			if (p_acs->state != HFI_AVAIL) {
 				p_acs->isr = query_p->local_node_id;
 				p_acs->state = HFI_AVAIL;
+				/* Notify user that adapter is ready */
+				hfidd_notify_hfi_ready(p_acs);
 			}
 		} else {
 			p_acs->state = HFI_UNAVAIL;
diff --git a/drivers/net/hfi/core/hfidd_events.c b/drivers/net/hfi/core/hfidd_events.c
new file mode 100644
index 0000000..fed94f6
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_events.c
@@ -0,0 +1,1106 @@
+/* hfidd_events.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 void rem_events(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		struct hfidd_tid_info *tid_info, unsigned int events,
+		struct hfidd_win_event **event_list);
+static int hfidd_hfi_ready_registration(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *reg);
+static void hfidd_hfi_ready_unregistration(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *reg);
+
+static unsigned int event_mask[HFIDD_NUM_EVENT_TYPES] = {
+	HFIDD_SEND_EVENT,
+	HFIDD_RECV_EVENT,
+	HFIDD_WIN_ERROR_EVENT,
+	HFIDD_HFI_ERROR_EVENT,
+	HFIDD_TERMINATE_EVENT,
+	HFIDD_RELEASE_WINDOW_EVENT,
+	HFIDD_CAU_ERROR_EVENT,
+	HFIDD_ICS_ERROR_EVENT,
+	HFIDD_HFI_READY_REG_EVENT,
+	HFIDD_ROUTE_CHANGE_EVENT,
+	HFIDD_IP_TRC_LVL_EVENT,
+	HFIDD_POOL_SIZE_EVENT};
+
+
+static void hfidd_tid_info_init(struct hfidd_tid_info *tid_info)
+{
+	memset(tid_info, 0, sizeof(*tid_info));
+	sema_init(&(tid_info->tid_sem), 1);
+	INIT_LIST_HEAD(&(tid_info->event_list));
+	init_waitqueue_head(&(tid_info->event_wait));
+	tid_info->th = current;
+	return;
+}
+
+static void hfidd_tid_info_end(struct hfidd_tid_info *tid_info,
+		struct hfidd_q_event **q_event_list)
+{
+	struct list_head	*pos;
+	struct list_head	*q;
+	struct hfidd_q_event	*ev;
+
+	/* Clean up any remaining events. */
+	list_for_each_safe(pos, q, &(tid_info->event_list)) {
+		ev = list_entry(pos, struct hfidd_q_event, list);
+		list_del(pos);
+		ev->next = *q_event_list;
+		*q_event_list = ev;
+	}
+	return;
+}
+
+static inline void hfidd_update_eb(struct hfidd_tid_info *tid_info,
+		struct hfi_reg_events *reg_events)
+{
+	tid_info->eb_xd = current->group_leader;
+	tid_info->eb = (struct hfi_event_buffer *)reg_events->info.eb.use.allu;
+}
+
+/* Post an event.  The win->event_lock must be held before calling. */
+static int hfidd_post_event(struct hfidd_acs *p_acs,
+		struct hfidd_tid_info *tid_info, enum hfi_event_type type,
+		unsigned int event, struct hfidd_q_event **q_event_list)
+{
+	int			rc = 0;
+	struct hfidd_q_event	*ev;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_post_event: event=0x%x tid=0x%llx\n",
+		event, tid_info->tid);
+
+	if (tid_info->type == WAIT_FOR_EVENTS) {
+		/* Allocate and fill in the structure for the event. */
+		if (*q_event_list == NULL) {
+			rc = -EFAULT;
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_post_event: internal error - "
+				"%d\n", rc);
+		} else {
+			ev = *q_event_list;
+			*q_event_list = (*q_event_list)->next;
+			ev->event = event;
+
+			/*
+			 * Add the event to the event list and wake up any
+			 * waiting thread.
+			 */
+			list_add(&(ev->list), &(tid_info->event_list));
+			wake_up_interruptible(&(tid_info->event_wait));
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * Wakeup waiting task if necessary.  The win->event_lock must be held before
+ * calling.
+ */
+static int hfidd_events_wakeup(struct hfidd_acs *p_acs,
+		struct hfidd_tid_info *tid_info,
+		struct hfidd_q_event **q_event_list)
+{
+	int			rc = 0;
+	struct list_head	*pos;
+	struct list_head	*q;
+	struct hfidd_q_event	*ev;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_wakeup: tid=0x%llx\n", tid_info->tid);
+	/*
+	 * A well behaved thread will not be waiting for any events when
+	 * wakeup is called.  This code is to handle misbehaving threads.
+	 */
+
+	/*
+	 * Add an event that will cause any misbehaving waiting thread to
+	 * wake up.  Once it wakes up, it will see that we are cleaning up
+	 * (because win->open_close_count has changed) and will end.
+	 */
+	if (*q_event_list == NULL) {
+		rc = -EFAULT;
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_wakeup: internal error - "
+			"%d\n", rc);
+		goto hfidd_events_wakeup_error1;
+	}
+
+	ev = *q_event_list;
+	*q_event_list = (*q_event_list)->next;
+	ev->event = HFIDD_TERMINATE;
+	list_add(&(ev->list), &(tid_info->event_list));
+	wake_up_interruptible(&(tid_info->event_wait));
+
+	/* By getting this lock, we make sure that we don't delete tid_info */
+	/* until the thread is done using it. */
+	down(&(tid_info->tid_sem));
+
+	list_for_each_safe(pos, q, &(tid_info->event_list)) {
+		ev = list_entry(pos, struct hfidd_q_event, list);
+		list_del(pos);
+		ev->next = *q_event_list;
+		*q_event_list = ev;
+	}
+
+	up(&(tid_info->tid_sem));
+
+
+hfidd_events_wakeup_error1:
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_wakeup: rc=%d\n", rc);
+	return rc;
+}
+
+/*
+ * Preallocate a group of q events.  We must preallocate because we are
+ * not allowed to use kzalloc once we have the event_lock.
+ */
+static struct hfidd_q_event *hfidd_prealloc_q_events(struct hfidd_acs *p_acs,
+		struct hfidd_window *win, int num_events)
+{
+	int i;
+	struct hfidd_q_event *q_event_list = NULL;
+	struct hfidd_q_event *q_event;
+
+	for (i = 0; i < num_events; i++) {
+		q_event = kzalloc(sizeof(*q_event), GFP_KERNEL);
+		if (q_event == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_prealloc_q_events: kzalloc failed, "
+				"num_events = %d\n", num_events);
+
+			while (q_event_list != NULL) {
+				q_event = q_event_list->next;
+				kfree(q_event_list);
+				q_event_list = q_event;
+			}
+			return NULL;
+		}
+		q_event->next = q_event_list;
+		q_event_list = q_event;
+	}
+
+	return q_event_list;
+}
+
+/* Return any queue events that haven't been used. */
+static void hfidd_return_q_events(struct hfidd_acs *p_acs,
+		struct hfidd_q_event **q_event_list)
+{
+	struct hfidd_q_event *q_event;
+
+	while (*q_event_list != NULL) {
+		q_event = (*q_event_list)->next;
+		kfree(*q_event_list);
+		*q_event_list = q_event;
+	}
+	return;
+}
+/*
+ * Preallocate a tid_info structure.  We must preallocate because we are
+ * not allowed to use kzalloc once we have the event_lock.
+ */
+static struct hfidd_tid_info *prealloc_tid_list(struct hfidd_acs *p_acs)
+{
+	struct hfidd_tid_info *tid_list;
+
+	tid_list = kzalloc(sizeof(*tid_list), GFP_KERNEL);
+	if (tid_list == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"prealloc_tid_list: kzalloc tid info failed\n");
+	} else {
+		hfidd_tid_info_init(tid_list);
+		tid_list->next = NULL;
+	}
+	return tid_list;
+}
+
+/* Return a list of hfidd_tid_info structures. */
+static void return_tid_list(struct hfidd_acs *p_acs,
+		struct hfidd_tid_info **tid_list,
+		struct hfidd_q_event **q_event_list)
+{
+	struct hfidd_tid_info *tid_info;
+
+	while (*tid_list != NULL) {
+		tid_info = *tid_list;
+		*tid_list = tid_info->next;
+		hfidd_tid_info_end(tid_info, q_event_list);
+		kfree(tid_info);
+	}
+}
+
+/*
+ * Preallocate a list of hfidd_win_event structures.  We must preallocate
+ * because we are not allowed to use kzalloc once we have the event_lock.
+ */
+static struct hfidd_win_event *prealloc_event_list(struct hfidd_acs *p_acs,
+		unsigned int events)
+{
+	int i;
+	unsigned int		test_bit = HFIDD_LOWEST_EVENT;
+	struct hfidd_win_event	*win_event;
+	struct hfidd_win_event	*event_list = NULL;
+
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		if (events & test_bit) {
+			win_event = kzalloc(sizeof(*win_event), GFP_KERNEL);
+			if (win_event == NULL) {
+				dev_printk(KERN_ERR, p_acs->hfidd_dev,
+					"prealloc_event_list: kzalloc failed\n");
+
+				while (event_list != NULL) {
+					win_event = event_list;
+					event_list = event_list->next;
+					kfree(win_event);
+				}
+				return NULL;
+			}
+			win_event->next = event_list;
+			event_list = win_event;
+		}
+		test_bit <<= 1;
+	}
+	return event_list;
+}
+
+/* Return a list of hfidd_win_event structures. */
+static void return_event_list(struct hfidd_acs *p_acs,
+		struct hfidd_win_event **event_list)
+{
+	struct hfidd_win_event *win_event;
+
+	while (*event_list != NULL) {
+		win_event = *event_list;
+		*event_list = (*event_list)->next;
+		kfree(win_event);
+	}
+}
+
+/*
+ * Add a group of events to the event handling structures.  The caller must
+ * hold win->event_lock.
+ */
+static int add_events(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		struct hfidd_tid_info *tid_info, unsigned int events,
+		struct hfidd_win_event **event_list)
+{
+	int			rc = 0;
+	int			i;
+	unsigned int		test_bit = HFIDD_LOWEST_EVENT;
+	struct hfidd_win_event	*win_event;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"add_events: enter win=0x%x events=0x%x\n",
+		win->index, events);
+
+	/* Add individual pointers from the window to the tid_info. */
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		if (events & test_bit) {
+			/* Add a pointer from the window to the events. */
+			if (*event_list == NULL) {
+				rc = -EFAULT;
+				dev_printk(KERN_ERR, p_acs->hfidd_dev,
+					"add_events: internal error - "
+					"%d\n", rc);
+
+				goto add_events_err1;
+			}
+			win_event = *event_list;
+			*event_list = (*event_list)->next;
+			win_event->tid_info = tid_info;
+			win_event->next = win->events[i];
+			win->events[i] = win_event;
+			atomic_inc(&(win->num_events[i]));
+		}
+		test_bit <<= 1;
+	}
+	return rc;
+
+add_events_err1:
+	rem_events(p_acs, win, tid_info, events, event_list);
+	return rc;
+}
+
+/*
+ * Remove a group of events from the event handling structures.	 The caller
+ * must hold win->event_lock.
+ */
+static void rem_events(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		struct hfidd_tid_info *tid_info, unsigned int events,
+		struct hfidd_win_event **event_list)
+{
+	int			i;
+	unsigned int		test_bit = HFIDD_LOWEST_EVENT;
+	struct hfidd_win_event	*prev_win_event;
+	struct hfidd_win_event	*win_event;
+	unsigned int		temp_events = events;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"rem_events: enter win=0x%x events=0x%x\n",
+		win->index, events);
+
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		if (temp_events & test_bit) {
+			/* Remove pointer from the window or p_acs to events. */
+			prev_win_event = NULL;
+			for (win_event = win->events[i]; win_event != NULL;
+					win_event = win_event->next) {
+				/* Search for this tid in list. */
+				if (win_event->tid_info == tid_info)
+					break;
+				else
+					prev_win_event = win_event;
+			}
+			if (win_event != NULL) {
+				/* Found tid.  Remove it. */
+				if (prev_win_event == NULL)
+					win->events[i] = win_event->next;
+				else
+					prev_win_event->next = win_event->next;
+				win_event->next = *event_list;
+				*event_list = win_event;
+				atomic_dec(&(win->num_events[i]));
+			}
+		}
+		test_bit <<= 1;
+	}
+}
+
+/*
+ * Find a tid_info structure for a given tid and window.  The caller must
+ * hold win->event_lock.
+ */
+static struct hfidd_tid_info *get_tid_info(struct hfidd_acs *p_acs,
+		struct hfidd_window *win, unsigned long long tid,
+		enum hfi_event_hndlr_type type,
+		struct hfidd_tid_info **prev_tid_info,
+		struct hfidd_tid_info **tid_list)
+{
+	struct hfidd_tid_info	*tid_info;
+
+	*prev_tid_info = NULL;
+
+	/* See if it exists already. */
+	for (tid_info = win->tid_list; tid_info != NULL;
+			tid_info = tid_info->next) {
+		if (tid_info->tid == tid)
+			break;
+		*prev_tid_info = tid_info;
+	}
+
+	/* Allocate new structure if necessary. */
+	if (tid_info == NULL) {
+		*prev_tid_info = NULL;
+		if (*tid_list == NULL) {
+			tid_info = NULL;
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"get_tid_info: internal error\n");
+		} else {
+			tid_info = *tid_list; /* Set to NULL so caller knows the
+						 preallocated tid_info
+						 structure was used. */
+			*tid_list = (*tid_list)->next;
+			tid_info->tid = tid;
+			tid_info->type = type;
+			atomic_inc(&win->num_tids);
+			tid_info->next = win->tid_list;
+			win->tid_list = tid_info;
+		}
+	}
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"get_tid_info: exit reg_events=0x%x tid_info=%p\n",
+		tid_info->registered_events,
+		(void *) tid_info);
+
+	return tid_info;
+}
+
+/*
+ * Remove a tid_info structure for a given tid and window.  The caller must
+ * hold win->event_lock.
+ */
+static void rem_tid_info(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		struct hfidd_tid_info *prev_tid_info,
+		struct hfidd_tid_info *tid_info,
+		struct hfidd_tid_info **tid_list)
+{
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"rem_tid_info: remove tid_info for tid 0x%llx\n",
+		tid_info->tid);
+
+	if (prev_tid_info == NULL)
+		win->tid_list = tid_info->next;
+	else
+		prev_tid_info->next = tid_info->next;
+	if (atomic_read(&win->num_tids) > 0)
+		atomic_dec(&win->num_tids);
+	tid_info->next = *tid_list;
+	*tid_list = tid_info; /* Set up to free after releasing lock */
+}
+
+
+/* Register events. */
+int hfidd_events_register(struct hfidd_acs *p_acs, struct hfi_reg_events *arg)
+{
+	int			rc = 0;
+	int			got_lock = 0;
+	struct hfi_reg_events	reg_events;
+	unsigned long long	tid;
+	struct hfidd_tid_info	*prev_tid_info;
+	struct hfidd_tid_info	*tid_info = NULL;
+	struct hfidd_tid_info	*tid_list = NULL;
+	unsigned int		new_events;
+	struct hfidd_window	*win = NULL;
+	struct hfidd_win_event	*event_list = NULL;
+	unsigned long		flags = 0;
+	struct hfidd_q_event	*q_event_list = NULL;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_register: enter p_acs=0x%p\n", (void *)p_acs);
+
+	/* Copy in client info from user */
+	rc = copy_from_user(&reg_events, arg, sizeof(reg_events));
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: copy_from_user failed, "
+			"rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* Verify inputs */
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_register: enter type=0x%x win=0x%x "
+		"events=0x%x\n", reg_events.type, reg_events.window,
+		reg_events.info.events);
+
+	if ((reg_events.type != WAIT_FOR_EVENTS) &&
+	    (reg_events.type != SIGNAL_EVENTS)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: invalid type - "
+			"0x%x\n", reg_events.type);
+		return -EINVAL;
+	}
+	if ((reg_events.window <  min_hfi_windows(p_acs)) ||
+	    (reg_events.window >= max_hfi_windows(p_acs))) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: invalid win - "
+			"0x%x\n", reg_events.window);
+		return -EINVAL;
+	}
+	if ((reg_events.type == WAIT_FOR_EVENTS) &&
+	    (reg_events.info.events & ~HFIDD_ALL_EVENTS)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: invalid events - "
+			"0x%x\n", reg_events.info.events & ~HFIDD_ALL_EVENTS);
+		return -EINVAL;
+	}
+	if ((reg_events.type == SIGNAL_EVENTS) &&
+	    (reg_events.info.eb.use.kptr == NULL)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: invalid signal buffer\n");
+		return -EINVAL;
+	}
+
+	win = hfi_window(p_acs, reg_events.window);
+	/*
+	 * Preallocate data structures.	 We must do this before the
+	 * lock or it will cause errors.
+	 */
+	tid_list = prealloc_tid_list(p_acs);
+	if (tid_list == NULL)
+		return -ENOMEM;
+	if (reg_events.type == WAIT_FOR_EVENTS)
+		event_list = prealloc_event_list(p_acs, reg_events.info.events);
+	else
+		event_list = prealloc_event_list(p_acs, HFIDD_ALL_EVENTS);
+	if (event_list == NULL) {
+		rc = -ENOMEM;
+		goto events_reg_err1;
+	}
+
+	spin_lock_irqsave(&(win->event_lock), flags);
+	got_lock = 1;
+	if (win->state == WIN_AVAILABLE) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: inv state wi=0x%x st=0x%x\n",
+			win->index, win->state);
+		rc = -EINVAL;
+		goto events_reg_err1;
+	}
+
+	/* Get the tid_info structure for this tid. */
+	tid = (current->pid);
+
+	tid_info = get_tid_info(p_acs, win, tid, reg_events.type,
+			&prev_tid_info, &tid_list);
+	if (tid_info == NULL)
+		goto events_reg_err1;
+	if (tid_info->type != reg_events.type) {
+		/* The user can't change types after first registration */
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: inv typ chg old=0x%x new=0x%x\n",
+			tid_info->type, reg_events.type);
+		rc = -EINVAL;
+		goto events_reg_err2;
+	}
+
+	/* Add new event entries. */
+	if (reg_events.type == WAIT_FOR_EVENTS) {
+		new_events = ~tid_info->registered_events &
+			reg_events.info.events;
+	} else {
+		/*
+		 * If signal version is registered more than once, this will
+		 * end up with no events.  Otherwise, all events
+		 */
+		new_events = (~tid_info->registered_events) &
+			HFIDD_ALL_EVENTS;
+		hfidd_update_eb(tid_info, &reg_events);
+	}
+	rc = add_events(p_acs, win, tid_info, new_events, &event_list);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_register: failed to add events, "
+			"rc=%d\n", rc);
+		goto events_reg_err2;
+	}
+	tid_info->registered_events |= new_events;
+
+events_reg_err2:
+	/* Remove tid info if necessary */
+	if (!(tid_info->registered_events))
+		rem_tid_info(p_acs, win, prev_tid_info, tid_info, &tid_list);
+
+events_reg_err1:
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_register: rc=%d events=0x%x\n",
+		rc, (tid_info == NULL) ? 0 : tid_info->registered_events);
+
+	if (got_lock)
+		spin_unlock_irqrestore(&(win->event_lock), flags);
+	return_tid_list(p_acs, &tid_list, &q_event_list);
+	hfidd_return_q_events(p_acs, &q_event_list);
+	return_event_list(p_acs, &event_list);
+	return rc;
+}
+
+int hfidd_events_unregister(struct hfidd_acs *p_acs, struct hfi_reg_events *arg)
+{
+	int			rc = 0;
+	int			got_lock = 0;
+	struct hfi_reg_events	unreg_events;
+	unsigned long long	tid;
+	struct hfidd_tid_info	*prev_tid_info;
+	struct hfidd_tid_info	*tid_info = NULL;
+	struct hfidd_tid_info	*tid_list = NULL;
+	struct hfidd_window	*win = NULL;
+	struct hfidd_win_event	*event_list = NULL;
+	unsigned long		flags = 0;
+	struct hfidd_q_event	*q_event_list = NULL;
+	unsigned int		events_to_rem;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_unregister: enter p_acs=0x%p\n", (void *)p_acs);
+
+	/* Copy in client info from user */
+	rc = copy_from_user(&unreg_events, arg, sizeof(unreg_events));
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_unregister: COPYIN err rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* Validate input */
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_unregister: enter win=0x%x events=0x%x\n",
+		unreg_events.window, unreg_events.info.events);
+
+	if ((unreg_events.type != WAIT_FOR_EVENTS) &&
+	    (unreg_events.type != SIGNAL_EVENTS)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_unregister: invalid type - "
+			"0x%x\n", unreg_events.type);
+		return -EINVAL;
+	}
+
+	if ((unreg_events.window < min_hfi_windows(p_acs)) ||
+	    (unreg_events.window >= max_hfi_windows(p_acs))) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_unregister: invalid win - "
+			"0x%x\n", unreg_events.window);
+		return -EINVAL;
+	}
+
+	if ((unreg_events.type == WAIT_FOR_EVENTS) &&
+	    (unreg_events.info.events & ~HFIDD_ALL_EVENTS)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_unregister: invalid events - "
+			"0x%x\n", unreg_events.info.events & ~HFIDD_ALL_EVENTS);
+		return -EINVAL;
+	}
+	win = hfi_window(p_acs, unreg_events.window);
+
+	/*
+	 * Preallocate data structures.	 We must do this before the
+	 * lock or it will cause errors.
+	 */
+	tid_list = prealloc_tid_list(p_acs);
+	if (tid_list == NULL)
+		return -ENOMEM;
+	spin_lock_irqsave(&(win->event_lock), flags);
+	got_lock = 1;
+
+	/* Get the tid_info structure for this tid. */
+	tid = (current->pid);
+
+	tid_info = get_tid_info(p_acs, win, tid, unreg_events.type,
+			&prev_tid_info, &tid_list);
+	if (tid_info == NULL)
+		goto events_unreg_err1;
+	if (tid_info->type != unreg_events.type) {
+		/* The user can't change types after first registration */
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_events_unregister: inv typ chg old=0x%x new=0x%x\n",
+			tid_info->type, unreg_events.type);
+		rc = -EINVAL;
+		goto events_unreg_err2;
+	}
+
+	/* Remove entries. */
+	if (unreg_events.type == WAIT_FOR_EVENTS)
+		events_to_rem = unreg_events.info.events;
+	else
+		events_to_rem = HFIDD_ALL_EVENTS;
+	rem_events(p_acs, win, tid_info, events_to_rem, &event_list);
+	tid_info->registered_events &= ~events_to_rem;
+
+events_unreg_err2:
+	/* Remove tid_info if necessary. */
+	if (!(tid_info->registered_events))
+		rem_tid_info(p_acs, win, prev_tid_info, tid_info, &tid_list);
+
+events_unreg_err1:
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_unregister: rc=%d events=0x%x\n",
+		rc, (tid_info == NULL) ? 0 : tid_info->registered_events);
+
+	if (got_lock)
+		spin_unlock_irqrestore(&(win->event_lock), flags);
+	return_tid_list(p_acs, &tid_list, &q_event_list);
+	hfidd_return_q_events(p_acs, &q_event_list);
+	return_event_list(p_acs, &event_list);
+	return rc;
+}
+
+/* Report that an event has occurred. */
+int hfidd_report_event(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		enum hfi_event_type event)
+{
+	int			rc = 0;
+	struct hfidd_win_event	*win_event_p;
+	struct hfidd_q_event	*q_event_list = NULL;
+	int			num_events;
+	unsigned long		flags;
+	int			allocated = 0;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_report_event: enter event=0x%x p_acs=0x%p\n",
+		event, (void *) p_acs);
+
+	/*
+	 * Prealloc queue event entries.  We must do this because we use a
+	 * lock that keeps us from allocating storage.
+	 */
+	while (!allocated) {
+		num_events = atomic_read(&(win->num_events[event]));
+		q_event_list = hfidd_prealloc_q_events(p_acs, win,
+				num_events);
+		if ((q_event_list == NULL) && num_events) {
+			rc = -ENOMEM;
+			return rc;
+		}
+		spin_lock_irqsave(&(win->event_lock), flags);
+		if (num_events == atomic_read(&(win->num_events[event]))) {
+			allocated = 1;
+		} else {
+			/*
+			 * The number of events we allocated for does not
+			 * match the current number of events.	It must
+			 * have changed between the allocation and the lock.
+			 * We must keep trying until we get a match.
+			 */
+			spin_unlock_irqrestore(&(win->event_lock), flags);
+			hfidd_return_q_events(p_acs, &q_event_list);
+		}
+	}
+
+	/* Mark that the event has occurred and awaken each tid. */
+	for (win_event_p = win->events[event]; win_event_p != NULL;
+			win_event_p = win_event_p->next) {
+		hfidd_post_event(p_acs, win_event_p->tid_info,
+				event, event_mask[event], &q_event_list);
+	}
+	spin_unlock_irqrestore(&(win->event_lock), flags);
+	hfidd_return_q_events(p_acs, &q_event_list);
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_report_event: type=0x%x rc=%d\n", event, rc);
+	return rc;
+}
+
+/* Clean up event handling when a window closes. */
+int hfidd_events_clean(struct hfidd_acs *p_acs, struct hfidd_window *win)
+{
+	int			rc = 0;
+	int			i;
+	struct hfidd_win_event	*win_event_p;
+	struct hfidd_win_event	*win_event_list = NULL;
+	struct hfidd_win_event	*next_win_event_p;
+	struct hfidd_tid_info	*tid_info;
+	struct hfidd_tid_info	*next_tid_info;
+	struct hfidd_tid_info	*tid_list = NULL;
+	int			num_events;
+	unsigned long		flags;
+	int			allocated = 0;
+	struct hfidd_q_event	*q_event_list = NULL;
+	int			loop_count = 0;
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_clean: enter p_acs=0x%p\n", (void *)p_acs);
+
+	/*
+	 * Prealloc queue event entries.  We must do this because we use a
+	 * ock that keeps us from allocating storage.
+	 */
+	while (!allocated) {
+		num_events = atomic_read(&win->num_tids);
+		q_event_list = hfidd_prealloc_q_events(p_acs, win,
+				num_events);
+		if ((q_event_list == NULL) && num_events) {
+			rc = -ENOMEM;
+			return rc;
+		}
+		spin_lock_irqsave(&(win->event_lock), flags);
+		if (num_events == atomic_read(&win->num_tids)) {
+			allocated = 1;
+		} else {
+			/*
+			 * The number of events we allocated for does not
+			 * match the current number of tids.  It must
+			 * have changed between the allocation and the lock.
+			 * We must keep trying until we get a match.
+			 */
+			spin_unlock_irqrestore(&(win->event_lock), flags);
+			hfidd_return_q_events(p_acs, &q_event_list);
+		}
+	}
+
+	/* Return all of the win_info structures. */
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		for (win_event_p = win->events[i]; win_event_p != NULL;
+				win_event_p = next_win_event_p) {
+			next_win_event_p = win_event_p->next;
+			win_event_p->next = win_event_list;
+			win_event_list = win_event_p;
+		}
+		win->events[i] = NULL;
+		atomic_set(&win->num_events[i], 0);
+	}
+
+	/* Return tid_info structures. */
+	for (tid_info = win->tid_list; tid_info != NULL;
+			tid_info = next_tid_info) {
+		/* Wake up the waiting task if necessary. */
+		hfidd_events_wakeup(p_acs, tid_info, &q_event_list);
+		next_tid_info = tid_info->next;
+		if (atomic_read(&win->num_tids) > 0)
+			atomic_dec(&win->num_tids);
+		tid_info->next = tid_list;
+		tid_list = tid_info;
+	}
+	win->tid_list = NULL;
+	atomic_set(&win->num_tids, 0);
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		win->funcs[i].function_p.use.kptr = NULL;
+		win->funcs[i].parameter.use.kptr = NULL;
+	}
+
+	/* Wait for all threads to finish. */
+	spin_unlock_irqrestore(&(win->event_lock), flags); /* Must disable or
+							will hang */
+	while ((atomic_read(&win->event_wait_count) > 0) &&
+			(loop_count < HFIDD_EVENT_CLEANUP_LOOP_COUNT)) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HFIDD_EVENT_CLEANUP_DELAY);
+		loop_count++;
+	}
+	atomic_set(&win->event_wait_count, 0);
+
+	return_event_list(p_acs, &win_event_list);
+	return_tid_list(p_acs, &tid_list, &q_event_list);
+	hfidd_return_q_events(p_acs, &q_event_list);
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_events_clean: rc=%d\n", rc);
+	return rc;
+}
+
+int hfidd_callback_register(struct hfidd_acs *p_acs, struct hfi_reg_events *arg)
+{
+	struct hfi_reg_events	reg_events;
+	struct hfidd_window	*win;
+	int			rc;
+
+	/* Copy in client info from user */
+	memcpy(&reg_events, arg, sizeof(reg_events));
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_callback_register: enter type=0x%x win=0x%x "
+		"events=0x%x\n", reg_events.type, reg_events.window,
+		reg_events.info.func.index);
+
+	/* Verify inputs */
+	if (reg_events.type != FUNCTIONS_FOR_EVENTS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_register: invalid type = "
+			"0x%x\n", reg_events.type);
+		return -EINVAL;
+	}
+	if (reg_events.info.func.index == HFIDD_HFI_READY_REG) {
+		rc = hfidd_hfi_ready_registration(p_acs, &reg_events);
+		return rc;
+	}
+
+	if ((reg_events.window <  min_hfi_windows(p_acs)) ||
+	    (reg_events.window >= max_hfi_windows(p_acs))) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_register: invalid win = "
+			"0x%x\n", reg_events.window);
+		return -EINVAL;
+	}
+
+	if (reg_events.info.func.index >= HFIDD_NUM_EVENT_TYPES) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_register: invalid events = "
+			"0x%x\n", reg_events.info.func.index);
+		return -EINVAL;
+	}
+
+	win = hfi_window(p_acs, reg_events.window);
+	spin_lock(&(win->win_lock));
+	if (win->state == WIN_AVAILABLE) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_register: inv state "
+			"wi=0x%x st=0x%x\n",
+			win->index, win->state);
+		spin_unlock(&(win->win_lock));
+		return -EINVAL;
+	}
+	spin_unlock(&(win->win_lock));
+
+	/* fill in function pointer and parameter */
+	win->funcs[reg_events.info.func.index].function_p.use.kptr =
+			reg_events.info.func.function_p.use.kptr;
+	win->funcs[reg_events.info.func.index].parameter.use.kptr  =
+			reg_events.info.func.parameter.use.kptr;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hfidd_callback_register);
+
+int hfidd_callback_unregister(struct hfidd_acs *p_acs,
+				struct hfi_reg_events *arg)
+{
+	struct hfi_reg_events	reg_events;
+	struct hfidd_window	*win;
+
+	/* Copy in client info from user */
+	memcpy(&reg_events, arg, sizeof(reg_events));
+
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_callback_unregister: enter type=0x%x win=0x%x "
+		"events=0x%x\n", reg_events.type, reg_events.window,
+		reg_events.info.func.index);
+
+	/* Verify inputs */
+	if (reg_events.type != FUNCTIONS_FOR_EVENTS) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_unregister: invalid type = "
+			"0x%x\n", reg_events.type);
+		return -EINVAL;
+	}
+	if (reg_events.info.func.index == HFIDD_HFI_READY_REG) {
+		hfidd_hfi_ready_unregistration(p_acs, &reg_events);
+		return 0;
+	}
+
+	if ((reg_events.window <  min_hfi_windows(p_acs)) ||
+	    (reg_events.window >= max_hfi_windows(p_acs))) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_unregister: invalid win = "
+			"0x%x\n", reg_events.window);
+		return -EINVAL;
+	}
+
+	if (reg_events.info.func.index >= HFIDD_NUM_EVENT_TYPES) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_unregister: invalid events = "
+			"0x%x\n", reg_events.info.func.index);
+		return -EINVAL;
+	}
+
+	win = hfi_window(p_acs, reg_events.window);
+	spin_lock(&(win->win_lock));
+	if ((win->state != WIN_OPENED) &&
+	    (win->state != WIN_ERROR)  &&
+	    (win->state != WIN_HERROR)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_unregister: inv state "
+			"wi=0x%x st=0x%x\n",
+			win->index, win->state);
+		spin_unlock(&(win->win_lock));
+		return -EINVAL;
+	}
+	spin_unlock(&(win->win_lock));
+
+	win->funcs[reg_events.info.func.index].function_p.use.kptr = NULL;
+	win->funcs[reg_events.info.func.index].parameter.use.kptr  = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hfidd_callback_unregister);
+
+int hfidd_callback_event(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		enum hfi_event_type event,
+		unsigned int data1,
+		unsigned int *data2_p)
+{
+	dev_printk(KERN_INFO, p_acs->hfidd_dev,
+		"hfidd_callback_event: enter event=0x%x, win_p=0x%llx\n",
+		event, (unsigned long long)win);
+
+	if (win->funcs[event].function_p.use.kptr == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_callback_event: NULL function ptr, "
+			"event=0x%x, win_p=0x%llx\n",
+			event, (unsigned long long)win);
+		return -EINVAL;
+	}
+
+	/* calling function */
+	((hfi_event_func_ptr)win->funcs[event].function_p.use.kptr)
+		(win->funcs[event].parameter.use.kptr,
+		data1, data2_p);
+	return 0;
+}
+
+static int hfidd_hfi_ready_registration(struct hfidd_acs *p_acs,
+				struct hfi_reg_events *reg)
+{
+	struct hfidd_hfi_ready_req *req;
+
+	if (p_acs->state == HFI_AVAIL) {
+		/* notify kernel user */
+		return ((hfi_event_func_ptr)reg->info.func.function_p.use.kptr)
+			(reg->info.func.parameter.use.kptr, 0, 0);
+	} else {
+		/* Alloc entry */
+		req = kzalloc(sizeof(*req), GFP_KERNEL);
+		if (req == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_hfi_ready_registration: kzalloc failed\n");
+			return -ENOMEM;
+		}
+
+		/* Fill the entry for the list */
+		req->func.index = reg->info.func.index;
+		req->func.function_p.use.kptr =
+				reg->info.func.function_p.use.kptr;
+		req->func.parameter.use.kptr =
+				reg->info.func.parameter.use.kptr;
+		list_add(&(req->list), &(p_acs->hfi_ready_reg_list));
+	}
+
+	return 0;
+}
+
+static void hfidd_hfi_ready_unregistration(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *reg)
+{
+	struct hfidd_hfi_ready_req *req;
+	struct list_head        *q;
+	struct list_head        *pos;
+
+	list_for_each_safe(pos, q, &p_acs->hfi_ready_reg_list) {
+		req = list_entry(pos,
+			struct hfidd_hfi_ready_req, list);
+		if ((req->func.function_p.use.kptr ==
+		     reg->info.func.function_p.use.kptr) &&
+		    (req->func.parameter.use.kptr ==
+		     reg->info.func.parameter.use.kptr)) {
+				list_del(pos);
+				kfree(req);
+				break;
+		}
+	}
+
+	return;
+}
+
+void hfidd_notify_hfi_ready(struct hfidd_acs *p_acs)
+{
+	struct hfidd_hfi_ready_req *req;
+	struct list_head        *q;
+	struct list_head        *pos;
+
+	list_for_each_safe(pos, q, &p_acs->hfi_ready_reg_list) {
+		req = list_entry(pos,
+			struct hfidd_hfi_ready_req, list);
+
+		dev_printk(KERN_INFO, p_acs->hfidd_dev,
+			"hfidd_notify_hfi_ready: Calling Kernel user\n");
+
+		/* Calling IP function */
+		((hfi_event_func_ptr)req->func.function_p.use.kptr)
+			(req->func.parameter.use.kptr, 0, 0);
+		list_del(pos);
+		kfree(req);
+	}
+}
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 603feb8..12e3857 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -180,6 +180,40 @@ static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
 				(struct hfi_window_info *) buf);
 		break;
 
+	case HFIDD_REQ_EVENT_REGISTER:
+		if (cmd.req_len != sizeof(struct hfi_reg_events)) {
+			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_reg_events), cmd.req);
+			return -EINVAL;
+		}
+		if (is_userspace)
+			rc = hfidd_events_register(p_acs,
+					(struct hfi_reg_events *) buf);
+		else
+			rc = hfidd_callback_register(p_acs,
+					(struct hfi_reg_events *) buf);
+		break;
+
+	case HFIDD_REQ_EVENT_UNREGISTER:
+		if (cmd.req_len != sizeof(struct hfi_reg_events)) {
+			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_reg_events), cmd.req);
+			return -EINVAL;
+		}
+		if (is_userspace)
+			rc = hfidd_events_unregister(p_acs,
+				(struct hfi_reg_events *) buf);
+		else
+			rc = hfidd_callback_unregister(p_acs,
+				(struct hfi_reg_events *) buf);
+		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,
@@ -349,6 +383,7 @@ int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop)
 {
 	int rc = 0;
 
+	INIT_LIST_HEAD(&(p_acs->hfi_ready_reg_list));
 	rc = hfidd_dds_init(p_acs, &(p_acs->dds));
 	p_acs->dds.num_d_windows = HFI_DYN_WINS_DEFAULT;
 	return rc;
diff --git a/drivers/net/hfi/core/hfidd_intr.c b/drivers/net/hfi/core/hfidd_intr.c
index 253de27..38f35f5 100644
--- a/drivers/net/hfi/core/hfidd_intr.c
+++ b/drivers/net/hfi/core/hfidd_intr.c
@@ -33,15 +33,45 @@
 #include <linux/hfi/hfidd_internal.h>
 #include "hfidd_proto.h"
 
+/* Post window event */
+static int hfidd_post_window_event(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p, enum hfi_event_type event)
+{
+	int rc = 0;
+
+	if (win_p->state == WIN_OPENED) {
+		if (win_p->funcs[event].function_p.use.kptr != NULL) {
+			rc = hfidd_callback_event(p_acs, win_p, event,
+					win_p->index, 0);
+		} else {
+			rc = hfidd_report_event(p_acs, win_p, event);
+		}
+		if (rc) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_post_window_event: failed to "
+				"post event %d win 0x%x rc 0x%x\n",
+				event, win_p->index, rc);
+		}
+	}
+	return rc;
+}
+
 static irqreturn_t send_intr_handler(int irq, void *data)
 {
 	struct hfidd_window *win_p = data;
 	struct hfidd_acs *p_acs;
+	int rc;
 
 	p_acs = hfidd_global.p_acs[win_p->ai];
 	if (p_acs == NULL)
 		return IRQ_HANDLED;
-
+	rc = hfidd_post_window_event(p_acs, win_p, HFIDD_SEND);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"send_intr_handler: failed post send event, "
+			"rc %d for win 0x%llx\n",
+			rc, (unsigned long long) win_p);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -49,11 +79,19 @@ static irqreturn_t recv_intr_handler(int irq, void *data)
 {
 	struct hfidd_window *win_p = data;
 	struct hfidd_acs *p_acs;
+	int		rc;
 
 	p_acs = hfidd_global.p_acs[win_p->ai];
 	if (p_acs == NULL)
 		return IRQ_HANDLED;
 
+	rc = hfidd_post_window_event(p_acs, win_p, HFIDD_RECV);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"recv_intr_handler: failed post recv event, "
+			"rc %d for win 0x%llx\n",
+			rc, (unsigned long long) win_p);
+	}
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index af88f0b..89f9639 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -73,6 +73,20 @@ int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
 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);
+int hfidd_events_register(struct hfidd_acs *p_acs, struct hfi_reg_events *arg);
+int hfidd_events_unregister(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *arg);
+int hfidd_callback_register(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *arg);
+int hfidd_callback_unregister(struct hfidd_acs *p_acs,
+		struct hfi_reg_events *arg);
+int hfidd_report_event(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		enum hfi_event_type event);
+int hfidd_callback_event(struct hfidd_acs *p_acs, struct hfidd_window *win,
+		enum hfi_event_type event, unsigned int data1,
+		unsigned int *data2_p);
+int hfidd_events_clean(struct hfidd_acs *p_acs, struct hfidd_window *win);
+void hfidd_notify_hfi_ready(struct hfidd_acs *p_acs);
 int hfidd_init_win_interrupt(struct hfidd_acs *p_acs,
 		struct hfidd_window *win_p);
 void hfidd_clear_win_interrupt(struct hfidd_window *win_p);
@@ -104,5 +118,5 @@ 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);
-
+long long hfi_query_window(u64 unit_id, u64 win_id, u64 *state);
 #endif
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 752cd11..ced669b 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -314,6 +314,8 @@ static inline int hfi_validate_window_id(struct hfidd_acs *p_acs,
 static inline void hfi_restore_window_parm(struct hfidd_acs *p_acs,
 		struct hfidd_window *win_p)
 {
+	int i;
+
 	if (win_p->type != HFIDD_RESERVE_WIN) {
 		win_p->type   = HFIDD_DYNAMIC_WIN;
 		win_p->job_id = 0;
@@ -325,6 +327,12 @@ static inline void hfi_restore_window_parm(struct hfidd_acs *p_acs,
 	}
 	win_p->pid   = 0;
 	win_p->is_ip = 0;
+
+
+	for (i = 0; i < HFIDD_NUM_EVENT_TYPES; i++) {
+		win_p->funcs[i].function_p.use.kptr = NULL;
+		win_p->funcs[i].parameter.use.kptr  = NULL;
+	}
 }
 
 /* Validate window number and type for open window request */
@@ -1075,6 +1083,13 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 	win_p->state = WIN_OPENED;
 	spin_unlock(&(win_p->win_lock));
 
+	/*
+	 * Increment so that any waiting threads that wake up realize
+	 * they are dealing with a window that has been reopened
+	 */
+	atomic_inc(&win_p->open_close_count);
+	hfidd_events_clean(p_acs, win_p);
+
 	kfree(local_p);
 	return rc;
 
@@ -1130,6 +1145,12 @@ int hfidd_close_window_internal(struct hfidd_acs *p_acs,
 		goto hfidd_close_window_internal_err0;
 	}
 
+	/* Wake up threads waiting for terminate event. */
+	rc = hfidd_report_event(p_acs, win_p, HFIDD_TERMINATE);
+	if (rc)
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"close_window_internal: report event failed "
+			"rc=0x%x\n", rc);
 	spin_lock(&(win_p->win_lock));
 
 	/* Make sure state is open or error state. */
@@ -1184,6 +1205,9 @@ int hfidd_close_window_internal(struct hfidd_acs *p_acs,
 	hfi_restore_window_parm(p_acs, win_p);
 	spin_unlock(&win_p->win_lock);
 
+	atomic_inc(&win_p->open_close_count);
+	hfidd_events_clean(p_acs, win_p);
+
 	dev_printk(KERN_INFO, p_acs->hfidd_dev,
 		"close_window_internal: type=0x%x state=0x%x JobID=0x%x\n",
 		win_p->type, win_p->state, win_p->job_id);
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 3b2d032..7f87674 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -97,6 +97,9 @@ struct fifo_info {
 #define HFIDD_RESERVE_WIN	3	/* Must be reserved by job scheduler */
 #define HFIDD_DYNAMIC_WIN	4	/* First come, first served. Window# is
 						returned */
+#define HFIDD_DST_BCST_WIN		0
+#define HFIDD_DST_BCST_ISR		0x3FFF
+
 struct hfi_client_info {
 	struct hfi_req_hdr	hdr;
 
@@ -138,6 +141,67 @@ enum hfi_event_type {
 	HFIDD_NUM_EVENT_TYPES	= 12
 };
 
+#define HFIDD_SEND_EVENT			0x00000100
+#define HFIDD_RECV_EVENT			0x00000200
+#define HFIDD_WIN_ERROR_EVENT			0x00000400
+#define HFIDD_HFI_ERROR_EVENT			0x00000800
+#define HFIDD_TERMINATE_EVENT			0x00001000
+#define HFIDD_RELEASE_WINDOW_EVENT		0x00002000
+#define HFIDD_CAU_ERROR_EVENT			0x00004000
+#define HFIDD_ICS_ERROR_EVENT			0x00008000
+#define HFIDD_HFI_READY_REG_EVENT		0x00010000
+#define HFIDD_ROUTE_CHANGE_EVENT		0x00020000
+#define HFIDD_IP_TRC_LVL_EVENT			0x00040000
+#define HFIDD_POOL_SIZE_EVENT			0x00080000
+#define HFIDD_LOWEST_EVENT			HFIDD_SEND_EVENT
+#define HFIDD_ALL_EVENTS			0x000FFF00
+
+enum hfi_event_hndlr_type {
+	WAIT_FOR_EVENTS		= 1,	/* Wait for events */
+	SIGNAL_EVENTS		= 2,	/* Event notification by signal */
+	FUNCTIONS_FOR_EVENTS	= 3	/* Callback functions */
+};
+
+typedef int (*hfi_event_func_ptr)(void *parm, unsigned int win,
+		unsigned int *ext);
+
+struct hfi_callback_func {	/* Callback funcs for kernel windows */
+	enum hfi_event_type	index;		/* index of callback type */
+	unsigned int		pad;
+	struct hfi_64b		function_p;	/* function ptr */
+	struct hfi_64b		parameter;	/* parameter to pass in */
+};
+
+/*
+ * HFIDD_REQ_EVENT_REGISTER/HFIDD_REQ_EVENT_UNREGISTER: event
+ * registration/unregistration
+ */
+#define HFI_MAX_BUF_EVENTS	8	/* # event buffers for signal version */
+struct hfi_event_buffer	{		/* For reporting events with signals */
+	unsigned int		tag;
+	enum hfi_event_type	current_event;
+};
+
+struct hfi_reg_events {
+	struct hfi_req_hdr		hdr;
+	unsigned int			window;
+	enum hfi_event_hndlr_type	type;
+	union {
+		unsigned int		events;
+		struct hfi_callback_func func;
+		struct hfi_64b eb;	/* Pointer to event buffer in
+					user space (signal only) */
+	} info;
+};
+
+/* HFIDD_REQ_EVENT_WAIT: wait on event */
+struct hfi_wait_events {
+	struct hfi_req_hdr	hdr;
+	unsigned int		window;		/* Window for events */
+	unsigned int		events;		/* events to wait for */
+	unsigned int		out_events;	/* events received */
+};
+
 #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 e96142a..18f0fb4 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -72,6 +72,16 @@
 #define HFIDD_DEV_NAME		"hfi"
 #define HFIDD_CLASS_NAME	"hfi"
 
+#define HFIDD_EVENT_CLEANUP_LOOP_COUNT	1000
+#define HFIDD_EVENT_CLEANUP_DELAY	10
+
+/* window event */
+struct hfidd_q_event {
+	struct list_head	list;
+	struct hfidd_q_event	*next;		/* For preallocation list */
+	unsigned int		event;
+};
+
 struct hfidd_dds {
 	unsigned int		version;	/* HFI adapter type */
 	unsigned long long	misc_base_address; /* Misc user base address */
@@ -83,6 +93,33 @@ struct hfidd_dds {
 	unsigned long long	fw_ec_level;	/* Firmware Level */
 };
 
+struct hfidd_tid_info {
+	struct hfidd_tid_info	*next;
+	unsigned long long	tid;		/* Thread id */
+	struct semaphore	tid_sem;
+	unsigned int		registered_events;
+	unsigned int		deferred_events;/* Events that have occurred
+						   but have not yet been
+						   reported */
+	enum hfi_event_hndlr_type type;
+	struct list_head	event_list;	/* List of hfidd_event */
+	wait_queue_head_t	event_wait;	/* Used to wait and post
+						   threads */
+	unsigned int		tag;		/* Used with eb */
+	struct task_struct	*eb_xd;		/* For cross task write */
+	struct hfi_event_buffer	*eb;		/* Pointer to event
+						   buffer location in
+						   user space (for
+						   signal handling) */
+	struct task_struct	*th;		/* task_struct associated with
+						   tid */
+};
+
+struct hfidd_win_event {
+	struct hfidd_win_event	*next;
+	struct hfidd_tid_info	*tid_info;
+};
+
 struct hfidd_fifo {
 	unsigned long long	eaddr;
 	unsigned long long	size;
@@ -92,6 +129,7 @@ struct hfidd_fifo {
 
 struct hfidd_window {
 	spinlock_t		win_lock;	/* lock for window */
+	spinlock_t		event_lock;	/* lock for event handling */
 	int			index;
 	unsigned int		type;		/* dynamic/scheduled */
 	int			state;
@@ -117,10 +155,40 @@ struct hfidd_window {
 							   OPEN_WINDOW hcall */
 	unsigned long long	mmio_regs;		/* logical addr from
 							   OPEN WINDOW hcall */
+	atomic_t		open_close_count;	/*Incremented every time
+						   a window is opened or
+						   closed.  This is used for
+						   event handling to determine
+						   if a close occurred while
+						   waiting. */
+	struct hfi_callback_func funcs[HFIDD_NUM_EVENT_TYPES];	/* Callback
+						   funcs for IP */
+	struct hfidd_win_event	*events[HFIDD_NUM_EVENT_TYPES];	/* Each
+						   array entry points to a
+						   list.  Each list entry
+						   contains a tid that should
+						   be posted when this event
+						   occurs. */
+	atomic_t	num_events[HFIDD_NUM_EVENT_TYPES]; /* Number
+						   of elements in each of the
+						   events lists */
+	struct hfidd_tid_info	*tid_list;	/* List of tids registered for
+						   events on this window */
+	atomic_t		num_tids;	/* Number of tids in
+						   tid_list */
+	atomic_t		event_wait_count;/* Indicates how many
+						    threads are waiting for
+						    events on this window */
 	struct hfidd_vlxmem	*sfifo_x_tab;
 	struct hfidd_vlxmem	*rfifo_x_tab;
 };
 
+struct hfidd_hfi_ready_req {
+	struct list_head		list;
+	struct hfi_callback_func	func;
+};
+
+
 #define HFI_DEVICE_NAME_MAX 64
 /* hfi global */
 struct hfidd_acs {
@@ -131,6 +199,7 @@ struct hfidd_acs {
 	unsigned int		state;
 
 	unsigned int		isr;
+	struct list_head	hfi_ready_reg_list;
 
 	struct hfidd_window	**win;
 	struct device		*hfidd_dev;
diff --git a/include/linux/hfi/hfidd_requests.h b/include/linux/hfi/hfidd_requests.h
index a7a38da..002ae7f 100644
--- a/include/linux/hfi/hfidd_requests.h
+++ b/include/linux/hfi/hfidd_requests.h
@@ -37,4 +37,7 @@
 #define HFIDD_REQ_QUERY_DD_INFO			0x00001004
 #define HFIDD_REQ_CLOSE_WINDOW			0x00000a02
 
+#define HFIDD_REQ_EVENT_REGISTER		0x00000702
+#define HFIDD_REQ_EVENT_UNREGISTER		0x00000703
+
 #endif /* _HFIDD_REQUESTS_H_ */
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 23/27] HFI: Define packet header formats and window register offsets
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (20 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 22/27] HFI: Add event notifications dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 24/27] HFI: hf network driver dykmanj
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 24/27] HFI: hf network driver
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (21 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 23/27] HFI: Define packet header formats and window register offsets dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 22:26   ` Stephen Hemminger
  2011-03-02 22:40   ` Ben Hutchings
  2011-03-02 21:10 ` [PATCH 25/27] HFI: hf fifo transmit paths dykmanj
                   ` (3 subsequent siblings)
  26 siblings, 2 replies; 38+ messages in thread
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

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

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

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

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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 25/27] HFI: hf fifo transmit paths
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (22 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 24/27] HFI: hf network driver dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 26/27] HFI: hf fifo receive path dykmanj
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 26/27] HFI: hf fifo receive path
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (23 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 25/27] HFI: hf fifo transmit paths dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:10 ` [PATCH 27/27] HFI: hf ethtool support dykmanj
  2011-03-03 14:07 ` [PATCH 01/27] HFI: skeleton driver Christoph Hellwig
  26 siblings, 0 replies; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* [PATCH 27/27] HFI: hf ethtool support
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (24 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 26/27] HFI: hf fifo receive path dykmanj
@ 2011-03-02 21:10 ` dykmanj
  2011-03-02 21:52   ` Ben Hutchings
  2011-03-03 14:07 ` [PATCH 01/27] HFI: skeleton driver Christoph Hellwig
  26 siblings, 1 reply; 38+ messages in thread
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

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	[flat|nested] 38+ messages in thread

* Re: [PATCH 27/27] HFI: hf ethtool support
  2011-03-02 21:10 ` [PATCH 27/27] HFI: hf ethtool support dykmanj
@ 2011-03-02 21:52   ` Ben Hutchings
  2011-03-02 22:28     ` Jim Dykman
  0 siblings, 1 reply; 38+ messages in thread
From: Ben Hutchings @ 2011-03-02 21:52 UTC (permalink / raw)
  To: dykmanj
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
	Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
	Sarah J. Sheppard

On Wed, 2011-03-02 at 16:10 -0500, dykmanj@linux.vnet.ibm.com wrote:
[...]
> +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;

The error code should be -EINVAL, I think.

> +	}
> +}
> +
> +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));
[...]

This may result in word tearing, particularly if this driver can be
built for a 32-bit system.  Since the stats appear to be updated
asynchronously in the data path, you may have to declare them as
unsigned long and then extend them to 64-bit in hf_get_ethtool_stats().

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 02/27] HFI: Add HFI adapter control structure
  2011-03-02 21:09 ` [PATCH 02/27] HFI: Add HFI adapter control structure dykmanj
@ 2011-03-02 22:21   ` Stephen Hemminger
  2011-03-02 22:44     ` Ben Hutchings
  0 siblings, 1 reply; 38+ messages in thread
From: Stephen Hemminger @ 2011-03-02 22:21 UTC (permalink / raw)
  To: dykmanj
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard

On Wed,  2 Mar 2011 16:09:48 -0500
dykmanj@linux.vnet.ibm.com wrote:

> 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;
> +}

If these were not in a separate file the could be marked as static.

Doing a return; on last line of a void function is considered poor
style since it is unnecessary.

-- 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 24/27] HFI: hf network driver
  2011-03-02 21:10 ` [PATCH 24/27] HFI: hf network driver dykmanj
@ 2011-03-02 22:26   ` Stephen Hemminger
  2011-04-18  3:21     ` Jim Dykman
  2011-03-02 22:40   ` Ben Hutchings
  1 sibling, 1 reply; 38+ messages in thread
From: Stephen Hemminger @ 2011-03-02 22:26 UTC (permalink / raw)
  To: dykmanj
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard

On Wed,  2 Mar 2011 16:10:10 -0500
dykmanj@linux.vnet.ibm.com wrote:

> +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;
> +};

You don't need net_stats in this structure if you use
the standard netdev->stats structure instead.

You won't need hf_get_stats then..

-- 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 27/27] HFI: hf ethtool support
  2011-03-02 21:52   ` Ben Hutchings
@ 2011-03-02 22:28     ` Jim Dykman
  2011-03-02 22:32       ` David Miller
  0 siblings, 1 reply; 38+ messages in thread
From: Jim Dykman @ 2011-03-02 22:28 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
	Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
	Sarah J. Sheppard

On 3/2/2011 4:52 PM, Ben Hutchings wrote:
> On Wed, 2011-03-02 at 16:10 -0500, dykmanj@linux.vnet.ibm.com wrote:
> [...]
>> +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;
> 
> The error code should be -EINVAL, I think.

ok

> 
>> +	}
>> +}
>> +
>> +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));
> [...]
> 
> This may result in word tearing, particularly if this driver can be
> built for a 32-bit system.  Since the stats appear to be updated
> asynchronously in the data path, you may have to declare them as
> unsigned long and then extend them to 64-bit in hf_get_ethtool_stats().
> 
> Ben.
> 

It is 64-bit only, but we forgot to mention that in Kconfig.

Thanks.

Jim Dykman


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 27/27] HFI: hf ethtool support
  2011-03-02 22:28     ` Jim Dykman
@ 2011-03-02 22:32       ` David Miller
  0 siblings, 0 replies; 38+ messages in thread
From: David Miller @ 2011-03-02 22:32 UTC (permalink / raw)
  To: dykmanj
  Cc: bhutchings, netdev, piyushc, fcchang, wscadden, winstonc,
	sakolish, jian, clsoto, sjsheppa

From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Date: Wed, 02 Mar 2011 17:28:42 -0500

> It is 64-bit only, but we forgot to mention that in Kconfig.

Please do not mark this driver as 64-bit only in the Kconfig if
at all possible, as that will markedly decrease the build test
coverage of this driver.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 24/27] HFI: hf network driver
  2011-03-02 21:10 ` [PATCH 24/27] HFI: hf network driver dykmanj
  2011-03-02 22:26   ` Stephen Hemminger
@ 2011-03-02 22:40   ` Ben Hutchings
  2011-04-18  3:21     ` Jim Dykman
  1 sibling, 1 reply; 38+ messages in thread
From: Ben Hutchings @ 2011-03-02 22:40 UTC (permalink / raw)
  To: dykmanj
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
	Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
	Sarah J. Sheppard

On Wed, 2011-03-02 at 16:10 -0500, dykmanj@linux.vnet.ibm.com wrote:
> 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.
[...]
> 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.

You actually call it hf_if!  But why it is not called hfi_ip?

> 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
[...]
> +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);

Try running:

# ifconfig lo down
# ifconfig lo up

and watch the explosion.

You need to check that this is actually one of your devices.  I've done
this by comparing netdev->netdev_ops pointer.

[...]
> +static int hf_alloc_tx_resource(struct hf_if *net_if)
> +{
[...]
> +	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);
[...]

The netdev_err() and netif_err() (etc.) macros are the standard way to
format messages relating to a net device.

[...]
> +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));

These two assignments should perhaps include an explicit cpu_to_be16().

[...]
> +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;

I'm a bit puzzled by this.  Do you not trust the networking core to keep
track of your device state?

> +	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);
> +}

Please use the stats contained in struct net_device instead.

> +static int hf_change_mtu(struct net_device *netdev, int new_mtu)
> +{
> +	if ((new_mtu <= 0) || (new_mtu > HF_NET_MTU))
> +		return -ERANGE;

Since this interface apparently only passes ARP and IPv4, the minimum
MTU should be the minimum for IPv4, which is 68.  (The spec says 576 but
the Linux IPv4 implementation uses this value.)

[...]
> +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;

You can't provide NETIF_F_SG without checksum offload.

> +	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;

Use ERR_PTR() instead of writing this sort of cast yourself.

[...]
> +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)));

Whyever are you formatting the error like this?  Use %ld and remove the
(u64) cast.


> +
> +				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;

Use the error code you were given:

	return PTR_ERR(net);

> +}
> +
> +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;

Redundant statement is redundant.

> +}
[...]
> --- /dev/null
> +++ b/include/linux/hfi/hf_if.h
[...]
> +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;

It looks like you're relying on gcc to treat a set of bitfields with
type u32 and only 16 bits assigned as having a size of 2 in a packed
structure.  This might be true now, but I wouldn't want to rely on that
being true for later versions.  Why not define the set of bitfields with
type u16?

Also the above appears to assume big-endian byte and bit order.

[...]
> +#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)
[...]

This looks familiar!  Maybe you should just use the existing struct
ethhdr?

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 02/27] HFI: Add HFI adapter control structure
  2011-03-02 22:21   ` Stephen Hemminger
@ 2011-03-02 22:44     ` Ben Hutchings
  2011-04-18  3:21       ` Jim Dykman
  0 siblings, 1 reply; 38+ messages in thread
From: Ben Hutchings @ 2011-03-02 22:44 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: dykmanj, netdev, Piyush Chaudhary, Fu-Chung Chang,
	William S. Cadden, Wen C. Chen, Scot Sakolish, Jian Xiao,
	Carol L. Soto, Sarah J. Sheppard

On Wed, 2011-03-02 at 14:21 -0800, Stephen Hemminger wrote:
> On Wed,  2 Mar 2011 16:09:48 -0500
> dykmanj@linux.vnet.ibm.com wrote:
> 
> > 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
[...]
> > +void hfidd_free_adapter(struct hfidd_acs *p_acs)
> > +{
> > +	kfree(p_acs);
> > +	p_acs = NULL;
> > +	return;
> > +}
> 
> If these were not in a separate file the could be marked as static.

I assume they're intending to add some more interesting code here in the
next installment.

> Doing a return; on last line of a void function is considered poor
> style since it is unnecessary.

Assigning to a local variable just before returning is also silly.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 01/27] HFI: skeleton driver
  2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
                   ` (25 preceding siblings ...)
  2011-03-02 21:10 ` [PATCH 27/27] HFI: hf ethtool support dykmanj
@ 2011-03-03 14:07 ` Christoph Hellwig
  26 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2011-03-03 14:07 UTC (permalink / raw)
  To: dykmanj
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard

On Wed, Mar 02, 2011 at 04:09:47PM -0500, dykmanj@linux.vnet.ibm.com wrote:
> From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
> 
> Device driver Makefile & Kconfig plumbing plus simple mod_init and mod_exit

It would help a lot if you could explain what the heck HFI is.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 02/27] HFI: Add HFI adapter control structure
  2011-03-02 22:44     ` Ben Hutchings
@ 2011-04-18  3:21       ` Jim Dykman
  0 siblings, 0 replies; 38+ messages in thread
From: Jim Dykman @ 2011-04-18  3:21 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Stephen Hemminger, netdev, Piyush Chaudhary, Fu-Chung Chang,
	William S. Cadden, Wen C. Chen, Scot Sakolish, Jian Xiao,
	Carol L. Soto, Sarah J. Sheppard

On 3/2/2011 5:44 PM, Ben Hutchings wrote:
> On Wed, 2011-03-02 at 14:21 -0800, Stephen Hemminger wrote:
>> On Wed,  2 Mar 2011 16:09:48 -0500
>> dykmanj@linux.vnet.ibm.com wrote:
>>
>>> 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
> [...]
>>> +void hfidd_free_adapter(struct hfidd_acs *p_acs)
>>> +{
>>> +	kfree(p_acs);
>>> +	p_acs = NULL;
>>> +	return;
>>> +}
>>
>> If these were not in a separate file the could be marked as static.
> 
> I assume they're intending to add some more interesting code here in the
> next installment.
> 

Yes, there is more to come.

>> Doing a return; on last line of a void function is considered poor
>> style since it is unnecessary.
> 
> Assigning to a local variable just before returning is also silly.
> 
> Ben.
> 
Both removed in v2. 

Jim


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 24/27] HFI: hf network driver
  2011-03-02 22:26   ` Stephen Hemminger
@ 2011-04-18  3:21     ` Jim Dykman
  0 siblings, 0 replies; 38+ messages in thread
From: Jim Dykman @ 2011-04-18  3:21 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
	Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
	Sarah J. Sheppard

On 3/2/2011 5:26 PM, Stephen Hemminger wrote:
> On Wed,  2 Mar 2011 16:10:10 -0500
> dykmanj@linux.vnet.ibm.com wrote:
> 
>> +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;
>> +};
> 
> You don't need net_stats in this structure if you use
> the standard netdev->stats structure instead.
> 
> You won't need hf_get_stats then..
> 
Ok, done in v2

Jim


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 24/27] HFI: hf network driver
  2011-03-02 22:40   ` Ben Hutchings
@ 2011-04-18  3:21     ` Jim Dykman
  0 siblings, 0 replies; 38+ messages in thread
From: Jim Dykman @ 2011-04-18  3:21 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
	Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
	Sarah J. Sheppard

On 3/2/2011 5:40 PM, Ben Hutchings wrote:
> On Wed, 2011-03-02 at 16:10 -0500, dykmanj@linux.vnet.ibm.com wrote:
>> 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.
> [...]
>> 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.
> 
> You actually call it hf_if!  But why it is not called hfi_ip?
> 
That IS a good name. Ok, we'll call it hfi_ip.

>> 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
> [...]
>> +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);
> 
> Try running:
> 
> # ifconfig lo down
> # ifconfig lo up
> 
> and watch the explosion.
> 
> You need to check that this is actually one of your devices.  I've done
> this by comparing netdev->netdev_ops pointer.
> 
Check added to v2.

> [...]
>> +static int hf_alloc_tx_resource(struct hf_if *net_if)
>> +{
> [...]
>> +	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);
> [...]
> 
> The netdev_err() and netif_err() (etc.) macros are the standard way to
> format messages relating to a net device.
> 
Fixed in v2

> [...]
>> +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));
> 
> These two assignments should perhaps include an explicit cpu_to_be16().
> 
The HFIs live in a chip on the motherboard of one specific Power7 server.
Power arch is big-endian. I'm going to leave this asis.

> [...]
>> +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;
> 
> I'm a bit puzzled by this.  Do you not trust the networking core to keep
> track of your device state?
> 
Removed in v2.
>> +	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);
>> +}
> 
> Please use the stats contained in struct net_device instead.
> 
Ok
>> +static int hf_change_mtu(struct net_device *netdev, int new_mtu)
>> +{
>> +	if ((new_mtu <= 0) || (new_mtu > HF_NET_MTU))
>> +		return -ERANGE;
> 
> Since this interface apparently only passes ARP and IPv4, the minimum
> MTU should be the minimum for IPv4, which is 68.  (The spec says 576 but
> the Linux IPv4 implementation uses this value.)
> 
Ok
> [...]
>> +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;
> 
> You can't provide NETIF_F_SG without checksum offload.
> 
Removed in v2.
>> +	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;
> 
> Use ERR_PTR() instead of writing this sort of cast yourself.
> 
Ok.
> [...]
>> +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)));
> 
> Whyever are you formatting the error like this?  Use %ld and remove the
> (u64) cast.
> 
> 
Fixed in v2.
>> +
>> +				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;
> 
> Use the error code you were given:
> 
> 	return PTR_ERR(net);
> 
Also fixed in v2.
>> +}
>> +
>> +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;
> 
> Redundant statement is redundant.
> 
These are all removed in v2.

>> +}
> [...]
>> --- /dev/null
>> +++ b/include/linux/hfi/hf_if.h
> [...]
>> +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;
> 
> It looks like you're relying on gcc to treat a set of bitfields with
> type u32 and only 16 bits assigned as having a size of 2 in a packed
> structure.  This might be true now, but I wouldn't want to rely on that
> being true for later versions.  Why not define the set of bitfields with
> type u16?
> 
They're not 16 bits long either, so I'm changing these to unsigned int

> Also the above appears to assume big-endian byte and bit order.
> 
Again, Power arch is big endian and HFI is Power-only.

> [...]
>> +#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)
> [...]
> 
> This looks familiar!  Maybe you should just use the existing struct
> ethhdr?
> 
Ok
> Ben.
> 

Jim


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2011-04-18  3:21 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-02 21:09 [PATCH 01/27] HFI: skeleton driver dykmanj
2011-03-02 21:09 ` [PATCH 02/27] HFI: Add HFI adapter control structure dykmanj
2011-03-02 22:21   ` Stephen Hemminger
2011-03-02 22:44     ` Ben Hutchings
2011-04-18  3:21       ` Jim Dykman
2011-03-02 21:09 ` [PATCH 03/27] HFI: Add device_create/device_destroy calls for HFI devices dykmanj
2011-03-02 21:09 ` [PATCH 04/27] HFI: Find HFI devices in the device tree dykmanj
2011-03-02 21:09 ` [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls dykmanj
2011-03-02 21:09 ` [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs dykmanj
2011-03-02 21:09 ` [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls dykmanj
2011-03-02 21:09 ` [PATCH 08/27] HFI: DD request framework and first HFI DD request dykmanj
2011-03-02 21:09 ` [PATCH 09/27] HFI: Add HFI window resource tracking dykmanj
2011-03-02 21:09 ` [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request dykmanj
2011-03-02 21:09 ` [PATCH 11/27] HFI: Check window number/assign window number dykmanj
2011-03-02 21:09 ` [PATCH 12/27] HFI: Sanity check send and receive fifo parameters dykmanj
2011-03-02 21:09 ` [PATCH 13/27] HFI: Send and receive fifo address translation dykmanj
2011-03-02 21:10 ` [PATCH 14/27] HFI: Add hypercalls to create/modify/free page tables in the nMMU dykmanj
2011-03-02 21:10 ` [PATCH 15/27] HFI: Set up nMMU page tables for the send and receive fifos dykmanj
2011-03-02 21:10 ` [PATCH 16/27] HFI: Add window open hypervisor call dykmanj
2011-03-02 21:10 ` [PATCH 17/27] HFI: Set up and call the open window hypercall dykmanj
2011-03-02 21:10 ` [PATCH 18/27] HFI: Map window registers into user process dykmanj
2011-03-02 21:10 ` [PATCH 19/27] HFI: Add window close request dykmanj
2011-03-02 21:10 ` [PATCH 20/27] HFI: Close window hypervisor call dykmanj
2011-03-02 21:10 ` [PATCH 21/27] HFI: Add send and receive interrupts dykmanj
2011-03-02 21:10 ` [PATCH 22/27] HFI: Add event notifications dykmanj
2011-03-02 21:10 ` [PATCH 23/27] HFI: Define packet header formats and window register offsets dykmanj
2011-03-02 21:10 ` [PATCH 24/27] HFI: hf network driver dykmanj
2011-03-02 22:26   ` Stephen Hemminger
2011-04-18  3:21     ` Jim Dykman
2011-03-02 22:40   ` Ben Hutchings
2011-04-18  3:21     ` Jim Dykman
2011-03-02 21:10 ` [PATCH 25/27] HFI: hf fifo transmit paths dykmanj
2011-03-02 21:10 ` [PATCH 26/27] HFI: hf fifo receive path dykmanj
2011-03-02 21:10 ` [PATCH 27/27] HFI: hf ethtool support dykmanj
2011-03-02 21:52   ` Ben Hutchings
2011-03-02 22:28     ` Jim Dykman
2011-03-02 22:32       ` David Miller
2011-03-03 14:07 ` [PATCH 01/27] HFI: skeleton driver Christoph Hellwig

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.