Netdev List
 help / color / mirror / Atom feed
* [PATCH v3 05/27] HFI: The first few HFI-specific hypervisor calls
From: dykmanj @ 2011-04-21 21:38 UTC (permalink / raw)
  To: netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com>

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

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

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

diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 6fe4e60..4e6cbd6 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -2,5 +2,6 @@
 # Makefile for the HFI device driver for IBM eServer System p
 #
 hfi_core-objs:=	hfidd_adpt.o \
-		hfidd_init.o
+		hfidd_init.o \
+		hfidd_hcalls.o
 obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index f309a02..fd4a0cb 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)
 {
 
@@ -66,3 +78,130 @@ void hfidd_free_adapter(struct hfidd_acs *p_acs)
 {
 	kfree(p_acs);
 }
+
+/* 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 78a5763..c7c67ca 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.5


^ permalink raw reply related

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

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

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

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


^ permalink raw reply related

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

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

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

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

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


^ permalink raw reply related

* [PATCH v3 08/27] HFI: DD request framework and first HFI DD request
From: dykmanj @ 2011-04-21 21:38 UTC (permalink / raw)
  To: netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com>

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 3dcaa8f..df79ae9 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -36,6 +36,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");
@@ -59,11 +60,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 c7c67ca..0cc8c88 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.5


^ permalink raw reply related

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

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

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

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 61ed559..40d5aaf 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -46,6 +46,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)
@@ -70,6 +71,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)
 {
@@ -128,6 +161,8 @@ static void hfidd_destroy_devices(void)
 		hfidd_global.p_acs[i] = NULL;
 		hfidd_global.acs_cnt--;
 	}
+	for (i = 0; i <= MAX_HFIS; i++)
+		hfidd_rmdev(i);
 }
 
 /*
@@ -155,6 +190,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 66765a5..956e6b2 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.5


^ permalink raw reply related

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

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

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

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

diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index fd4a0cb..487ef0e 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -162,6 +162,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 bbfc477..3dcaa8f 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -320,30 +320,43 @@ 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);
 }
 
 /*
  * 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) {
@@ -374,6 +387,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) {
@@ -402,6 +424,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.5


^ permalink raw reply related

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

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

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

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

diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 66ea5da..001f6d5 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,9 +39,18 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
 void hfidd_free_windows(struct hfidd_acs *p_acs);
 int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
 int hfidd_age_hcall(u64 time_start);
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		unsigned int is_userspace, struct hfidd_vlxmem *xlat_p);
 int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr,
 		unsigned int is_userspace, unsigned int length,
 		unsigned long long *page_size);
+int hfidd_get_page_num(struct hfidd_acs *p_acs, void *start_addr,
+		unsigned long long len, unsigned long long page_sz,
+		unsigned int *pg_num_p);
 int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		struct hfi_client_info *user_p,
 		struct hfi_client_info *out_p);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 5a4f395..de2e56d 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,125 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
 	return 0;
 }
 
+static int hfi_xlate_fifos(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	/*
+	 * add 4K(finish vector) to the sfifo size then call to
+	 * xlate when return, restore the sfifo size back..............
+	 */
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	rc = hfidd_fifo_xlat(p_acs, &(client_p->sfifo), is_userspace,
+			win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = hfidd_fifo_xlat(p_acs, &(client_p->rfifo), is_userspace,
+			win_p->rfifo_x_tab);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+			"rc = 0x%x\n", rc);
+		goto hfi_xlate_fifos_err1;
+	}
+
+hfi_xlate_fifos_err1:
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	hfidd_fifo_unxlat(p_acs, &(client_p->sfifo), is_userspace,
+			win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+
+	return rc;
+}
+
+int hfi_unxlate_fifos(struct hfidd_acs *p_acs, unsigned int is_userspace,
+		struct hfidd_window *win_p, struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	hfidd_fifo_unxlat(p_acs, &(client_p->rfifo),
+			is_userspace, win_p->rfifo_x_tab);
+
+	client_p->sfifo.size += PAGE_SIZE_4K;
+	hfidd_fifo_unxlat(p_acs, &(client_p->sfifo),
+			is_userspace, win_p->sfifo_x_tab);
+	client_p->sfifo.size -= PAGE_SIZE_4K;
+
+	return rc;
+}
+
+static inline void hfi_free_xlate_tab(struct hfidd_window *win_p)
+{
+	kfree(win_p->sfifo_x_tab);
+	win_p->sfifo_x_tab	= NULL;
+	kfree(win_p->rfifo_x_tab);
+	win_p->rfifo_x_tab	= NULL;
+}
+
+static int hfi_alloc_xlate_tab(struct hfidd_acs *p_acs,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	win_p->sfifo_x_tab = kzalloc(sizeof(*(win_p->sfifo_x_tab)),
+			GFP_KERNEL);
+	if (win_p->sfifo_x_tab == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_xlate_tab: kzalloc sfifo_x_tab failed\n");
+		return -ENOMEM;
+	}
+
+	win_p->rfifo_x_tab = kzalloc(sizeof(*(win_p->rfifo_x_tab)),
+			GFP_KERNEL);
+	if (win_p->rfifo_x_tab == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_xlate_tab: kzalloc rfifo_x_tab failed\n");
+		goto hfi_alloc_xlate_tab_err1;
+	}
+
+	return 0;
+
+hfi_alloc_xlate_tab_err1:
+	kfree(win_p->sfifo_x_tab);
+	win_p->sfifo_x_tab = NULL;
+	return -ENOMEM;
+}
+
+static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
+		unsigned int is_userspace,
+		struct hfidd_window *win_p,
+		struct hfi_client_info *client_p)
+{
+	int	rc = 0;
+
+	rc = hfi_alloc_xlate_tab(p_acs, win_p, client_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_win_resource: hfi_alloc_xlate_tab "
+			"failed, rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = hfi_xlate_fifos(p_acs, is_userspace, win_p, client_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfi_alloc_win_resource: hfi_xlate_fifos "
+			"failed, rc = 0x%x\n", rc);
+		hfi_free_xlate_tab(win_p);
+		return rc;
+	}
+
+	return 0;
+}
+
 /*
  * Allows an user/kernel window to send/receive network traffic thru HFI
  * adapter. This function will allocate the system resources needed to open
@@ -371,6 +490,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 {
 	int			rc = 0;
 	struct hfi_client_info	*local_p = NULL;
+	struct hfidd_window	*win_p = NULL;
 
 	/* Allocate local data structure */
 	local_p = kmalloc(sizeof(struct hfi_client_info), GFP_KERNEL);
@@ -398,9 +518,21 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
 		goto hfidd_open_window_func_err1;
 	}
 
+	win_p = hfi_window(p_acs, local_p->window);
+
+	rc = hfi_alloc_win_resource(p_acs, is_userspace, win_p, local_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_open_window_func: hfi_alloc_win_resource "
+			"failed, rc = 0x%x\n", rc);
+		goto hfidd_open_window_func_err2;
+	}
+
 	kfree(local_p);
 	return rc;
 
+hfidd_open_window_func_err2:
+	hfi_restore_window_parm(p_acs, win_p);
 hfidd_open_window_func_err1:
 	kfree(local_p);
 	return rc;
diff --git a/drivers/net/hfi/core/hfidd_xlat.c b/drivers/net/hfi/core/hfidd_xlat.c
index 23236cc..760d7e6 100644
--- a/drivers/net/hfi/core/hfidd_xlat.c
+++ b/drivers/net/hfi/core/hfidd_xlat.c
@@ -129,3 +129,213 @@ out1:
 	kfree(page_list);
 	return rc;
 }
+
+int hfidd_get_page_num(struct hfidd_acs *p_acs,
+		void			*start_addr,
+		unsigned long long	len,
+		unsigned long long	page_sz,
+		unsigned int		*pg_num_p)
+{
+	int			rc = 0;
+	int			pg_shift_count;
+	unsigned long long	address_mask;
+	unsigned long long	offset_mask;
+	unsigned long long	offset;
+
+	if (pg_num_p == NULL || len == 0) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_num: len=%llx pg_num_p=0x%llx\n",
+			len, (unsigned long long)pg_num_p);
+		return -EINVAL;
+	}
+
+	/*
+	 * Pre-Calculate Masks and shift count:
+	 */
+	if (page_sz == PAGE_SIZE_4K) {
+		offset_mask			= PAGE_MASK_4K;
+		pg_shift_count			= PAGE_SHIFT_4K;
+	} else if (page_sz == PAGE_SIZE_64K) {
+		offset_mask			= PAGE_MASK_64K;
+		pg_shift_count			= PAGE_SHIFT_64K;
+	} else if (page_sz == PAGE_SIZE_16M) {
+		offset_mask			= PAGE_MASK_16M;
+		pg_shift_count			= PAGE_SHIFT_16M;
+	} else if (page_sz == PAGE_SIZE_4G) {
+		offset_mask			= PAGE_MASK_4G;
+		pg_shift_count			= PAGE_SHIFT_4G;
+	} else {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_get_page_num: invalid page_sz 0x%llx "
+			"return EINVAL\n", page_sz);
+		return -EINVAL;
+	}
+	address_mask = ~offset_mask;
+
+	/*
+	 * Calculate the buffer offsets into the first page:
+	 */
+	offset = (unsigned long long)start_addr & offset_mask;
+	*pg_num_p  = (len + offset + offset_mask) >> pg_shift_count;
+
+	return rc;
+}
+
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+	unsigned int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	unsigned int		num_pages;
+	unsigned long long	page_size;
+	int			rc = 0;
+
+	rc = hfidd_get_page_size(p_acs, fifo_in->eaddr.use.kptr, is_userspace,
+			fifo_in->size, &page_size);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fill_xlat_tab: hfidd_get_page_size failed, "
+			" rc=0x%x\n", rc);
+		return rc;
+	}
+
+	/* Get num of pages based in buffer page size */
+	rc = hfidd_get_page_num(p_acs, fifo_in->eaddr.use.kptr,
+			fifo_in->size, page_size, &num_pages);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fill_xlat_tab:: hfidd_get_page_num return "
+			"rc 0x%x\n", rc);
+		return rc;
+	}
+
+	xlat_p->v_addr = (caddr_t)(fifo_in->eaddr.use.kptr);
+	xlat_p->e_addr = (caddr_t)(fifo_in->eaddr.use.allu & ~(page_size - 1));
+	xlat_p->page_sz = page_size;
+	xlat_p->num_page = num_pages;
+	xlat_p->len = num_pages * page_size;
+	xlat_p->num_kpage = (xlat_p->len) / PAGE_SIZE;
+
+	return 0;
+}
+
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	int			rc = 0;
+	int			i;
+	unsigned int		num_pages, pg_code;
+	unsigned long long	page_size;
+	unsigned long long	*l_pages;
+	struct page		**page_list;
+	unsigned int		hw_page = 0;
+
+	if ((fifo_in == NULL) || (xlat_p == NULL)) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: Invalid fifo_in 0x%llx\n",
+			(unsigned long long)fifo_in);
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: Invalid xlat_p 0x%llx\n",
+			(unsigned long long)xlat_p);
+		return -EINVAL;
+	}
+
+	rc = hfidd_fill_xlat_tab(p_acs, fifo_in, is_userspace, xlat_p);
+	if (rc) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: hfidd_fill_xlat_tab failed, "
+			"rc = 0x%x\n", rc);
+		return rc;
+	}
+
+	/* num_page is number of pages of page_sz */
+	num_pages = xlat_p->num_page;
+	page_size = xlat_p->page_sz;
+
+	l_pages = vmalloc(num_pages * sizeof(unsigned long long));
+	if (l_pages == NULL) {
+		dev_printk(KERN_ERR, p_acs->hfidd_dev,
+			"hfidd_fifo_xlat: vmalloc failed for l_pages\n");
+		return -ENOMEM;
+	}
+
+	if (!is_userspace) {
+		void *curr_addr = xlat_p->e_addr;
+
+		for (i = 0; i < num_pages; i++) {
+			l_pages[i] = __pa(curr_addr);
+			curr_addr += page_size;
+		}
+	} else {
+		/* For page_list use number of kernel pages */
+		page_list = kzalloc(xlat_p->num_kpage * sizeof(struct page *),
+			GFP_KERNEL);
+		if (page_list == NULL) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_fifo_xlat: kzalloc failed "
+				"for page_list\n");
+			rc = -ENOMEM;
+			goto out_err0;
+		}
+
+		down_read(&current->mm->mmap_sem);
+		rc = get_user_pages(current, current->mm,
+				(unsigned long long)(xlat_p->e_addr),
+				xlat_p->num_kpage, 1, 0, /* write, !force */
+				page_list, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (rc < xlat_p->num_kpage) {
+			dev_printk(KERN_ERR, p_acs->hfidd_dev,
+				"hfidd_fifo_xlat: get_user_pages failed, "
+				"rc = 0x%x\n", rc);
+			goto out_err1;
+		}
+
+		for (i = 0; i < num_pages;) {
+			l_pages[hw_page] = page_to_phys(page_list[i]);
+			hw_page++;
+			i += (page_size / PAGE_SIZE);
+		}
+
+		xlat_p->page_list = (void *)page_list;
+	}
+
+	xlat_p->l_pages = (void *)l_pages;
+	xlat_p->map_page_sz = page_size;
+	xlat_p->m_addr = xlat_p->e_addr;
+	xlat_p->num_page_sz.num_code.fields.pg_num = num_pages;
+	encode_pg_sz(page_size, &pg_code);
+	xlat_p->num_page_sz.num_code.fields.pg_code =
+		(pg_code << HFI_PAGE_CODE_SHIFT);
+	return 0;
+
+out_err1:
+	if (rc > 0) {
+		for (i = 0; i < rc; i++)
+			page_cache_release(page_list[i]);
+		rc = -EINVAL;
+	}
+	kfree(page_list);
+out_err0:
+	vfree(l_pages);
+	return rc;
+}
+
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+		int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+	int		rc = 0;
+	int		i;
+	struct page	**page_list;
+
+	if (!is_userspace)
+		return 0;
+	page_list = (struct page **)xlat_p->page_list;
+	if (page_list != NULL) {
+		/* For page list we used number of kernel pages */
+		for (i = 0; i < xlat_p->num_kpage; i++)
+			page_cache_release(page_list[i]);
+		kfree(page_list);
+		xlat_p->page_list = NULL;
+	}
+	return rc;
+}
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index a41825f..8eab059 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -74,4 +74,32 @@
 #define PAGE_MASK_4G		(PAGE_SIZE_4G - 1)
 #define PAGE_MASK_16G		(PAGE_SIZE_16G - 1)
 
+#define PAGE_CODE_4K	0x00000000
+#define PAGE_CODE_64K	0x00000001
+#define PAGE_CODE_1M	0x00000002
+#define PAGE_CODE_16M	0x00000003
+#define PAGE_CODE_256M	0x00000004
+#define PAGE_CODE_4G	0x00000005
+#define PAGE_CODE_INVAL	0x00000007
+#define PAGE_CODE_MASK	0x00000007
+
+static inline void encode_pg_sz(unsigned long long pg_sz,
+		unsigned int *pg_sz_code)
+{
+	if (pg_sz == PAGE_SIZE_4K)
+		*pg_sz_code = PAGE_CODE_4K;
+	else if (pg_sz == PAGE_SIZE_64K)
+		*pg_sz_code = PAGE_CODE_64K;
+	else if (pg_sz == PAGE_SIZE_1M)
+		*pg_sz_code = PAGE_CODE_1M;
+	else if (pg_sz == PAGE_SIZE_16M)
+		*pg_sz_code = PAGE_CODE_16M;
+	else if (pg_sz == PAGE_SIZE_256M)
+		*pg_sz_code = PAGE_CODE_256M;
+	else if (pg_sz == PAGE_SIZE_4G)
+		*pg_sz_code = PAGE_CODE_4G;
+	else
+		*pg_sz_code = PAGE_CODE_INVAL;
+}
+
 #endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 2a374e6..57140a0 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -42,6 +42,8 @@
 #define H_NMMU_START			0xF028
 #define H_NMMU_STOP			0xF02C
 
+#define HFI_PAGE_CODE_SHIFT	28
+
 #define EEH_QUERY	1
 #define COMP_QUERY	2
 
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 290e809..8e097d0 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.5


^ permalink raw reply related

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

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

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

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/Kconfig              |    1 +
 drivers/net/hfi/Makefile         |    1 +
 drivers/net/hfi/ip/Kconfig       |    9 +
 drivers/net/hfi/ip/Makefile      |    6 +
 drivers/net/hfi/ip/hf_proto.h    |   48 +++
 drivers/net/hfi/ip/hfi_ip_main.c |  613 ++++++++++++++++++++++++++++++++++++++
 include/linux/hfi/hfi_ip.h       |  148 +++++++++
 include/linux/if_arp.h           |    1 +
 8 files changed, 827 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_proto.h
 create mode 100644 drivers/net/hfi/ip/hfi_ip_main.c
 create mode 100644 include/linux/hfi/hfi_ip.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1abbfd9..ddae700 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3437,5 +3437,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..422782a
--- /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 IP over HFI. It transports IP
+	packets over HFI.
+
+	To compile the driver as a module, choose M here. The module
+	will be called hfi_ip.
diff --git a/drivers/net/hfi/ip/Makefile b/drivers/net/hfi/ip/Makefile
new file mode 100644
index 0000000..90c7dea
--- /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) += hfi_ip.o
+
+hfi_ip-objs :=	hfi_ip_main.o
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
new file mode 100644
index 0000000..b4133b7
--- /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,
+		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/drivers/net/hfi/ip/hfi_ip_main.c b/drivers/net/hfi/ip/hfi_ip_main.c
new file mode 100644
index 0000000..0c1ebd7
--- /dev/null
+++ b/drivers/net/hfi/ip/hfi_ip_main.c
@@ -0,0 +1,613 @@
+/*
+ * hfi_ip_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/hfi_ip.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 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_net *net)
+{
+	struct hf_if *net_if = &(net->hfif);
+	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) {
+		netdev_err(net->netdev, "%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) {
+		netdev_err(net->netdev,
+			"%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_net *net)
+{
+	struct hf_if *net_if = &(net->hfif);
+
+	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) {
+		netdev_err(net->netdev,
+			"%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 (rc)
+		goto alloc_resource_err0;
+
+	rc = hf_alloc_rx_resource(net);
+	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_net *net, struct hfidd_acs *p_acs)
+{
+	struct hf_if *net_if = &(net->hfif);
+	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) {
+		netdev_err(net->netdev,
+			"%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_net *net,
+			     struct hfidd_acs *p_acs)
+{
+	struct hf_if		*net_if = &(net->hfif);
+	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),
+			&(net_if->client));
+	if (rc) {
+		netdev_err(net->netdev,
+			"%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)) {
+		netdev_err(net->netdev,
+			"%s: hf_open_ip_window: fail to map doorbell\n",
+			net_if->name);
+		hf_close_ip_window(net, 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;
+	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, p_acs);
+	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(&(netdev->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);
+
+	spin_lock(&(net_if->lock));
+	if (net_if->state == HF_NET_OPEN) {
+		hf_close_ip_window(net, 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;
+}
+
+static int hf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	if ((new_mtu <= 68) || (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 ethhdr		*hwhdr_p;
+
+	skb_push(skb, ETH_HLEN);
+
+	hwhdr_p = (struct ethhdr *)(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,
+};
+
+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	= ETH_HLEN;
+	netdev->addr_len	= ETH_ALEN;
+	netdev->needed_headroom	= 0;
+
+	netdev->header_ops	= &hf_header_ops;
+	netdev->netdev_ops	= &hf_netdev_ops;
+
+	memcpy(netdev->broadcast, hfi_bcast_addr, ETH_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 ERR_PTR(-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) {
+		netdev_err(netdev, "hf_init_netdev: "
+				"failed to register netdev=hfi%d:hf%d, "
+				"rc = 0x%x\n", ai, idx, rc);
+		free_netdev(netdev);
+		return ERR_PTR(-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 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) && (netdev->netdev_ops == &hf_netdev_ops)) {
+		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 int __init hf_init_module(void)
+{
+	u32		idx, ai;
+	int		rc;
+	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"
+						" %ld\n",
+						idx, ai, PTR_ERR(net));
+
+				goto err_out;
+			}
+
+			hf_ginfo.net[idx][ai] = net;
+		}
+	}
+
+	register_inetaddr_notifier(&hf_inet_notifier);
+
+	printk(KERN_INFO "hfi_ip module loaded\n");
+	return 0;
+
+err_out:
+	rc = PTR_ERR(net);
+	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 rc;
+}
+
+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/include/linux/hfi/hfi_ip.h b/include/linux/hfi/hfi_ip.h
new file mode 100644
index 0000000..6b6a74c
--- /dev/null
+++ b/include/linux/hfi/hfi_ip.h
@@ -0,0 +1,148 @@
+/*
+ * hfi_ip.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 _HFI_IP_H_
+#define _HFI_IP_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 */
+	unsigned int	immediate_len:7;/* In bytes */
+	unsigned int	num_desc:3;     /* number of descriptors */
+					/* Logical Port ID: */
+	unsigned int	lpid_valid:1;   /* set by sending HFI */
+	unsigned int	lpid:4;         /* set by sending HFI */
+	/* Ethernet Service Header is 113 bits, which is 14 bytes + 1 bit */
+	unsigned int	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_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;
+};
+
+/* 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.5


^ permalink raw reply related

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

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

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

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


^ permalink raw reply related

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

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

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

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


^ permalink raw reply related

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

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

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/ip/Makefile      |    2 +-
 drivers/net/hfi/ip/hf_ethtool.c  |  136 ++++++++++++++++++++++++++++++++++++++
 drivers/net/hfi/ip/hf_proto.h    |    1 +
 drivers/net/hfi/ip/hfi_ip_main.c |   36 +++++++++-
 include/linux/hfi/hfi_ip.h       |   32 +++++++++-
 5 files changed, 201 insertions(+), 6 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 90c7dea..28a4a51 100644
--- a/drivers/net/hfi/ip/Makefile
+++ b/drivers/net/hfi/ip/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_HFI_IP) += hfi_ip.o
 
-hfi_ip-objs :=	hfi_ip_main.o
+hfi_ip-objs :=	hfi_ip_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..204a1bf
--- /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/hfi_ip.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 -EINVAL;
+	}
+}
+
+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_proto.h b/drivers/net/hfi/ip/hf_proto.h
index 022512a..3b2b23b 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/drivers/net/hfi/ip/hfi_ip_main.c b/drivers/net/hfi/ip/hfi_ip_main.c
index 6b2ec3f..4b897d3 100644
--- a/drivers/net/hfi/ip/hfi_ip_main.c
+++ b/drivers/net/hfi/ip/hfi_ip_main.c
@@ -208,6 +208,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;
 }
@@ -218,6 +219,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;
 }
 
@@ -381,6 +383,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);
 
@@ -390,6 +395,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++;
 	}
 }
 
@@ -507,7 +515,7 @@ static int hf_net_open(struct net_device *netdev)
 	struct hfidd_acs	*p_acs = HF_ACS(net_if);
 
 	memset(&(netdev->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;
@@ -614,6 +622,7 @@ static inline int hf_check_hdr_version(struct hf_net *net,
 			"hf_check_hdr_version: hdr version 0x%x "
 			"does not match 0x%x\n",
 			hf_hdr->version, HF_PROTO_HDR_VERSION);
+		net->hfif.eth_stats.rx_version_mismatch++;
 		net->netdev->stats.rx_dropped++;
 		return -EINVAL;
 	}
@@ -710,6 +719,7 @@ static void hf_recv_ip_with_payload(struct hf_net *net,
 	netdev->stats.rx_packets++;
 	netdev->stats.rx_bytes += skb->len;
 
+	net_if->eth_stats.payload_recv++;
 	netif_receive_skb(skb);
 }
 
@@ -717,6 +727,8 @@ 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:
@@ -731,6 +743,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->netdev->stats.rx_dropped++;
 		break;
 	}
@@ -767,6 +780,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->netdev->stats.rx_dropped++;
 		}
 
@@ -782,6 +796,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--;
@@ -791,6 +806,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);
 
@@ -860,9 +876,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 |
@@ -871,6 +888,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;
 		}
 	}
@@ -957,6 +975,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;
 	}
 
@@ -1051,7 +1070,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->netdev->stats.tx_packets++;
 	net->netdev->stats.tx_bytes += msg_len;
 
@@ -1079,6 +1099,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;
 	}
 
@@ -1119,8 +1140,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++;
 }
 
 static int hf_change_mtu(struct net_device *netdev, int new_mtu)
@@ -1207,6 +1232,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 */
@@ -1215,7 +1241,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;
 }
@@ -1248,6 +1275,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/include/linux/hfi/hfi_ip.h b/include/linux/hfi/hfi_ip.h
index ec87300..d4317ee 100644
--- a/include/linux/hfi/hfi_ip.h
+++ b/include/linux/hfi/hfi_ip.h
@@ -42,6 +42,7 @@
 #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>
@@ -150,6 +151,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   */
@@ -160,7 +190,6 @@ struct hf_if {
 	spinlock_t		lock;			/* lock for state */
 	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;
@@ -172,6 +201,7 @@ struct hf_if {
 	struct sk_buff		**tx_skb;		/* array to store tx
 							   2k skb */
 	void			*sfifo_finishvec;
+	struct hf_ethtool_stats eth_stats;
 };
 
 /* Private structure for HF inetrface */
-- 
1.7.3.5


^ permalink raw reply related

* [PATCH v3 18/27] HFI: Map window registers into user process
From: dykmanj @ 2011-04-21 21:38 UTC (permalink / raw)
  To: netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com>

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 c20277b..5d319a1 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -874,6 +874,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
@@ -940,6 +978,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;
@@ -951,7 +997,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));
@@ -963,6 +1009,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.5


^ permalink raw reply related

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

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

Signed-off-by:  Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by:  Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by:  Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by:  William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by:  Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by:  Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by:  Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by:  Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by:  Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
 drivers/net/hfi/core/hfidd_hcalls.c |   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 3cfe5c3..fd692eb 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -459,6 +459,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
@@ -1005,7 +1042,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 */
@@ -1019,7 +1056,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));
@@ -1031,9 +1068,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:
@@ -1103,6 +1142,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.5


^ permalink raw reply related

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

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  |  141 ++++++++++++++++++++++++++++++++++++
 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, 254 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 dc280bc..1abbfd9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3436,4 +3436,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 01b604a..e9ea418 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -304,3 +304,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..9498faf
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -0,0 +1,141 @@
+/*
+ * 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/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 rc;
+	}
+
+	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 75cf611..df925b4 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.5


^ permalink raw reply related

* [PATCH v3 00/27] HFI: minimal device driver/ip driver
From: dykmanj @ 2011-04-21 21:38 UTC (permalink / raw)
  To: netdev; +Cc: Jim Dykman

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

The HFI ("Host Fabric Interface") network interface is the internal cluster
fabric of IBM's PERCS supercomputer. The hardware design is under US export
control, so we cannot release hardware specs. There is a writeup of
publically available information about the system available here:
http://sourceforge.net/projects/hfidevicedriver/files/docs/hfi_general_desc_v2.1.txt

hfi_core contains the resource management to set up communications paths for
network traffic. Calls are provided for kernel drivers, and also for setting
up direct user-space access to HFI windows.
hfi_ip contains the kernel network driver.

The driver has been running in the lab for several months. The full patch is
around 22000 lines, so we've split out a minimal device/network driver that
can send and receive through the simplest path.  Once that much gets accepted
we'll start adding on to it.

Patches are against net-next-2.6.

Jim Dykman

Changelog:
----------
v3:	Don't include <linux/version.h>
	hfidd_mod_init: return -1; --> return rc;
	hfidd_alloc_adapter: pass snprintf xiHFI_DEVICE_NAME_MAX, 
		not HFI_DEVICE_NAME_MAX -1
	change HFI_DEVICE_NAME_MAX from 64 to 8
v2:
        Remove return; at the end of void funcs
        hfidd_free_adapter: p_acs = NULL unneccesssary, remove
        remove net_stats, and use netdev->stats, remove hf_get_stats
        rename network driver to hfi_ip
        hf_inet_event: NETDEV_UP needs to check event is for us, check
                netdev->netdev_ops == ours
        change printk()s to netdev_err() and friends
        hf_net_close: remove redundant CLOSE check
        hf_change_mtu: minimum mtu should be 68
        remove NETIF_F_SG flag
        hf_init_netdev: Use ERR_PTR
        hf_init_module: %ld / formatting
                        pass up return code from failed call
        use unsigned int instead of u32 for bit fields <32 bits
        use struct ethhdr instead of hf_hwhdr
        hf_get_sset_count: default return -EINVAL not -EOPNOTSUPP
        Remove "hfidd_callback_event: enter" message that printed on every
                recv interrupt
        hfidd_destroy_devices: hfidd_rmdev() after hfidd_free_adapter() so
                dev_printk doesn't oops on rmmod



^ permalink raw reply

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

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

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

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

diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index 487ef0e..8e3f5af 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,9 +86,63 @@ err_exit0:
 
 void hfidd_free_adapter(struct hfidd_acs *p_acs)
 {
+	hfidd_free_windows(p_acs);
 	kfree(p_acs);
 }
 
+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;
+}
+
 /* 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 0cc8c88..420d55a 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 8
 /* 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.5


^ permalink raw reply related

* [PATCH v3 17/27] HFI: Set up and call the open window hypercall
From: dykmanj @ 2011-04-21 21:38 UTC (permalink / raw)
  To: netdev
  Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang,  William S. Cadden,
	 Wen C. Chen, Scot Sakolish, Jian Xiao,  Carol L. Soto,
	 Sarah J. Sheppard
In-Reply-To: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com>

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

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

diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 6d90af6..c20277b 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,105 @@ 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;
+}
+
+/* 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 +672,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 +825,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 +856,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 +932,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.5


^ permalink raw reply related

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

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

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

diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index d181d97..bbfc477 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -318,6 +318,93 @@ 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);
+	}
+}
+
+/*
+ * 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;
@@ -338,9 +425,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();
 	return rc;
@@ -348,6 +444,7 @@ error1:
 
 static void __exit hfidd_mod_exit(void)
 {
+	hfidd_stop_adapter();
 	hfidd_destroy_devices();
 	hfidd_destroy_class();
 }
-- 
1.7.3.5


^ permalink raw reply related

* Re: [PATCHv4] usbnet: Resubmit interrupt URB once if halted
From: Alan Stern @ 2011-04-21 21:40 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: Paul Stewart, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	greg-U8xfFu+wG4EAvxtiuMwx3w
In-Reply-To: <201104212200.26551.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>

On Thu, 21 Apr 2011, Oliver Neukum wrote:

> Am Donnerstag, 21. April 2011, 16:03:34 schrieb Alan Stern:
> > On Tue, 19 Apr 2011, Paul Stewart wrote:
> 
> > > This version of the patch moves the urb submit directly into
> > > usbnet_resume.  Is it okay to submit a GFP_KERNEL urb from
> > > usbnet_resume()?
> 
> Suppose a device of two interfaces one of them storage is autosuspended.
> GFP_KERNEL in the first device to be resumed triggers a pageout to the
> suspended storage device.

True enough, I had forgotten about that.  A resume routine should 
always use GFP_NOIO, not GFP_KERNEL.

In fact this restriction is true in general, not just for USB devices 
containing a mass-storage interface.  The backing device for an evicted 
page might not be resumed until later on in the resume sequence.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* linux-next: build failure after merge of the final tree (net tree related)
From: Stephen Rothwell @ 2011-04-21 22:10 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: linux-next, linux-kernel, "Michał Mirosław"

[-- Attachment #1: Type: text/plain, Size: 439 bytes --]

Hi all,

After merging the final tree, today's linux-next build (powerpc chrp32_defconfig)
failed like this:

drivers/net/mv643xx_eth.c: In function 'port_start':
drivers/net/mv643xx_eth.c:2250: error: 'dev' undeclared (first use in this function)

Caused by commit aad59c431b77 ("net: mv643xx: convert to hw_features").

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply

* Re: [PATCH v5] net: bnx2x: convert to hw_features
From: Michał Mirosław @ 2011-04-21 22:15 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Vladislav Zolotarov, Eric Dumazet, netdev@vger.kernel.org,
	Eilon Greenstein
In-Reply-To: <1303413559.3165.55.camel@bwh-desktop>

On Thu, Apr 21, 2011 at 08:19:19PM +0100, Ben Hutchings wrote:
> 	/* Transfer changeable features to wanted_features and enable
> 	 * software offloads (GSO and GRO).
> 	 */
> 	dev->hw_features |= NETIF_F_SOFT_FEATURES;
> 	dev->features |= NETIF_F_SOFT_FEATURES;
> 	dev->wanted_features = dev->features & dev->hw_features;
> 
> This doesn't work correctly for features that are always enabled, like
> NETIF_F_HW_VLAN_RX in bnx2x, which are set in dev->features but not in
> dev->hw_features.

> The name 'hw_features' really wasn't a good choice - the obvious meaning
> and the meaning assumed by this code is 'hardware-supported features'
> and not 'hardware-supported features that can be toggled'.  And since we
> add NETIF_F_SOFT_FEATURES, it really only means 'features that can be
> toggled'.

I won't argue about hw_features name - I just couldn't find a better one.
Comment in include/linux/netdevice.h clearly explains the purpose of this
field.

wanted_features is supposed to be limited by hw_features (so that it's always
true that (hw_features & wanted_features) == wanted_features). If you have
an idea how to make that more clear, I'd be happy to update descriptions.

Best Regards,
Michał Mirosław

^ permalink raw reply

* [PATCH] iMX: Fix for missed MII interrupts and MDIO timeouts when FEC is in STOP
From: Matteo Fortini @ 2011-04-21 22:17 UTC (permalink / raw)
  To: netdev

We are experiencing unrecoverable timeouts if we disconnect a cable from the
FEC. This patch solves the issue by keeping the Ethernet enabled even in
STOP. The RM doesn't state it, but i seems that if disabled, the Ethernet is
not issuing interrupts to the core.
(See
http://forums.freescale.com/t5/i-MX-Microprocessors/iMX28-Network-MDIO-timeout-recovery-and-lost-IRQs/td-p/73309
)

The patch is against Freescale iMX tree from opensource.freescale.com/git

---
 drivers/net/fec.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d0e2e69..26ea72d 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -121,8 +121,10 @@
 #if defined(CONFIG_FEC_1588) && defined(CONFIG_ARCH_MX28)
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \
                FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER)
+#define FEC_STOP_IMASK (FEC_ENET_MII)
 #else
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_STOP_IMASK (FEC_ENET_MII)
 #endif

 /* The FEC stores dest/src/type, data, and checksum for receive packets.
@@ -1409,6 +1411,9 @@ fec_stop(struct net_device *dev)
    writel(1, fep->hwp + FEC_ECNTRL);
    udelay(10);

+    /* Reactivate the controller to get the IRQs */
+    writel(0x00000002, fep->hwp + FEC_ECNTRL);
+
 #ifdef CONFIG_ARCH_MXS
    /* Check MII or RMII */
    if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
@@ -1423,7 +1428,7 @@ fec_stop(struct net_device *dev)
    writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
    if (fep->ptimer_present)
        fec_ptp_stop(fep->ptp_priv);
-    writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+    writel(FEC_STOP_IMASK, fep->hwp + FEC_IMASK);

    netif_stop_queue(dev);
    fep->link = 0;
--
1.7.4.2

^ permalink raw reply related

* Re: linux-next: build failure after merge of the final tree (net tree related)
From: David Miller @ 2011-04-21 22:19 UTC (permalink / raw)
  To: sfr; +Cc: netdev, linux-next, linux-kernel, mirq-linux
In-Reply-To: <20110422081008.e7ebab59.sfr@canb.auug.org.au>

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Fri, 22 Apr 2011 08:10:08 +1000

> Hi all,
> 
> After merging the final tree, today's linux-next build (powerpc chrp32_defconfig)
> failed like this:
> 
> drivers/net/mv643xx_eth.c: In function 'port_start':
> drivers/net/mv643xx_eth.c:2250: error: 'dev' undeclared (first use in this function)
> 
> Caused by commit aad59c431b77 ("net: mv643xx: convert to hw_features").

I just pushed the following fix, thanks!

--------------------
mv643xx_eth: Fix build regression.

>From Stephen Rothwell:

--------------------
After merging the final tree, today's linux-next build (powerpc chrp32_defconfig)
failed like this:

drivers/net/mv643xx_eth.c: In function 'port_start':
drivers/net/mv643xx_eth.c:2250: error: 'dev' undeclared (first use in this function)

Caused by commit aad59c431b77 ("net: mv643xx: convert to hw_features").
--------------------

Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/mv643xx_eth.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 29605a3..57c2ac0 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2247,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp)
 	 * frames to RX queue #0, and include the pseudo-header when
 	 * calculating receive checksums.
 	 */
-	mv643xx_eth_set_features(dev, dev->features);
+	mv643xx_eth_set_features(mp->dev, mp->dev->features);
 
 	/*
 	 * Treat BPDUs as normal multicasts, and disable partition mode.
-- 
1.7.4.3

^ permalink raw reply related

* Re: [PATCH v2 02/27] HFI: Add HFI adapter control structure
From: Jim Dykman @ 2011-04-21 21:38 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
In-Reply-To: <1303129145.5282.1030.camel@localhost>

On 4/18/2011 8:19 AM, Ben Hutchings wrote:
> On Sun, 2011-04-17 at 23:21 -0400, dykmanj@linux.vnet.ibm.com wrote:
>> From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
>>
>> Alloc/free of hfidd_acs to track the state of each HFI
> [...]
>> --- /dev/null
>> +++ b/drivers/net/hfi/core/hfidd_adpt.c
> [...]
>> +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);
> 
> snprintf() always null-terminates so the buffer length should be
> specified as HFI_DEVICE_NAME_MAX or sizeof(p_acs->name).
> 

Ok.

> [...]
>> --- a/drivers/net/hfi/core/hfidd_init.c
>> +++ b/drivers/net/hfi/core/hfidd_init.c
> [...]
>>  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;
>>  }
> [...]
> 
> Should be 'return rc'.  Never return -1 as a generic failure; it means
> -EPERM.
> 

Ok

> Ben.
> 

Jim


^ permalink raw reply

* Re: [PATCH v5] net: bnx2x: convert to hw_features
From: Michał Mirosław @ 2011-04-21 22:41 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, Vladislav Zolotarov, Eilon Greenstein
In-Reply-To: <1303397531.3685.16.camel@edumazet-laptop>

On Thu, Apr 21, 2011 at 04:52:11PM +0200, Eric Dumazet wrote:
> Le mardi 12 avril 2011 à 21:38 +0200, Michał Mirosław a écrit :
> > Since ndo_fix_features callback is postponing features change when
> > bp->recovery_state != BNX2X_RECOVERY_DONE, netdev_update_features()
> > has to be called again when this condition changes. Previously,
> > ethtool_ops->set_flags callback returned -EBUSY in that case
> > (it's not possible in the new model).
> > 
> > Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > 
> > v5: - don't delay set_features, as it's rtnl_locked - same as recovery process
> > v4: - complete bp->rx_csum -> NETIF_F_RXCSUM conversion
> >     - add check for failed ndo_set_features in ndo_open callback
> > v3: - include NETIF_F_LRO in hw_features
> >     - don't call netdev_update_features() if bnx2x_nic_load() failed
> > v2: - comment in ndo_fix_features callback
> > ---
> I am not sure its related to these changes, but I now have in
> net-next-2.6 :

> [   23.674263] ------------[ cut here ]------------
> [   23.674266] WARNING: at net/core/dev.c:1318 dev_disable_lro+0x83/0x90()
> [   23.674270] Hardware name: ProLiant BL460c G6
> [   23.674273] Modules linked in: tg3 libphy sg
> [   23.674280] Pid: 3070, comm: sysctl Tainted: G        W   2.6.39-rc2-01242-g3ef22b9-dirty #669
> [   23.674282] Call Trace:
> [   23.674285]  [<ffffffff813b94f3>] ? dev_disable_lro+0x83/0x90
> [   23.674291]  [<ffffffff81042c9b>] warn_slowpath_common+0x8b/0xc0
> [   23.674298]  [<ffffffff81042ce5>] warn_slowpath_null+0x15/0x20
> [   23.674304]  [<ffffffff813b94f3>] dev_disable_lro+0x83/0x90
> [   23.674309]  [<ffffffff81429789>] devinet_sysctl_forward+0x199/0x210
[...]

Hmm. Looks like something is not allowing to disable LRO. Please check with
following patch so we can be sure which driver causes this.

Best Regards,
Michał Mirosław

^ permalink raw reply


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