* [PATCH 13/27] HFI: Send and receive fifo address translation
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Prepare for a hypervisor call to set up page tables in the nMMU for the
send and receive fifo.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_proto.h | 9 ++
drivers/net/hfi/core/hfidd_window.c | 132 ++++++++++++++++++++++
drivers/net/hfi/core/hfidd_xlat.c | 210 +++++++++++++++++++++++++++++++++++
include/linux/hfi/hfidd_adpt.h | 28 +++++
include/linux/hfi/hfidd_hcalls.h | 2 +
include/linux/hfi/hfidd_internal.h | 1 +
include/linux/hfi/hfidd_xlat_map.h | 91 +++++++++++++++
7 files changed, 473 insertions(+), 0 deletions(-)
create mode 100644 include/linux/hfi/hfidd_xlat_map.h
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 66ea5da..001f6d5 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,9 +39,18 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
void hfidd_free_windows(struct hfidd_acs *p_acs);
int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
int hfidd_age_hcall(u64 time_start);
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ int is_userspace, struct hfidd_vlxmem *xlat_p);
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ unsigned int is_userspace, struct hfidd_vlxmem *xlat_p);
int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr,
unsigned int is_userspace, unsigned int length,
unsigned long long *page_size);
+int hfidd_get_page_num(struct hfidd_acs *p_acs, void *start_addr,
+ unsigned long long len, unsigned long long page_sz,
+ unsigned int *pg_num_p);
int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
struct hfi_client_info *user_p,
struct hfi_client_info *out_p);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index 5a4f395..de2e56d 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -359,6 +359,125 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
return 0;
}
+static int hfi_xlate_fifos(struct hfidd_acs *p_acs,
+ unsigned int is_userspace,
+ struct hfidd_window *win_p,
+ struct hfi_client_info *client_p)
+{
+ int rc = 0;
+
+ /*
+ * add 4K(finish vector) to the sfifo size then call to
+ * xlate when return, restore the sfifo size back..............
+ */
+ client_p->sfifo.size += PAGE_SIZE_4K;
+ rc = hfidd_fifo_xlat(p_acs, &(client_p->sfifo), is_userspace,
+ win_p->sfifo_x_tab);
+ client_p->sfifo.size -= PAGE_SIZE_4K;
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+ "rc = 0x%x\n", rc);
+ return rc;
+ }
+
+ rc = hfidd_fifo_xlat(p_acs, &(client_p->rfifo), is_userspace,
+ win_p->rfifo_x_tab);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_xlate_fifos: hfidd_fifo_xlat failed, "
+ "rc = 0x%x\n", rc);
+ goto hfi_xlate_fifos_err1;
+ }
+
+hfi_xlate_fifos_err1:
+ client_p->sfifo.size += PAGE_SIZE_4K;
+ hfidd_fifo_unxlat(p_acs, &(client_p->sfifo), is_userspace,
+ win_p->sfifo_x_tab);
+ client_p->sfifo.size -= PAGE_SIZE_4K;
+
+ return rc;
+}
+
+int hfi_unxlate_fifos(struct hfidd_acs *p_acs, unsigned int is_userspace,
+ struct hfidd_window *win_p, struct hfi_client_info *client_p)
+{
+ int rc = 0;
+
+ hfidd_fifo_unxlat(p_acs, &(client_p->rfifo),
+ is_userspace, win_p->rfifo_x_tab);
+
+ client_p->sfifo.size += PAGE_SIZE_4K;
+ hfidd_fifo_unxlat(p_acs, &(client_p->sfifo),
+ is_userspace, win_p->sfifo_x_tab);
+ client_p->sfifo.size -= PAGE_SIZE_4K;
+
+ return rc;
+}
+
+static inline void hfi_free_xlate_tab(struct hfidd_window *win_p)
+{
+ kfree(win_p->sfifo_x_tab);
+ win_p->sfifo_x_tab = NULL;
+ kfree(win_p->rfifo_x_tab);
+ win_p->rfifo_x_tab = NULL;
+}
+
+static int hfi_alloc_xlate_tab(struct hfidd_acs *p_acs,
+ struct hfidd_window *win_p,
+ struct hfi_client_info *client_p)
+{
+ win_p->sfifo_x_tab = kzalloc(sizeof(*(win_p->sfifo_x_tab)),
+ GFP_KERNEL);
+ if (win_p->sfifo_x_tab == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_alloc_xlate_tab: kzalloc sfifo_x_tab failed\n");
+ return -ENOMEM;
+ }
+
+ win_p->rfifo_x_tab = kzalloc(sizeof(*(win_p->rfifo_x_tab)),
+ GFP_KERNEL);
+ if (win_p->rfifo_x_tab == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_alloc_xlate_tab: kzalloc rfifo_x_tab failed\n");
+ goto hfi_alloc_xlate_tab_err1;
+ }
+
+ return 0;
+
+hfi_alloc_xlate_tab_err1:
+ kfree(win_p->sfifo_x_tab);
+ win_p->sfifo_x_tab = NULL;
+ return -ENOMEM;
+}
+
+static int hfi_alloc_win_resource(struct hfidd_acs *p_acs,
+ unsigned int is_userspace,
+ struct hfidd_window *win_p,
+ struct hfi_client_info *client_p)
+{
+ int rc = 0;
+
+ rc = hfi_alloc_xlate_tab(p_acs, win_p, client_p);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_alloc_win_resource: hfi_alloc_xlate_tab "
+ "failed, rc = 0x%x\n", rc);
+ return rc;
+ }
+
+ rc = hfi_xlate_fifos(p_acs, is_userspace, win_p, client_p);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_alloc_win_resource: hfi_xlate_fifos "
+ "failed, rc = 0x%x\n", rc);
+ hfi_free_xlate_tab(win_p);
+ return rc;
+ }
+
+ return 0;
+}
+
/*
* Allows an user/kernel window to send/receive network traffic thru HFI
* adapter. This function will allocate the system resources needed to open
@@ -371,6 +490,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
{
int rc = 0;
struct hfi_client_info *local_p = NULL;
+ struct hfidd_window *win_p = NULL;
/* Allocate local data structure */
local_p = kmalloc(sizeof(struct hfi_client_info), GFP_KERNEL);
@@ -398,9 +518,21 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
goto hfidd_open_window_func_err1;
}
+ win_p = hfi_window(p_acs, local_p->window);
+
+ rc = hfi_alloc_win_resource(p_acs, is_userspace, win_p, local_p);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_open_window_func: hfi_alloc_win_resource "
+ "failed, rc = 0x%x\n", rc);
+ goto hfidd_open_window_func_err2;
+ }
+
kfree(local_p);
return rc;
+hfidd_open_window_func_err2:
+ hfi_restore_window_parm(p_acs, win_p);
hfidd_open_window_func_err1:
kfree(local_p);
return rc;
diff --git a/drivers/net/hfi/core/hfidd_xlat.c b/drivers/net/hfi/core/hfidd_xlat.c
index 23236cc..760d7e6 100644
--- a/drivers/net/hfi/core/hfidd_xlat.c
+++ b/drivers/net/hfi/core/hfidd_xlat.c
@@ -129,3 +129,213 @@ out1:
kfree(page_list);
return rc;
}
+
+int hfidd_get_page_num(struct hfidd_acs *p_acs,
+ void *start_addr,
+ unsigned long long len,
+ unsigned long long page_sz,
+ unsigned int *pg_num_p)
+{
+ int rc = 0;
+ int pg_shift_count;
+ unsigned long long address_mask;
+ unsigned long long offset_mask;
+ unsigned long long offset;
+
+ if (pg_num_p == NULL || len == 0) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_get_page_num: len=%llx pg_num_p=0x%llx\n",
+ len, (unsigned long long)pg_num_p);
+ return -EINVAL;
+ }
+
+ /*
+ * Pre-Calculate Masks and shift count:
+ */
+ if (page_sz == PAGE_SIZE_4K) {
+ offset_mask = PAGE_MASK_4K;
+ pg_shift_count = PAGE_SHIFT_4K;
+ } else if (page_sz == PAGE_SIZE_64K) {
+ offset_mask = PAGE_MASK_64K;
+ pg_shift_count = PAGE_SHIFT_64K;
+ } else if (page_sz == PAGE_SIZE_16M) {
+ offset_mask = PAGE_MASK_16M;
+ pg_shift_count = PAGE_SHIFT_16M;
+ } else if (page_sz == PAGE_SIZE_4G) {
+ offset_mask = PAGE_MASK_4G;
+ pg_shift_count = PAGE_SHIFT_4G;
+ } else {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_get_page_num: invalid page_sz 0x%llx "
+ "return EINVAL\n", page_sz);
+ return -EINVAL;
+ }
+ address_mask = ~offset_mask;
+
+ /*
+ * Calculate the buffer offsets into the first page:
+ */
+ offset = (unsigned long long)start_addr & offset_mask;
+ *pg_num_p = (len + offset + offset_mask) >> pg_shift_count;
+
+ return rc;
+}
+
+int hfidd_fill_xlat_tab(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ unsigned int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+ unsigned int num_pages;
+ unsigned long long page_size;
+ int rc = 0;
+
+ rc = hfidd_get_page_size(p_acs, fifo_in->eaddr.use.kptr, is_userspace,
+ fifo_in->size, &page_size);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fill_xlat_tab: hfidd_get_page_size failed, "
+ " rc=0x%x\n", rc);
+ return rc;
+ }
+
+ /* Get num of pages based in buffer page size */
+ rc = hfidd_get_page_num(p_acs, fifo_in->eaddr.use.kptr,
+ fifo_in->size, page_size, &num_pages);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fill_xlat_tab:: hfidd_get_page_num return "
+ "rc 0x%x\n", rc);
+ return rc;
+ }
+
+ xlat_p->v_addr = (caddr_t)(fifo_in->eaddr.use.kptr);
+ xlat_p->e_addr = (caddr_t)(fifo_in->eaddr.use.allu & ~(page_size - 1));
+ xlat_p->page_sz = page_size;
+ xlat_p->num_page = num_pages;
+ xlat_p->len = num_pages * page_size;
+ xlat_p->num_kpage = (xlat_p->len) / PAGE_SIZE;
+
+ return 0;
+}
+
+int hfidd_fifo_xlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+ int rc = 0;
+ int i;
+ unsigned int num_pages, pg_code;
+ unsigned long long page_size;
+ unsigned long long *l_pages;
+ struct page **page_list;
+ unsigned int hw_page = 0;
+
+ if ((fifo_in == NULL) || (xlat_p == NULL)) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: Invalid fifo_in 0x%llx\n",
+ (unsigned long long)fifo_in);
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: Invalid xlat_p 0x%llx\n",
+ (unsigned long long)xlat_p);
+ return -EINVAL;
+ }
+
+ rc = hfidd_fill_xlat_tab(p_acs, fifo_in, is_userspace, xlat_p);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: hfidd_fill_xlat_tab failed, "
+ "rc = 0x%x\n", rc);
+ return rc;
+ }
+
+ /* num_page is number of pages of page_sz */
+ num_pages = xlat_p->num_page;
+ page_size = xlat_p->page_sz;
+
+ l_pages = vmalloc(num_pages * sizeof(unsigned long long));
+ if (l_pages == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: vmalloc failed for l_pages\n");
+ return -ENOMEM;
+ }
+
+ if (!is_userspace) {
+ void *curr_addr = xlat_p->e_addr;
+
+ for (i = 0; i < num_pages; i++) {
+ l_pages[i] = __pa(curr_addr);
+ curr_addr += page_size;
+ }
+ } else {
+ /* For page_list use number of kernel pages */
+ page_list = kzalloc(xlat_p->num_kpage * sizeof(struct page *),
+ GFP_KERNEL);
+ if (page_list == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: kzalloc failed "
+ "for page_list\n");
+ rc = -ENOMEM;
+ goto out_err0;
+ }
+
+ down_read(¤t->mm->mmap_sem);
+ rc = get_user_pages(current, current->mm,
+ (unsigned long long)(xlat_p->e_addr),
+ xlat_p->num_kpage, 1, 0, /* write, !force */
+ page_list, NULL);
+ up_read(¤t->mm->mmap_sem);
+
+ if (rc < xlat_p->num_kpage) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_fifo_xlat: get_user_pages failed, "
+ "rc = 0x%x\n", rc);
+ goto out_err1;
+ }
+
+ for (i = 0; i < num_pages;) {
+ l_pages[hw_page] = page_to_phys(page_list[i]);
+ hw_page++;
+ i += (page_size / PAGE_SIZE);
+ }
+
+ xlat_p->page_list = (void *)page_list;
+ }
+
+ xlat_p->l_pages = (void *)l_pages;
+ xlat_p->map_page_sz = page_size;
+ xlat_p->m_addr = xlat_p->e_addr;
+ xlat_p->num_page_sz.num_code.fields.pg_num = num_pages;
+ encode_pg_sz(page_size, &pg_code);
+ xlat_p->num_page_sz.num_code.fields.pg_code =
+ (pg_code << HFI_PAGE_CODE_SHIFT);
+ return 0;
+
+out_err1:
+ if (rc > 0) {
+ for (i = 0; i < rc; i++)
+ page_cache_release(page_list[i]);
+ rc = -EINVAL;
+ }
+ kfree(page_list);
+out_err0:
+ vfree(l_pages);
+ return rc;
+}
+
+int hfidd_fifo_unxlat(struct hfidd_acs *p_acs, struct fifo_info *fifo_in,
+ int is_userspace, struct hfidd_vlxmem *xlat_p)
+{
+ int rc = 0;
+ int i;
+ struct page **page_list;
+
+ if (!is_userspace)
+ return 0;
+ page_list = (struct page **)xlat_p->page_list;
+ if (page_list != NULL) {
+ /* For page list we used number of kernel pages */
+ for (i = 0; i < xlat_p->num_kpage; i++)
+ page_cache_release(page_list[i]);
+ kfree(page_list);
+ xlat_p->page_list = NULL;
+ }
+ return rc;
+}
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index a41825f..8eab059 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -74,4 +74,32 @@
#define PAGE_MASK_4G (PAGE_SIZE_4G - 1)
#define PAGE_MASK_16G (PAGE_SIZE_16G - 1)
+#define PAGE_CODE_4K 0x00000000
+#define PAGE_CODE_64K 0x00000001
+#define PAGE_CODE_1M 0x00000002
+#define PAGE_CODE_16M 0x00000003
+#define PAGE_CODE_256M 0x00000004
+#define PAGE_CODE_4G 0x00000005
+#define PAGE_CODE_INVAL 0x00000007
+#define PAGE_CODE_MASK 0x00000007
+
+static inline void encode_pg_sz(unsigned long long pg_sz,
+ unsigned int *pg_sz_code)
+{
+ if (pg_sz == PAGE_SIZE_4K)
+ *pg_sz_code = PAGE_CODE_4K;
+ else if (pg_sz == PAGE_SIZE_64K)
+ *pg_sz_code = PAGE_CODE_64K;
+ else if (pg_sz == PAGE_SIZE_1M)
+ *pg_sz_code = PAGE_CODE_1M;
+ else if (pg_sz == PAGE_SIZE_16M)
+ *pg_sz_code = PAGE_CODE_16M;
+ else if (pg_sz == PAGE_SIZE_256M)
+ *pg_sz_code = PAGE_CODE_256M;
+ else if (pg_sz == PAGE_SIZE_4G)
+ *pg_sz_code = PAGE_CODE_4G;
+ else
+ *pg_sz_code = PAGE_CODE_INVAL;
+}
+
#endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 2a374e6..57140a0 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -42,6 +42,8 @@
#define H_NMMU_START 0xF028
#define H_NMMU_STOP 0xF02C
+#define HFI_PAGE_CODE_SHIFT 28
+
#define EEH_QUERY 1
#define COMP_QUERY 2
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 1781d52..216546b 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -63,6 +63,7 @@
#include <linux/hfi/hfidd_client.h>
#include <linux/hfi/hfidd_adpt.h>
#include <linux/hfi/hfidd_hcalls.h>
+#include <linux/hfi/hfidd_xlat_map.h>
#define MAX_D_WIN_PER_HFI (p_acs->dds.num_d_windows)
diff --git a/include/linux/hfi/hfidd_xlat_map.h b/include/linux/hfi/hfidd_xlat_map.h
new file mode 100644
index 0000000..e5d1869
--- /dev/null
+++ b/include/linux/hfi/hfidd_xlat_map.h
@@ -0,0 +1,91 @@
+/*
+ * hfidd_xlat_map.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFIDD_XLAT_MAP_H_
+#define _HFIDD_XLAT_MAP_H_
+
+#include <linux/hfi/hfidd_client.h>
+
+/*
+ * So we can shift rather than divide!
+ */
+#define PAGE_SHIFT_2K 11
+#define PAGE_SHIFT_4K 12
+#define PAGE_SHIFT_64K 16
+#define PAGE_SHIFT_1M 20
+#define PAGE_SHIFT_16M 24
+#define PAGE_SHIFT_4G 32
+
+struct page_num_code {
+ union {
+ unsigned long long llu_value;
+ struct num_and_code {
+ unsigned int pg_num;
+ unsigned int pg_code;
+ } fields;
+ } num_code;
+};
+
+struct hfidd_vlxmem {
+ unsigned long long page_sz; /* actual page size */
+ unsigned int num_page; /* calculated using actual
+ page size */
+ unsigned int rsvd;
+ struct page_num_code num_page_sz; /* page num and size code
+ mapping */
+ unsigned long long map_page_sz; /* page size used for mapping */
+ caddr_t m_addr; /* aligned address start for
+ mapping */
+ caddr_t v_addr; /* user given vaddr */
+ caddr_t e_addr;
+
+ unsigned long long len;
+ unsigned long long access_flag;
+ void *l_pages;
+
+ unsigned long long mr_handle;
+ unsigned int l_key;
+
+ struct task *xd;
+
+ int num_kpage; /* num of kernel pages */
+ atomic_t *share_cnt; /* # of processes sharing this
+ submr */
+ unsigned int num_chunks; /* number of chunks the mr is
+ divided */
+ caddr_t mr_addr; /* aligned submr starting
+ address */
+ void *page_list; /* struct page_list */
+ unsigned int liobn; /* logical I/O bus number */
+};
+
+#endif
--
1.7.3.1
^ permalink raw reply related
* [PATCH 24/27] HFI: hf network driver
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
It is a separate binary because it is not strictly necessary to use the HFI.
This patch includes module load/unload and the window open/setup with the
hfi device driver.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/Kconfig | 1 +
drivers/net/hfi/Makefile | 1 +
drivers/net/hfi/ip/Kconfig | 9 +
drivers/net/hfi/ip/Makefile | 6 +
drivers/net/hfi/ip/hf_if_main.c | 616 +++++++++++++++++++++++++++++++++++++++
drivers/net/hfi/ip/hf_proto.h | 48 +++
include/linux/hfi/hf_if.h | 156 ++++++++++
include/linux/if_arp.h | 1 +
8 files changed, 838 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/hfi/ip/Kconfig
create mode 100644 drivers/net/hfi/ip/Makefile
create mode 100644 drivers/net/hfi/ip/hf_if_main.c
create mode 100644 drivers/net/hfi/ip/hf_proto.h
create mode 100644 include/linux/hfi/hf_if.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d4ca094..3ba39c8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3423,5 +3423,6 @@ config VMXNET3
module will be called vmxnet3.
source "drivers/net/hfi/core/Kconfig"
+source "drivers/net/hfi/ip/Kconfig"
endif # NETDEVICES
diff --git a/drivers/net/hfi/Makefile b/drivers/net/hfi/Makefile
index 0440cbe..768f27c 100644
--- a/drivers/net/hfi/Makefile
+++ b/drivers/net/hfi/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_HFI) += core/
+obj-$(CONFIG_HFI_IP) += ip/
diff --git a/drivers/net/hfi/ip/Kconfig b/drivers/net/hfi/ip/Kconfig
new file mode 100644
index 0000000..1a2c21d
--- /dev/null
+++ b/drivers/net/hfi/ip/Kconfig
@@ -0,0 +1,9 @@
+config HFI_IP
+ tristate "IP-over-HFI"
+ depends on NETDEVICES && INET && HFI
+ ---help---
+ Support for the IP over HFI. It transports IP
+ packets over HFI.
+
+ To compile the driver as a module, choose M here. The module
+ will be called hf.
diff --git a/drivers/net/hfi/ip/Makefile b/drivers/net/hfi/ip/Makefile
new file mode 100644
index 0000000..59eff9b
--- /dev/null
+++ b/drivers/net/hfi/ip/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the HF IP interface for IBM eServer System p
+#
+obj-$(CONFIG_HFI_IP) += hf_if.o
+
+hf_if-objs := hf_if_main.o
diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
new file mode 100644
index 0000000..329baa1
--- /dev/null
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -0,0 +1,616 @@
+/*
+ * hf_if_main.c
+ *
+ * HF IP driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/hfi/hf_if.h>
+#include "hf_proto.h"
+
+MODULE_AUTHOR("James Dykman <dykmanj@linux.vnet.ibm.com>, "
+ "Piyush Chaudhary <piyushc@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IP driver v" HF_DRV_VERSION " (" HF_DRV_RELDATE ")"
+ " for IBM eServer HFI for System p");
+MODULE_VERSION(HF_DRV_VERSION);
+MODULE_LICENSE("GPL v2");
+
+struct hf_global_info hf_ginfo;
+
+static const u8 hfi_bcast_addr[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static int hf_inet_event(struct notifier_block *this,
+ unsigned long event,
+ void *ifa)
+{
+ struct in_device *in_dev;
+ struct net_device *netdev;
+
+ in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
+
+ netdev = in_dev->dev;
+
+ if (!net_eq(dev_net(netdev), &init_net))
+ return NOTIFY_DONE;
+
+ if (event == NETDEV_UP) {
+ struct hf_if *net_if;
+
+ net_if = &(((struct hf_net *)(netdev_priv(netdev)))->hfif);
+ net_if->ip_addr = ntohl(in_dev->ifa_list->ifa_address);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block hf_inet_notifier = {
+ .notifier_call = hf_inet_event,
+};
+
+static void hf_free_tx_resource(struct hf_if *net_if)
+{
+ int i;
+
+ if (net_if->tx_skb) {
+ for (i = 0; i <= net_if->tx_fifo.emax; i++) {
+ if (net_if->tx_skb[i])
+ dev_kfree_skb_any(net_if->tx_skb[i]);
+ }
+
+ free_pages((unsigned long)(net_if->tx_skb),
+ get_order((net_if->tx_fifo.emax + 1) *
+ sizeof(struct sk_buff *)));
+ net_if->tx_skb = 0;
+ }
+ if (net_if->tx_fifo.addr) {
+ free_pages((unsigned long)(net_if->tx_fifo.addr),
+ get_order(net_if->tx_fifo.size + PAGE_SIZE_4K));
+ net_if->tx_fifo.addr = 0;
+ }
+}
+
+static int hf_alloc_tx_resource(struct hf_if *net_if)
+{
+ int i;
+
+ net_if->tx_fifo.size = HF_SFIFO_SIZE;
+ net_if->tx_fifo.head = 0;
+ net_if->tx_fifo.tail = 0;
+ net_if->tx_fifo.emax = HF_SFIFO_SLOTS - 1;
+ atomic_set(&net_if->tx_fifo.avail, HF_SFIFO_SLOTS - 1);
+
+ net_if->tx_fifo.addr =
+ (void *)__get_free_pages(GFP_KERNEL,
+ get_order(net_if->tx_fifo.size + PAGE_SIZE_4K));
+
+ if (net_if->tx_fifo.addr == 0) {
+ printk(KERN_ERR "%s: hf_alloc_tx_resource: "
+ "tx_fifo fail, size=0x%x\n",
+ net_if->name, net_if->tx_fifo.size);
+
+ return -ENOMEM;
+ }
+ memset(net_if->tx_fifo.addr, 0, net_if->tx_fifo.size + PAGE_SIZE_4K);
+
+ /* Sfifo finish vector locates at very next page of sfifo */
+ net_if->sfifo_finishvec = net_if->tx_fifo.addr + net_if->tx_fifo.size;
+ net_if->sfifo_fv_polarity = 0;
+ net_if->sfifo_slots_per_blk = HF_SFIFO_SLOTS / HF_FV_BIT_CNT;
+
+ /* allocate array to hold the tx skbs */
+ net_if->tx_skb =
+ (struct sk_buff **)__get_free_pages(GFP_KERNEL,
+ get_order((net_if->tx_fifo.emax + 1) *
+ sizeof(struct sk_buff *)));
+
+ if (net_if->tx_skb == 0) {
+ printk(KERN_ERR "%s: hf_alloc_tx_resource: tx_skb failed\n",
+ net_if->name);
+
+ goto err_out;
+ }
+
+ for (i = 0; i <= net_if->tx_fifo.emax; i++)
+ net_if->tx_skb[i] = NULL;
+
+ return 0;
+
+err_out:
+ hf_free_tx_resource(net_if);
+
+ return -ENOMEM;
+}
+
+static void hf_free_rx_resource(struct hf_if *net_if)
+{
+ if (net_if->rx_fifo.addr) {
+ free_pages((unsigned long)(net_if->rx_fifo.addr),
+ get_order(net_if->rx_fifo.size));
+ net_if->rx_fifo.addr = 0;
+ }
+}
+
+static int hf_alloc_rx_resource(struct hf_if *net_if)
+{
+ net_if->rx_fifo.size = HF_RFIFO_SIZE;
+ net_if->rx_fifo.head = 0;
+ net_if->rx_fifo.tail = 0;
+ net_if->rx_fifo.emax = HF_RFIFO_SLOTS - 1;
+
+ net_if->rx_fifo.addr =
+ (void *)__get_free_pages(GFP_KERNEL,
+ get_order(net_if->rx_fifo.size));
+
+ if (net_if->rx_fifo.addr == 0) {
+ printk(KERN_ERR "%s: hf_alloc_rx_resource: fail, size=0x%x\n",
+ net_if->name, net_if->rx_fifo.size);
+
+ return -ENOMEM;
+ }
+
+ memset(net_if->rx_fifo.addr, 0, net_if->rx_fifo.size);
+
+ return 0;
+}
+
+static void hf_free_resource(struct hf_if *net_if)
+{
+ hf_free_rx_resource(net_if);
+
+ hf_free_tx_resource(net_if);
+}
+
+static int hf_alloc_resource(struct hf_net *net)
+{
+ int rc;
+ struct hf_if *net_if = &(net->hfif);
+
+ rc = hf_alloc_tx_resource(net_if);
+ if (rc)
+ goto alloc_resource_err0;
+
+ rc = hf_alloc_rx_resource(net_if);
+ if (rc)
+ goto alloc_resource_err1;
+
+ return 0;
+
+alloc_resource_err1:
+ hf_free_tx_resource(net_if);
+alloc_resource_err0:
+ return rc;
+}
+
+static int hf_close_ip_window(struct hf_if *net_if, struct hfidd_acs *p_acs)
+{
+ int rc;
+
+ if (net_if->doorbell) {
+ iounmap(net_if->doorbell);
+ net_if->doorbell = NULL;
+ }
+
+ /* Fill in the request structure */
+ net_if->client.hdr.req = HFIDD_REQ_CLOSE_WINDOW;
+ net_if->client.hdr.req_len = sizeof(struct hfi_window_info);
+ net_if->client.hdr.result.use.kptr = &(net_if->client);
+
+ rc = hfidd_close_window_func(HF_ACS(net_if), 0,
+ (struct hfi_window_info *)(&(net_if->client)));
+ if (rc) {
+ printk(KERN_ERR "%s: hf_close_ip_window: fail, rc=0x%x\n",
+ net_if->name, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int hf_open_ip_window(struct hf_if *net_if,
+ struct hfidd_acs *p_acs,
+ int share_with)
+{
+ int rc = 0;
+
+ net_if->client.win_type = HFIDD_IP_WIN;
+
+ net_if->client.sfifo.eaddr.use.kptr = net_if->tx_fifo.addr;
+ net_if->client.sfifo.size = net_if->tx_fifo.size;
+ net_if->client.rfifo.eaddr.use.kptr = net_if->rx_fifo.addr;
+ net_if->client.rfifo.size = net_if->rx_fifo.size;
+ net_if->client.sfifo_finish_vec.use.kptr = net_if->sfifo_finishvec;
+ net_if->client.job_id = HF_IP_JOBID;
+
+ /* Fill in the request structure */
+ net_if->client.hdr.req = HFIDD_REQ_OPEN_WINDOW;
+ net_if->client.hdr.req_len = sizeof(struct hfi_client_info);
+ net_if->client.hdr.result.use.kptr = &(net_if->client);
+
+ rc = hfidd_open_window_func(p_acs, 0, &(net_if->client), 0,
+ &(net_if->client));
+ if (rc) {
+ printk(KERN_ERR "%s: hf_open_ip_window: fail open rc=0x%x\n",
+ net_if->name, rc);
+ return rc;
+ }
+
+ net_if->doorbell = (ioremap(
+ (u64)(net_if->client.mmio_regs.use.kptr), PAGE_SIZE_64K));
+
+ if (unlikely(net_if->doorbell == NULL)) {
+ printk(KERN_ERR "%s: hf_open_ip_window: fail to map doorbell\n",
+ net_if->name);
+ hf_close_ip_window(net_if, p_acs);
+ }
+
+ net_if->isr_id = net_if->client.local_isrid;
+
+ return 0;
+}
+
+static int hf_set_mac_addr(struct net_device *netdev, void *p)
+{
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+
+ /* Mac address format: 02:ClusterID:ISR:ISR:HFI_WIN:WIN */
+
+ /* Locally administered MAC address */
+ netdev->dev_addr[0] = 0x2; /* bit6=1, bit7=0 */
+
+ netdev->dev_addr[1] = 0x0; /* cluster id */
+
+ *(u16 *)(&(netdev->dev_addr[2])) = (u16)(net_if->isr_id);
+
+ *(u16 *)(&(netdev->dev_addr[4])) = (u16)
+ (((net_if->ai) << HF_MAC_HFI_SHIFT) | (net_if->client.window));
+
+ return 0;
+}
+
+static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
+{
+ struct net_device *netdev = (struct net_device *)parm;
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+ int rc = 0;
+ int share_with;
+ struct hfidd_acs *p_acs = HF_ACS(net_if);
+
+ spin_lock(&(net_if->lock));
+ if (net_if->state != HF_NET_HALF_OPEN) {
+ netdev_err(netdev, "hf_net_delayed_open: net_if state=0x%x\n",
+ net_if->state);
+ spin_unlock(&(net_if->lock));
+ return -EINVAL;
+ }
+
+ rc = hf_alloc_resource(net);
+ if (rc)
+ goto delayed_open_err0;
+
+ rc = hf_open_ip_window(net_if, p_acs, share_with);
+ if (rc)
+ goto delayed_open_err1;
+
+ hf_set_mac_addr(netdev, NULL);
+
+ net_if->state = HF_NET_OPEN;
+ spin_unlock(&(net_if->lock));
+
+ return 0;
+
+delayed_open_err1:
+ hf_free_resource(net_if);
+
+delayed_open_err0:
+ spin_unlock(&(net_if->lock));
+
+ return rc;
+}
+
+static int hf_register_hfi_ready_callback(struct net_device *netdev,
+ struct hfidd_acs *p_acs,
+ int flag)
+{
+ struct hfi_reg_events reg_events;
+ int rc = 0;
+
+ reg_events.hdr.req = flag;
+ reg_events.hdr.req_len = sizeof(struct hfi_reg_events);
+ reg_events.hdr.result.use.kptr = NULL;
+ reg_events.type = FUNCTIONS_FOR_EVENTS;
+
+ reg_events.info.func.index = HFIDD_HFI_READY_REG;
+ reg_events.info.func.function_p.use.kptr = hf_net_delayed_open;
+ reg_events.info.func.parameter.use.kptr = (void *)(netdev);
+
+ if (flag == HFIDD_REQ_EVENT_REGISTER)
+ rc = hfidd_callback_register(p_acs, ®_events);
+ else
+ rc = hfidd_callback_unregister(p_acs, ®_events);
+ if (rc) {
+ netdev_err(netdev, "hf_register_hfi_ready_callback: fail"
+ " flag=0x%x rc=0x%x\n", flag, rc);
+
+ return rc;
+ }
+
+ return 0;
+}
+
+static int hf_net_open(struct net_device *netdev)
+{
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+ int rc = 0;
+ struct hfidd_acs *p_acs = HF_ACS(net_if);
+
+ memset(&(net_if->net_stats), 0, sizeof(struct net_device_stats));
+ net_if->sfifo_packets = 0;
+
+ spin_lock(&(net_if->lock));
+ net_if->state = HF_NET_HALF_OPEN;
+ spin_unlock(&(net_if->lock));
+
+ netif_carrier_off(netdev);
+
+ rc = hf_register_hfi_ready_callback(netdev, p_acs,
+ HFIDD_REQ_EVENT_REGISTER);
+ if (rc != 0) {
+ spin_lock(&(net_if->lock));
+ net_if->state = HF_NET_CLOSE;
+ spin_unlock(&(net_if->lock));
+
+ netdev_err(netdev, "hf_net_open: hf_register_hfi_ready_callback"
+ "fail, rc=0x%x, state=0x%x", rc, net_if->state);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int hf_net_close(struct net_device *netdev)
+{
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+ struct hfidd_acs *p_acs = HF_ACS(net_if);
+
+ if (net_if->state == HF_NET_CLOSE)
+ return 0;
+
+ spin_lock(&(net_if->lock));
+ if (net_if->state == HF_NET_OPEN) {
+ hf_close_ip_window(net_if, p_acs);
+
+ hf_free_resource(net_if);
+ }
+
+ hf_register_hfi_ready_callback(netdev, p_acs,
+ HFIDD_REQ_EVENT_UNREGISTER);
+
+ net_if->state = HF_NET_CLOSE;
+ spin_unlock(&(net_if->lock));
+
+ return 0;
+}
+
+struct net_device_stats *hf_get_stats(struct net_device *netdev)
+{
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+
+ return &(net_if->net_stats);
+}
+
+static int hf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ if ((new_mtu <= 0) || (new_mtu > HF_NET_MTU))
+ return -ERANGE;
+
+ netdev->mtu = new_mtu;
+
+ return 0;
+}
+
+static int hf_hard_header(struct sk_buff *skb,
+ struct net_device *netdev,
+ u16 type,
+ const void *daddr,
+ const void *saddr,
+ u32 len)
+{
+ struct hf_hwhdr *hwhdr_p;
+
+ skb_push(skb, HF_HLEN);
+
+ hwhdr_p = (struct hf_hwhdr *)(skb->data);
+ hwhdr_p->h_proto = htons(type);
+
+ if (!saddr)
+ saddr = netdev->dev_addr;
+
+ memcpy(hwhdr_p->h_source, saddr, netdev->addr_len);
+
+ if (daddr) {
+ memcpy(hwhdr_p->h_dest, daddr, netdev->addr_len);
+ return netdev->hard_header_len;
+ }
+
+ if (netdev->flags & IFF_NOARP) {
+ memset(hwhdr_p->h_dest, 0, netdev->addr_len);
+ return netdev->hard_header_len;
+ }
+
+ return -netdev->hard_header_len;
+}
+
+static const struct header_ops hf_header_ops = {
+ .create = hf_hard_header,
+};
+
+static const struct net_device_ops hf_netdev_ops = {
+ .ndo_open = hf_net_open,
+ .ndo_stop = hf_net_close,
+ .ndo_change_mtu = hf_change_mtu,
+ .ndo_set_mac_address = NULL,
+ .ndo_get_stats = hf_get_stats,
+};
+
+static void hf_if_setup(struct net_device *netdev)
+{
+ netdev->type = ARPHRD_HFI;
+ netdev->mtu = HF_NET_MTU;
+ netdev->tx_queue_len = 1000;
+ netdev->flags = IFF_BROADCAST;
+ netdev->hard_header_len = HF_HLEN;
+ netdev->addr_len = HF_ALEN;
+ netdev->needed_headroom = 0;
+
+ netdev->header_ops = &hf_header_ops;
+ netdev->netdev_ops = &hf_netdev_ops;
+
+ netdev->features |= NETIF_F_SG;
+
+ memcpy(netdev->broadcast, hfi_bcast_addr, HF_ALEN);
+}
+
+static struct hf_net *hf_init_netdev(int idx, int ai)
+{
+ struct net_device *netdev;
+ struct hf_net *net;
+ int ii;
+ int rc;
+ char ifname[HF_MAX_NAME_LEN];
+
+ ii = (idx * MAX_HFIS) + ai;
+ sprintf(ifname, "hf%d", ii);
+ netdev = alloc_netdev(sizeof(struct hf_net), ifname, hf_if_setup);
+ if (!netdev) {
+ printk(KERN_ERR "hf_init_netdev: "
+ "alloc_netdev for hfi%d:hf%d fail\n", ai, idx);
+ return (struct hf_net *) -ENODEV;
+ }
+
+ net = netdev_priv(netdev);
+ net->netdev = netdev;
+
+ memset(&(net->hfif), 0, sizeof(struct hf_if));
+ net->hfif.idx = ii; /* interface index */
+ net->hfif.ai = ai; /* adapter index */
+ strncpy(net->hfif.name, ifname, HF_MAX_NAME_LEN);
+ net->hfif.state = HF_NET_CLOSE;
+
+ spin_lock_init(&net->hfif.lock);
+
+ rc = register_netdev(netdev);
+ if (rc) {
+ printk(KERN_ERR "hf_init_netdev: "
+ "failed to register netdev=hfi%d:hf%d, "
+ "rc 0x%x\n", ai, idx, rc);
+ free_netdev(netdev);
+ return (struct hf_net *) -ENODEV;
+ }
+
+ return net;
+}
+
+static void hf_del_netdev(struct hf_net *net)
+{
+ struct net_device *netdev = net->netdev;
+
+ unregister_netdev(netdev);
+
+ free_netdev(netdev);
+}
+
+static int __init hf_init_module(void)
+{
+ u32 idx, ai;
+ struct hf_net *net;
+
+ memset(&hf_ginfo, 0, sizeof(struct hf_global_info));
+
+ for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+ for (ai = 0; ai < MAX_HFIS; ai++) {
+ net = hf_init_netdev(idx, ai);
+ if (IS_ERR(net)) {
+ printk(KERN_ERR "hf_init_module: hf_init_netdev"
+ " for idx %d ai %d failed rc"
+ " 0x%016llx\n",
+ idx, ai, (u64)(PTR_ERR(net)));
+
+ goto err_out;
+ }
+
+ hf_ginfo.net[idx][ai] = net;
+ }
+ }
+
+ register_inetaddr_notifier(&hf_inet_notifier);
+
+ printk(KERN_INFO "hf module loaded\n");
+ return 0;
+
+err_out:
+ for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+ for (ai = 0; ai < MAX_HFIS; ai++) {
+ net = hf_ginfo.net[idx][ai];
+ if (net != NULL) {
+ hf_del_netdev(net);
+ hf_ginfo.net[idx][ai] = NULL;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void __exit hf_cleanup_module(void)
+{
+ u32 idx, ai;
+ struct hf_net *net;
+
+ unregister_inetaddr_notifier(&hf_inet_notifier);
+ for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
+ for (ai = 0; ai < MAX_HFIS; ai++) {
+ net = hf_ginfo.net[idx][ai];
+ if (net != NULL) {
+ hf_del_netdev(net);
+ hf_ginfo.net[idx][ai] = NULL;
+ }
+ }
+ }
+
+ return;
+}
+
+module_init(hf_init_module);
+module_exit(hf_cleanup_module);
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
new file mode 100644
index 0000000..f2b159e
--- /dev/null
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -0,0 +1,48 @@
+/*
+ * hf_proto.h
+ *
+ * HF IP driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HF_PROTO_H_
+#define _HF_PROTO_H_
+
+extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
+ u32 is_userspace,
+ struct hfi_client_info *user_p,
+ u64 fl, struct hfi_client_info *out_p);
+extern int hfidd_close_window_func(struct hfidd_acs *p_acs,
+ u32 is_userspace,
+ struct hfi_window_info *user_p);
+extern int hfidd_callback_register(struct hfidd_acs *p_acs,
+ struct hfi_reg_events *arg);
+extern int hfidd_callback_unregister(struct hfidd_acs *p_acs,
+ struct hfi_reg_events *arg);
+
+#endif
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
new file mode 100644
index 0000000..d13c6ab
--- /dev/null
+++ b/include/linux/hfi/hf_if.h
@@ -0,0 +1,156 @@
+/*
+ * hf_if.h
+ *
+ * HF IP driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <wcchen@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HF_IF_H_
+#define _HF_IF_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <net/arp.h>
+
+#include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_client.h>
+#include <linux/hfi/hfidd_requests.h>
+#include <linux/hfi/hfidd_pkt_formats.h>
+
+#define HF_DRV_VERSION "1.0"
+#define HF_DRV_RELDATE "July 7, 2010"
+#define HF_DRV_NAME "hf"
+
+#define MAX_HF_PER_HFI 2
+#define HF_IP_JOBID 0xFFFFFFF0
+#define HF_MAX_NAME_LEN 64
+
+#define HF_SFIFO_SIZE 0x40000 /* 256K */
+#define HF_SFIFO_SLOTS (HF_SFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+#define HF_RFIFO_SIZE 0x1000000 /* 16M */
+#define HF_RFIFO_SLOTS (HF_RFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+
+#define HF_FV_BIT_CNT 32
+#define HF_NET_MTU (2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+
+struct hfi_ip_extended_hdr { /* 16B */
+ u32 immediate_len:7;/* In bytes */
+ u32 num_desc:3; /* number of descriptors */
+ /* Logical Port ID: */
+ u32 lpid_valid:1; /* set by sending HFI */
+ u32 lpid:4; /* set by sending HFI */
+ /* Ethernet Service Header is 113 bits, which is 14 bytes + 1 bit */
+ u32 ethernet_svc_hdr_hi:1; /* Not used by HFI */
+ char ethernet_svc_hdr[12]; /* Not used by HFI */
+ __sum16 bcast_csum;
+} __packed;
+
+struct hfi_ip_with_payload_pkt {
+ struct hfi_hdr hfi_hdr;
+ struct hfi_ip_extended_hdr ip_ext;
+ char payload[2016];
+} __packed;
+
+#define HF_IP_HDR_LEN ((sizeof(struct hfi_hdr) + \
+ sizeof(struct hfi_ip_extended_hdr)))
+#define HF_ALEN 6
+struct hf_hwhdr {
+ u8 h_dest[HF_ALEN];
+ u8 h_source[HF_ALEN];
+ __be16 h_proto;
+};
+
+#define HF_HLEN sizeof(struct hf_hwhdr)
+#define HF_ALIGN_PAD 2
+
+struct hf_if_proto_hdr {
+ u16 version;
+ u8 msg_type;
+ u8 msg_flag;
+ u32 msg_len; /* Include HFI header */
+ u32 msg_id;
+};
+
+#define HF_PROTO_LEN sizeof(struct hf_if_proto_hdr)
+
+struct hf_fifo {
+ void *addr;
+ u32 size; /* total bytes */
+ u32 head;
+ u32 tail;
+ u32 emax; /* power 2 mask */
+ atomic_t avail; /* for tx */
+ atomic_t outstanding; /* for rx */
+};
+
+#define HF_NET_CLOSE 0x00
+#define HF_NET_HALF_OPEN 0xA0
+#define HF_NET_OPEN 0xA1
+
+struct hf_if {
+ u32 idx; /* 0, 1, 2, 3 ... */
+ u32 ai; /* 0=hfi0, 1=hfi1 */
+ char name[HF_MAX_NAME_LEN];
+ u32 isr_id;
+ u32 ip_addr;
+ u32 state; /* CLOSE, OPEN */
+ spinlock_t lock; /* lock for state */
+ u32 sfifo_fv_polarity;
+ u32 sfifo_slots_per_blk;
+ u32 sfifo_packets;
+ void __iomem *doorbell; /* mapped mmio_regs */
+ struct hf_fifo tx_fifo;
+ struct hf_fifo rx_fifo;
+ struct hfi_client_info client;
+ struct sk_buff **tx_skb; /* array to store tx
+ 2k skb */
+ void *sfifo_finishvec;
+ struct net_device_stats net_stats;
+};
+
+/* Private structure for HF inetrface */
+struct hf_net {
+ struct net_device *netdev;
+ struct hf_if hfif;
+};
+
+extern struct hfidd_global hfidd_global;
+
+#define HF_ACS(net_if) (hfidd_global.p_acs[(net_if)->ai])
+
+struct hf_global_info {
+ struct hf_net *net[MAX_HF_PER_HFI][MAX_HFI_PER_TORRENT];
+};
+
+extern struct hf_global_info hf_ginfo;
+
+#define HF_MAC_HFI_SHIFT 12
+#endif
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 6d722f4..f2cfdc1 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -41,6 +41,7 @@
#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */
#define ARPHRD_EUI64 27 /* EUI-64 */
#define ARPHRD_INFINIBAND 32 /* InfiniBand */
+#define ARPHRD_HFI 37 /* Host Fabric Interface */
/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP 256
--
1.7.3.1
^ permalink raw reply related
* [PATCH 11/27] HFI: Check window number/assign window number
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
RESERVED windows are reserved by a job scheduler before the application starts.
the application is given a list of windows to use, the DD has to check that
they are opening one of the windows assigned to that jobid.
DYNAMIC windows are used without a job scheduler; the application calls into
the DD and asks for any free window.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_window.c | 161 +++++++++++++++++++++++++++++++++++
include/linux/hfi/hfidd_internal.h | 16 ++++
2 files changed, 177 insertions(+), 0 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
index f16caf7..cc775e3 100644
--- a/drivers/net/hfi/core/hfidd_window.c
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -35,6 +35,153 @@
#include "hfidd_proto.h"
#include <linux/hfi/hfidd_requests.h>
+/* Validate the type, state and job id for RESERVED window */
+static int hfi_validate_reserve_window_id(struct hfidd_acs *p_acs,
+ struct hfi_client_info *client_p)
+{
+ struct hfidd_window *win_p;
+
+ /* Check if win is between min_hfi_windows and max_hfi_windows */
+ if ((client_p->window < min_hfi_windows(p_acs)) ||
+ (client_p->window >= max_hfi_windows(p_acs))) {
+
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_reserve_window_id: window = 0x%x too big\n",
+ client_p->window);
+ return -EINVAL;
+ }
+
+ /* Check if win_p indexed by window is not NULL */
+ win_p = hfi_window(p_acs, client_p->window);
+ if (win_p == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_reserve_window_id: win 0x%x win_p is NULL\n",
+ client_p->window);
+ return -EINVAL;
+ }
+
+ spin_lock(&(win_p->win_lock));
+ /*
+ * Check if win_p->type is HFIDD_RESERVE_WIN
+ * win_p->state is WIN_RESERVED,
+ * job id is matched
+ */
+ if ((win_p->type != HFIDD_RESERVE_WIN) ||
+ (win_p->state != WIN_RESERVED) ||
+ (win_p->job_id != client_p->job_id)) {
+ spin_unlock(&(win_p->win_lock));
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_reserve_window_id: win 0x%x type0x%x/"
+ "state0x%x/jid invalid\n",
+ client_p->window, win_p->type, win_p->state);
+ return -EINVAL;
+ }
+ spin_unlock(&(win_p->win_lock));
+ return 0;
+}
+
+/* Find an available dynamic window for open window request */
+static int hfi_validate_dynamic_window_id(struct hfidd_acs *p_acs,
+ struct hfi_client_info *client_p)
+{
+ int i;
+ struct hfidd_window *win_p;
+
+ /* Find out next available dynamic window */
+ for (i = min_hfi_windows(p_acs);
+ i < max_hfi_windows(p_acs); i++) {
+
+ win_p = hfi_window(p_acs, i);
+ if (win_p == NULL)
+ continue;
+
+ /* if the spinlock is busy, the window is in use */
+ if (!spin_trylock(&(win_p->win_lock)))
+ continue;
+
+ if ((win_p->type == HFIDD_DYNAMIC_WIN) &&
+ (win_p->state == WIN_AVAILABLE)) {
+ /*
+ * Fill in the window number into
+ * client info and update state
+ */
+ client_p->window = win_p->index;
+ win_p->job_id = client_p->job_id;
+ win_p->state = WIN_RESERVED;
+ win_p->type = client_p->win_type;
+
+ /* Set isIP flag if came from IP */
+ if (win_p->type == HFIDD_IP_WIN)
+ win_p->is_ip = 1;
+ else
+ win_p->is_ip = 0;
+ spin_unlock(&(win_p->win_lock));
+ return 0;
+ }
+ spin_unlock(&(win_p->win_lock));
+ }
+
+ /* We are out of dynamic windows */
+ if (i == max_hfi_windows(p_acs)) {
+ client_p->window = 0;
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_dynamic_window_id: out of dynamic window\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+/* Validate the window request for RESERVED or DYNAMIC window */
+static inline int hfi_validate_window_id(struct hfidd_acs *p_acs,
+ struct hfi_client_info *client_p, unsigned int is_userspace)
+{
+ int rc = 0;
+
+ /* Check the type of window request */
+ switch (client_p->win_type) {
+ case HFIDD_RESERVE_WIN:
+ rc = hfi_validate_reserve_window_id(p_acs, client_p);
+ break;
+ case HFIDD_IP_WIN:
+ case HFIDD_KERNEL_WIN:
+ if (is_userspace) {
+ rc = -EINVAL;
+ break;
+ }
+ /* fall thru here....*/
+ case HFIDD_DYNAMIC_WIN:
+ rc = hfi_validate_dynamic_window_id(p_acs, client_p);
+ break;
+ default:
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_window_id: invalid win type 0x%x\n",
+ client_p->win_type);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+/* Validate window number and type for open window request */
+static int hfi_validate_window_parm(struct hfidd_acs *p_acs,
+ unsigned int is_userspace,
+ struct hfi_client_info *client_p)
+{
+ int rc = 0;
+
+ /* Validate the window number */
+ rc = hfi_validate_window_id(p_acs, client_p, is_userspace);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfi_validate_window_parm: hfi_validate_window_id "
+ "failed, rc = 0x%x\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
/*
* Allows an user/kernel window to send/receive network traffic thru HFI
* adapter. This function will allocate the system resources needed to open
@@ -62,9 +209,23 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
if (rc) {
dev_printk(KERN_ERR, p_acs->hfidd_dev,
"open_window_func: hfi_copy_from_user failed\n");
+ goto hfidd_open_window_func_err1;
+ }
+
+ /* Validate the window parms */
+ rc = hfi_validate_window_parm(p_acs, is_userspace, local_p);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "open_window_func: hfi_validate_window_parm failed, "
+ "rc = 0x%x\n", rc);
+ goto hfidd_open_window_func_err1;
}
kfree(local_p);
return rc;
+
+hfidd_open_window_func_err1:
+ kfree(local_p);
+ return rc;
}
EXPORT_SYMBOL_GPL(hfidd_open_window_func);
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index dd1ce4c..1781d52 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -142,6 +142,22 @@ struct hfidd_global {
struct hfidd_acs *p_acs[MAX_HFIS];
};
+static inline struct hfidd_window *hfi_window(struct hfidd_acs *p,
+ unsigned int idx)
+{
+ return p->win[idx - p->dds.window_start];
+}
+
+static inline unsigned int min_hfi_windows(struct hfidd_acs *p)
+{
+ return p->dds.window_start;
+}
+
+static inline unsigned int max_hfi_windows(struct hfidd_acs *p)
+{
+ return p->dds.window_start + p->dds.window_num;
+}
+
static inline int hfi_copy_to_user(void *user_p, void *local_p,
unsigned int is_userspace, unsigned int size)
{
--
1.7.3.1
^ permalink raw reply related
* [PATCH 25/27] HFI: hf fifo transmit paths
From: dykmanj @ 2011-03-02 21:10 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/ip/hf_if_main.c | 436 ++++++++++++++++++++++++++++++++++++++-
drivers/net/hfi/ip/hf_proto.h | 1 +
include/linux/hfi/hf_if.h | 73 +++++++-
3 files changed, 508 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hfi/ip/hf_if_main.c b/drivers/net/hfi/ip/hf_if_main.c
index 329baa1..ea4579e 100644
--- a/drivers/net/hfi/ip/hf_if_main.c
+++ b/drivers/net/hfi/ip/hf_if_main.c
@@ -208,6 +208,87 @@ alloc_resource_err0:
return rc;
}
+static int hf_send_intr_callback(void *parm, u32 win, u32 ext)
+{
+ struct hf_net *net = (struct hf_net *)parm;
+ struct hf_if *net_if = &(net->hfif);
+ u64 sintr_status;
+
+ sintr_status = hf_mmio_regs_read(net_if, HFI_SINTR_STATUS_REG);
+
+ netdev_info(net->netdev, "hf_send_intr_callback: "
+ "sintr_status 0x%016llx", sintr_status);
+
+ /* mask off the interrupt */
+ if (sintr_status & HF_SFIFO_INTR_EVENT)
+ hf_mmio_regs_write(net_if, HFI_SFIFO_INTR_CNTL, 0);
+
+ /* Make sure interrupts are masked */
+ /* Otherwise after the queue is awaken, it will get stale interrupt */
+ mb();
+
+ netif_wake_queue(net->netdev);
+
+ return 0;
+}
+
+struct hf_events_cb hf_events[HF_EVENT_NUM] = {
+ {HFIDD_SEND, (void *)hf_send_intr_callback},
+};
+
+static int hf_register_ip_events(struct hf_net *net,
+ struct hfidd_acs *p_acs,
+ int flag)
+{
+ struct hf_if *net_if = &(net->hfif);
+ int rc = 0, i, j;
+ struct hfi_reg_events events[HF_EVENT_NUM];
+ int (*reg_func)(struct hfidd_acs *,
+ struct hfi_reg_events *);
+
+ if (flag == HFIDD_REQ_EVENT_REGISTER)
+ reg_func = hfidd_callback_register;
+ else
+ reg_func = hfidd_callback_unregister;
+
+ for (i = 0; i < HF_EVENT_NUM; i++) {
+ events[i].window = net_if->client.window;
+ events[i].type = FUNCTIONS_FOR_EVENTS;
+ events[i].info.func.index = hf_events[i].type;
+ events[i].info.func.function_p.use.kptr = hf_events[i].func;
+ events[i].info.func.parameter.use.kptr = (void *)(net);
+
+ events[i].hdr.req = flag;
+ events[i].hdr.req_len = sizeof(struct hfi_reg_events);
+ events[i].hdr.result.use.kptr = &(events[i]);
+
+ rc = reg_func(p_acs, &(events[i]));
+ if (rc) {
+ netdev_err(net->netdev, "hf_register_ip_events: "
+ "fail event 0x%x, flag=0x%x rc=0x%x\n",
+ hf_events[i].type, flag, rc);
+
+ if (flag == HFIDD_REQ_EVENT_REGISTER)
+ goto err_out;
+ }
+ }
+
+ return rc;
+
+err_out:
+ for (j = 0; j < i; j++) {
+ events[j].hdr.req = HFIDD_REQ_EVENT_UNREGISTER;
+ rc = hfidd_callback_unregister(p_acs, &(events[i]));
+ if (rc) {
+ netdev_err(net->netdev, "hf_register_ip_events: failed "
+ "to unregister callback event 0x%x, rc=0x%x\n",
+ events[i].info.func.index, rc);
+ }
+ }
+
+ return rc;
+}
+
static int hf_close_ip_window(struct hf_if *net_if, struct hfidd_acs *p_acs)
{
int rc;
@@ -295,6 +376,16 @@ static int hf_set_mac_addr(struct net_device *netdev, void *p)
return 0;
}
+static void hf_init_hw_regs(struct hf_if *net_if)
+{
+ /* setup IP with payload threshold in cache line size */
+ hf_mmio_regs_write(net_if, HFI_IP_RECV_SIZE,
+ (HF_PAYLOAD_RX_THRESHOLD << HF_PAYLOAD_RX_THRESH_SHIFT));
+
+ /* initialize SEND INTR STATUS */
+ hf_mmio_regs_write(net_if, HFI_SINTR_STATUS_REG, 0);
+}
+
static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
{
struct net_device *netdev = (struct net_device *)parm;
@@ -320,13 +411,25 @@ static int hf_net_delayed_open(void *parm, u16 win, u16 ext)
if (rc)
goto delayed_open_err1;
+ rc = hf_register_ip_events(net, p_acs, HFIDD_REQ_EVENT_REGISTER);
+ if (rc)
+ goto delayed_open_err2;
+
hf_set_mac_addr(netdev, NULL);
+ hf_init_hw_regs(net_if);
+
net_if->state = HF_NET_OPEN;
spin_unlock(&(net_if->lock));
+ netif_carrier_on(netdev);
+ netif_start_queue(netdev);
+
return 0;
+delayed_open_err2:
+ hf_close_ip_window(net_if, p_acs);
+
delayed_open_err1:
hf_free_resource(net_if);
@@ -408,6 +511,11 @@ static int hf_net_close(struct net_device *netdev)
spin_lock(&(net_if->lock));
if (net_if->state == HF_NET_OPEN) {
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
+
+ hf_register_ip_events(net, p_acs, HFIDD_REQ_EVENT_UNREGISTER);
+
hf_close_ip_window(net_if, p_acs);
hf_free_resource(net_if);
@@ -422,6 +530,328 @@ static int hf_net_close(struct net_device *netdev)
return 0;
}
+static void hf_tx_recycle(struct hf_if *net_if)
+{
+ u32 head, head_idx, slots_per_blk;
+ u32 *fv;
+ int i;
+ u32 fv_bit;
+ u8 nr;
+
+ head = net_if->tx_fifo.head;
+
+ slots_per_blk = net_if->sfifo_slots_per_blk;
+
+ head_idx = head / slots_per_blk;
+
+ fv = (u32 *)(net_if->sfifo_finishvec);
+
+ while (1) {
+ nr = HF_FV_BIT_MAX - head_idx;
+ fv_bit = BIT(nr) & (ACCESS_ONCE(*fv));
+ fv_bit = fv_bit >> nr;
+
+ if ((fv_bit ^ (net_if->sfifo_fv_polarity)) == 0)
+ break;
+
+ for (i = 0; i < slots_per_blk; i++) {
+ struct sk_buff *skb;
+
+ skb = net_if->tx_skb[head + i];
+ if (skb != NULL) {
+ dev_kfree_skb_any(skb);
+ net_if->tx_skb[head + i] = NULL;
+ }
+ }
+
+ head = (head + slots_per_blk) & (net_if->tx_fifo.emax);
+
+ atomic_add(slots_per_blk, &(net_if->tx_fifo.avail));
+
+ if (++head_idx == HF_FV_BIT_CNT) {
+ head_idx = 0;
+ net_if->sfifo_fv_polarity ^= 1;
+ }
+ }
+
+ net_if->tx_fifo.head = head;
+
+ return;
+}
+
+int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls)
+{
+ struct net_device *netdev = net->netdev;
+ struct hf_if *net_if = &(net->hfif);
+
+ if (atomic_read(&net_if->tx_fifo.avail) < xmit_cls) {
+
+ hf_tx_recycle(net_if);
+
+ if (atomic_read(&net_if->tx_fifo.avail) < xmit_cls) {
+ u32 intr_cntl;
+ u64 intr_thresh;
+
+ netif_stop_queue(netdev);
+
+ /* turn on transmit interrupt */
+ intr_thresh = (net_if->sfifo_packets -
+ HF_SFIFO_INTR_WATERMARK) & HF_SFIFO_INTR_MASK;
+
+ intr_cntl = HF_SFIFO_INTR_ENABLE |
+ (intr_thresh << HF_SFIFO_INTR_CNT_SHIFT);
+
+ hf_mmio_regs_write_then_read(net_if,
+ HFI_SFIFO_INTR_CNTL, intr_cntl);
+
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static inline void hf_fill_route(u16 dst_isr, struct base_hdr *base_hdr_p)
+{
+ base_hdr_p->route_control = HFI_HW_DIRECT_ROUTE;
+}
+
+static int hf_copy_skb_to_fifo(struct hf_if *net_if,
+ struct sk_buff *skb,
+ char *dst,
+ u32 len,
+ u32 offset)
+{
+ u64 fifo_end;
+ u32 tail_room;
+ int rc;
+
+ fifo_end = (u64)(net_if->tx_fifo.addr) + net_if->tx_fifo.size;
+
+ tail_room = fifo_end - (u64)dst;
+ if (tail_room >= len) {
+ rc = skb_copy_bits(skb, offset, dst, len);
+ if (rc) {
+ printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+ "fail1 offset=0x%x, len=0x%x, rc=0x%x\n",
+ offset, len, rc);
+ return rc;
+ }
+ } else {
+ rc = skb_copy_bits(skb, offset, dst, tail_room);
+ if (rc) {
+ printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+ "fail2 offset=0x%x, len=0x%x, rc=0x%x\n",
+ offset, tail_room, rc);
+
+ return rc;
+ }
+ rc = skb_copy_bits(skb, offset + tail_room,
+ net_if->tx_fifo.addr, len - tail_room);
+ if (rc) {
+ printk(KERN_ERR "hf_copy_skb_to_fifo: skb_copy_bits"
+ "fail3 offset=0x%x, len=0x%x, rc=0x%x\n",
+ offset + tail_room, len - tail_room, rc);
+
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/* Build base_hdr and proto_hdr for payload pkt.
+ Return pointer to the end of proto_hdr */
+static char *hf_build_payload_hdr(struct hf_net *net,
+ struct sk_buff *skb,
+ u32 msg_len,
+ u32 xmit_cls,
+ u32 is_bcast)
+{
+ struct hf_if *net_if = &(net->hfif);
+ struct hf_if_proto_hdr *proto_hdr_p;
+ struct hfi_ip_with_payload_pkt *hdr_p;
+ char *dst;
+ u8 msg_type, msg_flag;
+ struct hf_hwhdr *hwhdr_p;
+
+ hwhdr_p = (struct hf_hwhdr *)(skb->data);
+
+ if (hwhdr_p->h_proto == htons(ETH_P_IP))
+ msg_type = HF_IF_FIFO;
+ else if (hwhdr_p->h_proto == htons(ETH_P_ARP))
+ msg_type = HF_IF_ARP;
+ else {
+ netdev_err(net->netdev, "hf_build_payload_hdr: h_proto = 0x%x "
+ " not supported\n", hwhdr_p->h_proto);
+
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
+
+ dst = net_if->tx_fifo.addr +
+ (net_if->tx_fifo.tail << HFI_CACHE_LINE_SHIFT);
+
+ /* fill in base_hdr + ip_extended_hdr */
+ hdr_p = (struct hfi_ip_with_payload_pkt *)dst;
+
+ /* Do not memset over one cacheline since it might wrap */
+ memset(hdr_p, 0, HF_IP_HDR_LEN);
+
+ hdr_p->hfi_hdr.type.header_type = HFI_IP_WITH_PAYLOAD;
+ hdr_p->hfi_hdr.id.job_id = net_if->client.job_id;
+
+ if (is_bcast) {
+ hdr_p->hfi_hdr.base_hdr.dst_isr = HFIDD_DST_BCST_ISR;
+ hdr_p->hfi_hdr.base_hdr.dst_win = HFIDD_DST_BCST_WIN;
+ hdr_p->hfi_hdr.type.header_type = HFI_IP_MULTICAST_WITH_PAYLOAD;
+
+ msg_flag = HF_IF_BCAST;
+ } else {
+ u16 dst_isr, dst_win;
+
+ hf_get_dst_info(hwhdr_p, &dst_isr, &dst_win);
+ hdr_p->hfi_hdr.base_hdr.dst_isr = dst_isr;
+ hdr_p->hfi_hdr.base_hdr.dst_win = dst_win;
+
+ hf_fill_route(dst_isr, &(hdr_p->hfi_hdr.base_hdr));
+
+ msg_flag = HF_IF_UCAST;
+ }
+
+ netdev_dbg(net->netdev, "hf_build_payload_hdr: dst_isr = 0x%x, "
+ "dst_win = 0x%x, xmit_cls = 0x%x\n",
+ hdr_p->hfi_hdr.base_hdr.dst_isr,
+ hdr_p->hfi_hdr.base_hdr.dst_win, xmit_cls);
+
+ hdr_p->hfi_hdr.base_hdr.pkt_len = hfi_cachelines_to_pktlen(xmit_cls);
+
+ dst += HF_IP_HDR_LEN;
+ proto_hdr_p = (struct hf_if_proto_hdr *)dst;
+
+ proto_hdr_p->version = HF_PROTO_HDR_VERSION;
+ proto_hdr_p->msg_len = msg_len;
+ proto_hdr_p->msg_id = net_if->msg_id;
+ proto_hdr_p->msg_type = msg_type;
+ proto_hdr_p->msg_flag = msg_flag;
+
+ dst += HF_PROTO_LEN;
+
+ return dst;
+}
+
+static int hf_payload_tx(struct sk_buff *skb, struct hf_net *net, u32 is_bcast)
+{
+ struct hf_if *net_if = &(net->hfif);
+ u32 msg_len, len;
+ u32 xmit_cls;
+ char *dst;
+ int rc = 0;
+
+ msg_len = skb->len - HF_HLEN + HF_PROTO_LEN;
+ xmit_cls = hfi_bytes_to_cacheline(msg_len + HF_IP_HDR_LEN);
+
+ if (is_bcast) {
+ if (xmit_cls <= HF_BCAST_CACHE_LINE_2)
+ xmit_cls = HF_BCAST_CACHE_LINE_2;
+ else
+ xmit_cls = HF_BCAST_CACHE_LINE_16;
+ }
+
+ rc = hf_tx_check_avail(net, xmit_cls);
+ if (rc) {
+ netdev_err(net->netdev, "hf_payload_tx: hf_tx_check_avail find "
+ "no avail slot\n");
+ return rc;
+ }
+
+ dst = hf_build_payload_hdr(net, skb, msg_len, xmit_cls, is_bcast);
+ if (!dst)
+ return 0;
+
+ /* copy skb data, skipping hwhdr */
+ len = skb->len - HF_HLEN;
+
+ rc = hf_copy_skb_to_fifo(net_if, skb, dst, len, HF_HLEN);
+ if (rc)
+ return rc;
+
+ net_if->tx_fifo.tail =
+ (net_if->tx_fifo.tail + xmit_cls) & (net_if->tx_fifo.emax);
+ atomic_sub(xmit_cls, &(net_if->tx_fifo.avail));
+
+ net_if->sfifo_packets++;
+ net_if->net_stats.tx_packets++;
+ net_if->net_stats.tx_bytes += msg_len;
+
+ netdev_dbg(net->netdev, "hf_payload_tx: exit, tx_fifo tail = 0x%x, "
+ "avail = 0x%x, skb->len = 0x%x\n", net_if->tx_fifo.tail,
+ atomic_read(&(net_if->tx_fifo.avail)), skb->len);
+
+ dev_kfree_skb_any(skb);
+ return 0;
+
+}
+
+static int hf_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct hf_net *net = netdev_priv(netdev);
+ struct hf_if *net_if = &(net->hfif);
+ u32 len, is_bcast;
+ u32 send_cnt = 1;
+
+ is_bcast = !memcmp(((struct hf_hwhdr *)(skb->data))->h_dest,
+ netdev->broadcast,
+ netdev->addr_len);
+
+ if (unlikely(skb->len <= 0)) {
+ netdev_err(netdev, "hf_start_xmit: invalid skb->len 0x%x\n",
+ skb->len);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /* total len to transfer */
+ len = skb->len - HF_HLEN;
+
+ if (len <= HF_PAYLOAD_MAX) {
+ /* send ip with payload */
+ if (hf_payload_tx(skb, net, is_bcast) < 0) {
+ netdev_err(netdev, "hf_start_xmit: "
+ "hf_payload_tx fail 1\n");
+
+ return NETDEV_TX_BUSY;
+ }
+ } else {
+ netdev_err(netdev, "hf_start_xmit: skb->len 0x%x "
+ "greater than max 0x%x\n",
+ skb->len, (u32)HF_PAYLOAD_MAX);
+
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /* Make sure all fields are written before ringing hw doorbell */
+ wmb();
+
+ /* ring doorbell */
+ hf_mmio_regs_write(net_if, HFI_SFIFO_DB_REG, send_cnt);
+
+ if (atomic_read(&net_if->tx_fifo.avail) < HF_TX_LOW_WATERMARK)
+ hf_tx_check_avail(net, HF_TX_LOW_WATERMARK);
+
+ net_if->msg_id++;
+ netdev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+}
+
+static void hf_tx_timeout(struct net_device *netdev)
+{
+ netdev_warn(netdev, "hf_tx_timeout: queue_stopped is %d\n",
+ netif_queue_stopped(netdev));
+}
+
struct net_device_stats *hf_get_stats(struct net_device *netdev)
{
struct hf_net *net = netdev_priv(netdev);
@@ -480,6 +910,8 @@ static const struct net_device_ops hf_netdev_ops = {
.ndo_open = hf_net_open,
.ndo_stop = hf_net_close,
.ndo_change_mtu = hf_change_mtu,
+ .ndo_start_xmit = hf_start_xmit,
+ .ndo_tx_timeout = hf_tx_timeout,
.ndo_set_mac_address = NULL,
.ndo_get_stats = hf_get_stats,
};
@@ -497,6 +929,7 @@ static void hf_if_setup(struct net_device *netdev)
netdev->header_ops = &hf_header_ops;
netdev->netdev_ops = &hf_netdev_ops;
+ netdev->watchdog_timeo = HF_TX_TIMEOUT;
netdev->features |= NETIF_F_SG;
memcpy(netdev->broadcast, hfi_bcast_addr, HF_ALEN);
@@ -534,7 +967,7 @@ static struct hf_net *hf_init_netdev(int idx, int ai)
if (rc) {
printk(KERN_ERR "hf_init_netdev: "
"failed to register netdev=hfi%d:hf%d, "
- "rc 0x%x\n", ai, idx, rc);
+ "rc = 0x%x\n", ai, idx, rc);
free_netdev(netdev);
return (struct hf_net *) -ENODEV;
}
@@ -601,6 +1034,7 @@ static void __exit hf_cleanup_module(void)
unregister_inetaddr_notifier(&hf_inet_notifier);
for (idx = 0; idx < MAX_HF_PER_HFI; idx++) {
for (ai = 0; ai < MAX_HFIS; ai++) {
+
net = hf_ginfo.net[idx][ai];
if (net != NULL) {
hf_del_netdev(net);
diff --git a/drivers/net/hfi/ip/hf_proto.h b/drivers/net/hfi/ip/hf_proto.h
index f2b159e..b7c6d3c 100644
--- a/drivers/net/hfi/ip/hf_proto.h
+++ b/drivers/net/hfi/ip/hf_proto.h
@@ -33,6 +33,7 @@
#ifndef _HF_PROTO_H_
#define _HF_PROTO_H_
+int hf_tx_check_avail(struct hf_net *net, u32 xmit_cls);
extern int hfidd_open_window_func(struct hfidd_acs *p_acs,
u32 is_userspace,
struct hfi_client_info *user_p,
diff --git a/include/linux/hfi/hf_if.h b/include/linux/hfi/hf_if.h
index d13c6ab..90b6331 100644
--- a/include/linux/hfi/hf_if.h
+++ b/include/linux/hfi/hf_if.h
@@ -43,6 +43,7 @@
#include <linux/hfi/hfidd_internal.h>
#include <linux/hfi/hfidd_client.h>
#include <linux/hfi/hfidd_requests.h>
+#include <linux/hfi/hfidd_regs.h>
#include <linux/hfi/hfidd_pkt_formats.h>
#define HF_DRV_VERSION "1.0"
@@ -51,15 +52,31 @@
#define MAX_HF_PER_HFI 2
#define HF_IP_JOBID 0xFFFFFFF0
+#define HF_TX_TIMEOUT (500 * HZ)
#define HF_MAX_NAME_LEN 64
+/* sfifo intr: bit 39-55 is threshold */
+/* bit 34 enable, bit 35 unmask */
+#define HF_SFIFO_INTR_ENABLE (0x3 << (63 - 35))
+#define HF_SFIFO_INTR_MASK 0x1FFFF /* 17 bits */
+#define HF_SFIFO_INTR_CNT_SHIFT (63 - 55)
+#define HF_SFIFO_INTR_EVENT 0x00000040 /* bit 57 */
+#define HF_SFIFO_INTR_WATERMARK (HF_SFIFO_SLOTS - (HF_SFIFO_SLOTS >> 3))
+
#define HF_SFIFO_SIZE 0x40000 /* 256K */
#define HF_SFIFO_SLOTS (HF_SFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
#define HF_RFIFO_SIZE 0x1000000 /* 16M */
#define HF_RFIFO_SLOTS (HF_RFIFO_SIZE >> HFI_CACHE_LINE_SHIFT)
+#define HF_TX_LOW_WATERMARK (HF_SFIFO_SLOTS >> 4)
#define HF_FV_BIT_CNT 32
-#define HF_NET_MTU (2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+#define HF_FV_BIT_MAX 31
+#define HF_SEND_ONE 1
+
+#define HF_PAYLOAD_MAX (2048 - HF_IP_HDR_LEN - HF_PROTO_LEN)
+#define HF_NET_MTU HF_PAYLOAD_MAX
+#define HF_PAYLOAD_RX_THRESHOLD 0x10ULL
+#define HF_PAYLOAD_RX_THRESH_SHIFT 59
struct hfi_ip_extended_hdr { /* 16B */
u32 immediate_len:7;/* In bytes */
@@ -91,6 +108,15 @@ struct hf_hwhdr {
#define HF_HLEN sizeof(struct hf_hwhdr)
#define HF_ALIGN_PAD 2
+#define HF_PROTO_HDR_VERSION 0x1
+/* HFI protocol message type */
+#define HF_IF_ARP 0xA0
+#define HF_IF_FIFO 0xA1
+
+/* HFI protocol message flag */
+#define HF_IF_UCAST 0xB0
+#define HF_IF_BCAST 0xB1
+
struct hf_if_proto_hdr {
u16 version;
u8 msg_type;
@@ -100,6 +126,8 @@ struct hf_if_proto_hdr {
};
#define HF_PROTO_LEN sizeof(struct hf_if_proto_hdr)
+#define HF_BCAST_CACHE_LINE_16 16
+#define HF_BCAST_CACHE_LINE_2 2
struct hf_fifo {
void *addr;
@@ -126,6 +154,7 @@ struct hf_if {
u32 sfifo_fv_polarity;
u32 sfifo_slots_per_blk;
u32 sfifo_packets;
+ u32 msg_id;
void __iomem *doorbell; /* mapped mmio_regs */
struct hf_fifo tx_fifo;
struct hf_fifo rx_fifo;
@@ -152,5 +181,47 @@ struct hf_global_info {
extern struct hf_global_info hf_ginfo;
+#define HF_EVENT_NUM 1
+
+struct hf_events_cb {
+ enum hfi_event_type type;
+ void *func;
+};
+
#define HF_MAC_HFI_SHIFT 12
+#define HF_HDR_HFI_SHIFT 8
+
+static inline u32 hf_get_win(u16 id)
+{
+ return ((id >> HF_MAC_HFI_SHIFT) << HF_HDR_HFI_SHIFT) | (id & 0xFF);
+}
+
+static inline void hf_get_dst_info(struct hf_hwhdr *hwhdr_p,
+ u16 *d_isr,
+ u16 *d_win)
+{
+ *d_isr = (*(u16 *)(&(hwhdr_p->h_dest[2]))) & 0xFFF;
+ *d_win = hf_get_win(*(u16 *)(&(hwhdr_p->h_dest[4])));
+}
+
+static inline void hf_mmio_regs_write_then_read(struct hf_if *net_if,
+ int off,
+ u64 data)
+{
+ __raw_writeq(data, net_if->doorbell + off);
+ isync();
+ __raw_readq(net_if->doorbell + off);
+ /* Make sure all received pkt shows up in rfifo */
+ mb();
+}
+
+static inline u64 hf_mmio_regs_read(struct hf_if *net_if, int off)
+{
+ return __raw_readq(net_if->doorbell + off);
+}
+
+static inline void hf_mmio_regs_write(struct hf_if *net_if, int off, u64 data)
+{
+ __raw_writeq(data, net_if->doorbell + off);
+}
#endif
--
1.7.3.1
^ permalink raw reply related
* [PATCH 06/27] HFI: Add DD calls to START/STOP INTERFACE HCALLs
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_init.c | 98 +++++++++++++++++++++++++++++++++++++
1 files changed, 98 insertions(+), 0 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index fcdbd03..9dfd2b4 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -319,6 +319,94 @@ hfidd_create_devices_error0:
return rc;
}
+/*
+ * Disable message passing to each adapter by calling the
+ * Stop Interface hcall.
+ */
+static void hfidd_stop_adapter(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_HFIS; i++) {
+ hfidd_stop_interface(hfidd_global.p_acs[i],
+ hfidd_global.p_acs[i]->dds.hfi_id);
+ }
+ return;
+}
+
+/*
+ * Query the interface to check the logical state of HFI.
+ * Enable message passing to each adapter by calling Start
+ * Interface hcall.
+ */
+static int hfidd_start_adapter(void)
+{
+ unsigned long long hfi_state;
+ int i, j;
+ int rc = 0;
+
+ for (i = 0; i < MAX_HFIS; i++) {
+ rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
+ hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
+ if (hfi_state != NOT_STARTED) {
+ rc = hfidd_stop_interface(hfidd_global.p_acs[i],
+ hfidd_global.p_acs[i]->dds.hfi_id);
+ if (rc) {
+ dev_printk(KERN_ERR,
+ hfidd_global.p_acs[i]->hfidd_dev,
+ "%s: hfidd_start_adapter:"
+ " hfidd_stop_interface failed rc = "
+ " 0x%x\n", hfidd_global.p_acs[i]->name,
+ rc);
+ }
+
+ rc = hfidd_query_interface(hfidd_global.p_acs[i],
+ COMP_QUERY,
+ hfidd_global.p_acs[i]->dds.hfi_id,
+ &hfi_state);
+ if (hfi_state != NOT_STARTED) {
+ dev_printk(KERN_ERR,
+ hfidd_global.p_acs[i]->hfidd_dev,
+ "%s: hfidd_start_adapter: query"
+ " interface bad state 0x%llx\n",
+ hfidd_global.p_acs[i]->name, hfi_state);
+ return -EIO;
+ }
+ }
+
+ }
+
+ for (i = 0; i < MAX_HFIS; i++) {
+ rc = hfidd_start_interface(hfidd_global.p_acs[i]);
+ if (rc) {
+ dev_printk(KERN_ERR, hfidd_global.p_acs[i]->hfidd_dev,
+ "%s: hfidd_start_adapter: "
+ "hfidd_start_interface failed rc = "
+ "%d\n", hfidd_global.p_acs[i]->name, rc);
+ goto hfidd_start_adapter_err;
+ }
+
+ /* query interface to get src ISR */
+ rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
+ hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
+ if (rc) {
+ dev_printk(KERN_ERR, hfidd_global.p_acs[i]->hfidd_dev,
+ "%s: hfidd_start_adapter: "
+ "hfidd_query_interface failed rc = %d\n",
+ hfidd_global.p_acs[i]->name, rc);
+ goto hfidd_start_adapter_err;
+ }
+ }
+ return 0;
+
+hfidd_start_adapter_err:
+ for (j = 0; j < i; j++) {
+ hfidd_stop_interface(hfidd_global.p_acs[j],
+ hfidd_global.p_acs[j]->dds.hfi_id);
+ }
+ return rc;
+}
+
static int __init hfidd_mod_init(void)
{
int rc = 0;
@@ -339,9 +427,18 @@ static int __init hfidd_mod_init(void)
goto error1;
}
+ rc = hfidd_start_adapter();
+ if (rc < 0) {
+ printk(KERN_ERR "%s: hfidd_mod_init: hfidd_start_adapter failed"
+ " rc = %d\n", HFIDD_DEV_NAME, rc);
+ goto error2;
+ }
+
printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
return 0;
+error2:
+ hfidd_destroy_devices();
error1:
hfidd_destroy_class();
@@ -351,6 +448,7 @@ error1:
static void __exit hfidd_mod_exit(void)
{
+ hfidd_stop_adapter();
hfidd_destroy_devices();
hfidd_destroy_class();
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 10/27] HFI: HFIDD_REQ_OPEN_WINDOW request
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Set up protocol access to an HFI window.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/Makefile | 1 +
drivers/net/hfi/core/hfidd_init.c | 14 +++++++
drivers/net/hfi/core/hfidd_proto.h | 3 +
drivers/net/hfi/core/hfidd_window.c | 70 +++++++++++++++++++++++++++++++++++
include/linux/hfi/hfidd_client.h | 22 +++++++++++
include/linux/hfi/hfidd_internal.h | 26 +++++++++++++
include/linux/hfi/hfidd_requests.h | 1 +
7 files changed, 137 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/hfi/core/hfidd_window.c
diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 4e6cbd6..0224a57 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -2,6 +2,7 @@
# Makefile for the HFI device driver for IBM eServer System p
#
hfi_core-objs:= hfidd_adpt.o \
+ hfidd_window.o \
hfidd_init.o \
hfidd_hcalls.o
obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index a57f247..1008260 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -130,6 +130,20 @@ static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
}
switch (cmd.req) {
+ case HFIDD_REQ_OPEN_WINDOW:
+ if (cmd.req_len != sizeof(struct hfi_client_info)) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_cmd_write: hdr.reqlen 0x%x expected "
+ "0x%lx for cmd req 0x%x\n",
+ cmd.req_len,
+ sizeof(struct hfi_client_info), cmd.req);
+ return -EINVAL;
+ }
+ rc = hfidd_open_window_func(p_acs, is_userspace,
+ (struct hfi_client_info *) buf,
+ (struct hfi_client_info *) cmd.result.use.kptr);
+ break;
+
case HFIDD_REQ_QUERY_DD_INFO:
if (cmd.req_len != sizeof(struct hfi_query_dd_info)) {
dev_printk(KERN_ERR, p_acs->hfidd_dev,
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index c61387e..e7f2901 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -39,6 +39,9 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs);
void hfidd_free_windows(struct hfidd_acs *p_acs);
int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
int hfidd_age_hcall(u64 time_start);
+int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+ struct hfi_client_info *user_p,
+ struct hfi_client_info *out_p);
int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
caddr_t *laddr, int size);
void hfidd_release_phyp_page(caddr_t page, int size);
diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c
new file mode 100644
index 0000000..f16caf7
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_window.c
@@ -0,0 +1,70 @@
+/*
+ * hfidd_window.c
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include <linux/hfi/hfidd_hcalls.h>
+#include "hfidd_proto.h"
+#include <linux/hfi/hfidd_requests.h>
+
+/*
+ * Allows an user/kernel window to send/receive network traffic thru HFI
+ * adapter. This function will allocate the system resources needed to open
+ * a window. If any problem detected, then the request will fail. This function
+ * is called directly by kernel users and by a write system call by userspace.
+ */
+int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace,
+ struct hfi_client_info *user_p,
+ struct hfi_client_info *out_p)
+{
+ int rc = 0;
+ struct hfi_client_info *local_p = NULL;
+
+ /* Allocate local data structure */
+ local_p = kmalloc(sizeof(struct hfi_client_info), GFP_KERNEL);
+ if (local_p == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "open_window_func: kmalloc local_p failed\n");
+ return -ENOMEM;
+ }
+
+ /* Copy into local from user */
+ rc = hfi_copy_from_user((void *)local_p, (void *)user_p,
+ is_userspace, sizeof(struct hfi_client_info));
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "open_window_func: hfi_copy_from_user failed\n");
+ }
+
+ kfree(local_p);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(hfidd_open_window_func);
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index c3c8fef..7e4c1a7 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -69,6 +69,28 @@ struct fifo_info {
unsigned long long size; /* bytes */
};
+/*
+ * HFIDD_REQ_OPEN_WINDOW: Window Open
+ * For reserved windows
+ * The job scheduler provides the application with window number and
+ * jobid, which need to be passed in/will be checked on the window open.
+ * Immediate send slots were also reserved by the job scheduler, and the
+ * DD returns the count. The application has the option of setting
+ * protection keys by task or by jobid. Protection key is passed in.
+ * For Dynamic windows
+ * The DD will select a free dynamic window and return its window number.
+ * The jobid will be assigned by the DD (upper bits set to select a
+ * reserved range of jobids, lower bits come from userid). The
+ * protection key flag is always by task. The protection key is passed in.
+ * For Kernel/IP windows
+ * The DD will select a free dynamic window and return its window number.
+ * The jobid is passed in. The jobid is used for the protection key.
+ *
+ * Finished vectors:
+ * sfifo_finishvec and imm_finishvec must reside in an extra page (last
+ * page) in the sfifo memory range, provided by the user.
+ */
+
#define HFIDD_IP_WIN 1 /* IP windows get broadcasts forwarded
to them... */
#define HFIDD_KERNEL_WIN 2 /* ... other kernel windows do not */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index a36c244..dd1ce4c 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -142,4 +142,30 @@ struct hfidd_global {
struct hfidd_acs *p_acs[MAX_HFIS];
};
+static inline int hfi_copy_to_user(void *user_p, void *local_p,
+ unsigned int is_userspace, unsigned int size)
+{
+ int rc = 0;
+
+ if (is_userspace)
+ rc = copy_to_user(user_p, local_p, size);
+ else
+ memcpy(user_p, local_p, size);
+
+ return rc;
+}
+
+static inline int hfi_copy_from_user(void *local_p, void *user_p,
+ unsigned int is_userspace, unsigned int size)
+{
+ int rc = 0;
+
+ if (is_userspace)
+ rc = copy_from_user(local_p, user_p, size);
+ else
+ memcpy(local_p, user_p, size);
+
+ return rc;
+}
+
#endif
diff --git a/include/linux/hfi/hfidd_requests.h b/include/linux/hfi/hfidd_requests.h
index b6e255f..4f1c74d 100644
--- a/include/linux/hfi/hfidd_requests.h
+++ b/include/linux/hfi/hfidd_requests.h
@@ -33,6 +33,7 @@
#ifndef _HFIDD_REQUESTS_H_
#define _HFIDD_REQUESTS_H_
+#define HFIDD_REQ_OPEN_WINDOW 0x00000a01
#define HFIDD_REQ_QUERY_DD_INFO 0x00001004
#endif /* _HFIDD_REQUESTS_H_ */
--
1.7.3.1
^ permalink raw reply related
* [PATCH 09/27] HFI: Add HFI window resource tracking
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
An HFI window is very roughly similar to an infiniband UD queue pair.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_adpt.c | 65 ++++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_proto.h | 2 +
include/linux/hfi/hfidd_adpt.h | 10 +++++
include/linux/hfi/hfidd_client.h | 27 +++++++++++++++
include/linux/hfi/hfidd_internal.h | 43 +++++++++++++++++++++++
5 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index feb1b59..372eeec 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -66,6 +66,16 @@ int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
goto err_exit0;
*adpt = p_acs;
+
+ /* alloc window structures */
+ ret = hfidd_alloc_windows(p_acs);
+ if (ret) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_alloc_adapter: hfidd_alloc_windows failed, "
+ "ret = 0x%x\n", ret);
+ goto err_exit0;
+ }
+
return 0;
err_exit0:
@@ -76,11 +86,66 @@ err_exit0:
void hfidd_free_adapter(struct hfidd_acs *p_acs)
{
+ hfidd_free_windows(p_acs);
kfree(p_acs);
p_acs = NULL;
return;
}
+int hfidd_alloc_windows(struct hfidd_acs *p_acs)
+{
+ int i;
+
+ p_acs->win = kzalloc(sizeof(*p_acs->win) * p_acs->dds.window_num,
+ GFP_KERNEL);
+
+ if (p_acs->win == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_alloc_windows: kzalloc p_acs->win failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < p_acs->dds.window_num; i++) {
+ p_acs->win[i] = kzalloc(sizeof(*(p_acs->win[i])),
+ GFP_KERNEL);
+ if (p_acs->win[i] == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_alloc_windows: kzalloc win 0x%x "
+ "failed\n", i);
+ hfidd_free_windows(p_acs);
+ return -ENOMEM;
+ }
+
+ /* Initialize window fields */
+ spin_lock_init(&(p_acs->win[i]->win_lock));
+
+ p_acs->win[i]->ai = p_acs->index;
+ p_acs->win[i]->index = p_acs->dds.window_start + i;
+
+ if (p_acs->win[i]->index < (p_acs->dds.window_start +
+ MAX_D_WIN_PER_HFI)) {
+ p_acs->win[i]->type = HFIDD_DYNAMIC_WIN;
+ } else {
+ p_acs->win[i]->type = HFIDD_RESERVE_WIN;
+ }
+ p_acs->win[i]->state = WIN_AVAILABLE;
+ }
+ return 0;
+}
+
+void hfidd_free_windows(struct hfidd_acs *p_acs)
+{
+ int i;
+
+ for (i = 0; i < p_acs->dds.window_num; i++) {
+ kfree(p_acs->win[i]);
+ p_acs->win[i] = NULL;
+ }
+ kfree(p_acs->win);
+ p_acs->win = NULL;
+ return;
+}
+
/* Allocate the page for the HCALL */
int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page, caddr_t *laddr,
int size)
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 320f41f..c61387e 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -35,6 +35,8 @@
int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
void hfidd_free_adapter(struct hfidd_acs *p_acs);
+int hfidd_alloc_windows(struct hfidd_acs *p_acs);
+void hfidd_free_windows(struct hfidd_acs *p_acs);
int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
int hfidd_age_hcall(u64 time_start);
int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index e3271e9..babdb14 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -47,4 +47,14 @@
#define HFI_GOING_UNAVAIL 2
#define HFI_UNAVAIL 3
+/* HFI window states */
+#define WIN_AVAILABLE 0
+#define WIN_RESERVED 1
+#define WIN_OPENED 2
+#define WIN_SUSPENDED 3
+#define WIN_ERROR 4
+#define WIN_HERROR 5
+#define WIN_PENDING 6
+#define WIN_FAIL_CLOSE 7
+
#endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index b2ebd01..c3c8fef 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -64,6 +64,33 @@ struct hfi_req_hdr {
};
#define HFIDD_REQ_HDR_SIZE sizeof(struct hfi_req_hdr)
+struct fifo_info {
+ struct hfi_64b eaddr;
+ unsigned long long size; /* bytes */
+};
+
+#define HFIDD_IP_WIN 1 /* IP windows get broadcasts forwarded
+ to them... */
+#define HFIDD_KERNEL_WIN 2 /* ... other kernel windows do not */
+#define HFIDD_RESERVE_WIN 3 /* Must be reserved by job scheduler */
+#define HFIDD_DYNAMIC_WIN 4 /* First come, first served. Window# is
+ returned */
+struct hfi_client_info {
+ struct hfi_req_hdr hdr;
+
+ unsigned int window;
+ unsigned int win_type; /* HFIDD_*_WIN */
+ unsigned int job_id;
+ unsigned int protection_key_flag;
+ unsigned int protection_key;
+ unsigned int local_isrid; /* Output */
+ struct fifo_info sfifo;
+ struct fifo_info rfifo;
+ struct hfi_64b sfifo_finish_vec;
+ unsigned int sfifo_lkey; /* Output */
+ struct hfi_64b mmio_regs; /* Output */
+};
+
#define MAX_TORRENTS 1
#define MAX_HFI_PER_TORRENT 2
#define MAX_HFIS (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 311f906..a36c244 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -59,9 +59,13 @@
#include <asm/pgalloc.h>
#include <asm/ibmebus.h>
#include <linux/kthread.h>
+
#include <linux/hfi/hfidd_client.h>
#include <linux/hfi/hfidd_adpt.h>
#include <linux/hfi/hfidd_hcalls.h>
+
+#define MAX_D_WIN_PER_HFI (p_acs->dds.num_d_windows)
+
#define HFIDD_DEV_NAME "hfi"
#define HFIDD_CLASS_NAME "hfi"
@@ -76,6 +80,44 @@ struct hfidd_dds {
unsigned long long fw_ec_level; /* Firmware Level */
};
+struct hfidd_fifo {
+ unsigned long long eaddr;
+ unsigned long long size;
+};
+
+#define IRQ_NAME_SIZE 20
+
+struct hfidd_window {
+ spinlock_t win_lock; /* lock for window */
+ int index;
+ unsigned int type; /* dynamic/scheduled */
+ int state;
+
+ unsigned int ai; /* index to p_acs */
+ unsigned int is_ip;
+
+ unsigned int job_id;
+ unsigned int pid;
+ unsigned int protection_key_flag; /* by job/task */
+
+ unsigned int recv_intr; /* Recv interrupt */
+ unsigned int send_intr; /* Send interrupt */
+ char recv_name[IRQ_NAME_SIZE];
+ char send_name[IRQ_NAME_SIZE];
+
+ uid_t uid;
+
+ struct hfi_client_info client_info; /* From user input */
+ struct win_open_info *win_open_info_p; /* virtual addr
+ OPEN_WINDOW hcall */
+ caddr_t win_open_info_laddr; /* logical addr
+ OPEN_WINDOW hcall */
+ unsigned long long mmio_regs; /* logical addr from
+ OPEN WINDOW hcall */
+ struct hfidd_vlxmem *sfifo_x_tab;
+ struct hfidd_vlxmem *rfifo_x_tab;
+};
+
#define HFI_DEVICE_NAME_MAX 64
/* hfi global */
struct hfidd_acs {
@@ -87,6 +129,7 @@ struct hfidd_acs {
unsigned int isr;
+ struct hfidd_window **win;
struct device *hfidd_dev;
struct hfidd_dds dds;
};
--
1.7.3.1
^ permalink raw reply related
* [PATCH 04/27] HFI: Find HFI devices in the device tree
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_adpt.c | 10 +++
drivers/net/hfi/core/hfidd_init.c | 108 ++++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_proto.h | 1 +
include/linux/hfi/hfidd_adpt.h | 5 ++
include/linux/hfi/hfidd_client.h | 3 +
include/linux/hfi/hfidd_internal.h | 12 ++++
6 files changed, 139 insertions(+), 0 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index d64fa38..d5065cf 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -36,6 +36,7 @@
int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
{
+ int ret = 0;
struct hfidd_acs *p_acs = NULL;
p_acs = kzalloc(sizeof(*p_acs), GFP_KERNEL);
@@ -48,8 +49,17 @@ int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
snprintf(p_acs->name, HFI_DEVICE_NAME_MAX - 1,
"%s%d", HFIDD_DEV_NAME, p_acs->index);
+ ret = hfidd_init_adapter(p_acs, uiop);
+ if (ret)
+ goto err_exit0;
+
*adpt = p_acs;
return 0;
+
+err_exit0:
+ kfree(p_acs);
+ p_acs = NULL;
+ return ret;
}
void hfidd_free_adapter(struct hfidd_acs *p_acs)
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 68d6e65..fcdbd03 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/hfi/hfidd_internal.h>
#include "hfidd_proto.h"
@@ -104,6 +105,113 @@ static void hfidd_rmdev(int ai)
device_destroy(hfidd_global.class, MKDEV(MAJOR(hfidd_dev), ai));
}
+/*
+ * Read the hfi device tree attributes and
+ * fill the hfidd_dds structure to be used by the driver
+ */
+static int hfidd_dds_init(struct hfidd_acs *p_acs, struct hfidd_dds *pdds)
+{
+ struct device_node *node;
+ struct device_node *child_node = NULL;
+ unsigned long long *lp;
+ int *p;
+ unsigned char octant;
+ unsigned char id;
+ int found = 0;
+
+ node = of_find_node_by_name(NULL, "hfi-iohub");
+ if (!node) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_find_node_by_name"
+ " 'hfi-iohub' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+
+ lp = (unsigned long long *)of_get_property(node, "reg", NULL);
+ if (!lp) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+ " 'hfi-iohub/reg' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+ pdds->torr_id = *lp;
+
+ lp = (unsigned long long *)of_get_property(node,
+ "ibm,fw-ec-level", NULL);
+ if (!lp) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+ " 'ibm,fw-ec-level' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+ pdds->fw_ec_level = *lp;
+
+ octant = (node->full_name[strlen(node->full_name) - 1] - '0');
+ if (octant > HFI_MAX_OCTANT) {
+ printk(KERN_ERR "%s: hfidd_dds_init: invalid hfi-iohub octant"
+ " '%s'\n", node->full_name, p_acs->name);
+ return -EINVAL;
+ }
+
+ id = ((octant << HFI_SHIFT_OCTANT) | p_acs->index);
+
+ while ((child_node = of_get_next_child(node, child_node))) {
+ p = (int *)of_get_property(child_node, "reg", NULL);
+ if (!p) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_get_property "
+ "'reg' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+
+ if (id == *p) {
+ pdds->hfi_id = *p;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ printk(KERN_ERR "%s: hfidd_dds_init: can not find child\n",
+ p_acs->name);
+ return -EINVAL;
+ }
+
+ lp = (unsigned long long *)of_get_property(child_node,
+ "ibm,hfi-windows", NULL);
+ if (!lp) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+ " 'ibm,hfi-windows' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+
+ pdds->window_num = (int) (*lp >> HFI_WNUM_SHIFT);
+ pdds->window_start = (int) *lp;
+
+ if (pdds->window_num > MAX_WIN_PER_HFI) {
+ printk(KERN_ERR "%s: hfidd_dds_init: Max windows exceeded,"
+ " windows=%d\n", p_acs->name, pdds->window_num);
+ return -EINVAL;
+ }
+
+ lp = (unsigned long long *)of_get_property(child_node,
+ "ibm,hfi-misc-user-base-addr", NULL);
+ if (!lp) {
+ printk(KERN_ERR "%s: hfidd_dds_init: of_get_property"
+ " 'ibm,hfi-misc-user-base-addr' failed\n", p_acs->name);
+ return -EINVAL;
+ }
+ pdds->misc_base_address = *lp;
+
+ return 0;
+}
+
+/* Initialize adapter structure */
+int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop)
+{
+ int rc = 0;
+
+ rc = hfidd_dds_init(p_acs, &(p_acs->dds));
+ p_acs->dds.num_d_windows = HFI_DYN_WINS_DEFAULT;
+ return rc;
+}
+
/* Destroy the HFI class */
static inline void hfidd_destroy_class(void)
{
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 01a5ba2..e2ed4c9 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -35,5 +35,6 @@
int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
void hfidd_free_adapter(struct hfidd_acs *p_acs);
+int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
#endif
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
index 6b1432d..e3271e9 100644
--- a/include/linux/hfi/hfidd_adpt.h
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -36,6 +36,11 @@
#include <linux/hfi/hfidd_client.h>
+#define HFI_WNUM_SHIFT 32
+#define HFI_CAUNUM_SHIFT 32
+#define HFI_SHIFT_OCTANT 3
+#define HFI_MAX_OCTANT 7
+
/* Adpt state */
#define HFI_INVALID 0
#define HFI_AVAIL 1
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index b738f4b..28f1693 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -36,5 +36,8 @@
#define MAX_TORRENTS 1
#define MAX_HFI_PER_TORRENT 2
#define MAX_HFIS (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
+#define MAX_WIN_PER_HFI 256
+
+#define HFI_DYN_WINS_DEFAULT 32
#endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 695d7f4..fafca96 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -46,6 +46,17 @@
#define HFIDD_DEV_NAME "hfi"
#define HFIDD_CLASS_NAME "hfi"
+struct hfidd_dds {
+ unsigned int version; /* HFI adapter type */
+ unsigned long long misc_base_address; /* Misc user base address */
+ int window_start; /* window start for this HFI */
+ int window_num; /* window count for this HFI */
+ unsigned int num_d_windows; /* number of dynamic windows */
+ unsigned long long torr_id; /* torrent chip id */
+ unsigned int hfi_id; /* HFI Unit Id */
+ unsigned long long fw_ec_level; /* Firmware Level */
+};
+
#define HFI_DEVICE_NAME_MAX 64
/* hfi global */
struct hfidd_acs {
@@ -55,6 +66,7 @@ struct hfidd_acs {
unsigned int acs_cnt;
unsigned int state;
struct device *hfidd_dev;
+ struct hfidd_dds dds;
};
/* DD global */
--
1.7.3.1
^ permalink raw reply related
* [PATCH 07/27] HFI: Add nMMU start/stop hypervisor calls
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
H_NMMU_START resets/inits state for the nMMU in the hypervisor.
H_NMMU_STOP cleans up hypervisor nMMU state, called on DD unload after HFIs are
stopped.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_adpt.c | 36 +++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_hcalls.c | 33 ++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_init.c | 29 +++++++++++++++++++++++++--
drivers/net/hfi/core/hfidd_proto.h | 3 ++
include/linux/hfi/hfidd_hcalls.h | 2 +
5 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index bec838a..feb1b59 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -164,6 +164,42 @@ query1:
return rc;
}
+int hfidd_start_nmmu(struct hfidd_acs *p_acs)
+{
+ long long hvrc;
+ int rc = 0;
+ struct nmmu_info *nmmu_info;
+ caddr_t laddr = NULL;
+ u64 start_time = get_jiffies_64();
+
+ rc = hfidd_get_phyp_page(p_acs, (caddr_t *)&nmmu_info, &laddr,
+ PAGE_SIZE_4K);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_start_nmmu: hfidd_get_phyp_page failed\n");
+ return -ENOMEM;
+ }
+
+ while (1) {
+ hvrc = hfi_start_nmmu(p_acs->dds.torr_id,
+ (struct nmmu_info *) laddr);
+ if (hvrc != H_BUSY)
+ break;
+ if (hfidd_age_hcall(start_time))
+ break;
+ }
+
+ if (hvrc != H_SUCCESS) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_start_nmmu: HFI_START_NMMU failed "
+ "hvrc 0x%llx\n", hvrc);
+ rc = -EPERM;
+ }
+
+ hfidd_release_phyp_page((caddr_t)nmmu_info, PAGE_SIZE_4K);
+ return rc;
+}
+
int hfidd_start_interface(struct hfidd_acs *p_acs)
{
long long hvrc = 0;
diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
index 84467b3..2ca1c8a 100644
--- a/drivers/net/hfi/core/hfidd_hcalls.c
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -33,6 +33,18 @@
#include <linux/hfi/hfidd_internal.h>
#include "hfidd_proto.h"
+static inline long long h_nmmu_start(int token,
+ u64 torrent_chip_ID,
+ void *output_page_ptr)
+{
+ return plpar_hcall_norets(token, torrent_chip_ID, output_page_ptr);
+}
+
+static inline long long h_nmmu_stop(int token, u64 torrent_chip_ID)
+{
+ return plpar_hcall_norets(token, torrent_chip_ID);
+}
+
static inline long long h_hfi_start_interface(int token,
u64 HFI_chip_ID)
{
@@ -61,6 +73,27 @@ static inline long long h_hfi_query_interface(int token,
return rc;
}
+long long hfi_start_nmmu(u64 chip_id, void *nmmu_info)
+{
+ return h_nmmu_start(H_NMMU_START, chip_id, nmmu_info);
+}
+
+long long hfi_stop_nmmu(u64 chip_id)
+{
+ long long hvrc;
+ u64 start_time = get_jiffies_64();
+
+ while (1) {
+ hvrc = h_nmmu_stop(H_NMMU_STOP,
+ chip_id);
+ if (hvrc != H_BUSY)
+ break;
+ if (hfidd_age_hcall(start_time))
+ break;
+ }
+ return hvrc;
+}
+
long long hfi_hquery_interface(u64 unit_id, u64 subtype,
u64 query_p, u64 *state)
{
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 9dfd2b4..448349d 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -321,31 +321,44 @@ hfidd_create_devices_error0:
/*
* Disable message passing to each adapter by calling the
- * Stop Interface hcall.
+ * Stop Interface hcall and free phyp NMMU tables for this
+ * lpar by calling STOP NMMU
*/
static void hfidd_stop_adapter(void)
{
int i;
+ long long hvrc;
for (i = 0; i < MAX_HFIS; i++) {
hfidd_stop_interface(hfidd_global.p_acs[i],
hfidd_global.p_acs[i]->dds.hfi_id);
}
+ hvrc = hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
+ if (hvrc != H_SUCCESS)
+ dev_printk(KERN_ERR, hfidd_global.p_acs[0]->hfidd_dev,
+ "%s: hfidd_stop_adapter: HFI_STOP_NMMU failed"
+ " hvrc = 0x%llx\n", HFIDD_DEV_NAME, hvrc);
return;
}
/*
* Query the interface to check the logical state of HFI.
- * Enable message passing to each adapter by calling Start
- * Interface hcall.
+ * Initialize the phyp NMMU tables for this lpar by calling
+ * the START NMMU hcall and enable message passing to each
+ * adapter by calling Start Interface hcall.
*/
static int hfidd_start_adapter(void)
{
+ long long hvrc;
unsigned long long hfi_state;
int i, j;
int rc = 0;
for (i = 0; i < MAX_HFIS; i++) {
+ /* query interface before doing START_NMMU.
+ * If we crashed the LPAR a few minutes ago, we never did the
+ * stop interface and the stop nmmu. Do it now.
+ */
rc = hfidd_query_interface(hfidd_global.p_acs[i], COMP_QUERY,
hfidd_global.p_acs[i]->dds.hfi_id, &hfi_state);
if (hfi_state != NOT_STARTED) {
@@ -376,6 +389,15 @@ static int hfidd_start_adapter(void)
}
+ hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
+ hvrc = hfidd_start_nmmu(hfidd_global.p_acs[0]);
+ if (hvrc != H_SUCCESS) {
+ dev_printk(KERN_ERR, hfidd_global.p_acs[0]->hfidd_dev,
+ "%s: hfidd_start_adapter: HFI_START_NMMU failed"
+ " hvrc = 0x%llx\n", HFIDD_DEV_NAME, hvrc);
+ return -EIO;
+ }
+
for (i = 0; i < MAX_HFIS; i++) {
rc = hfidd_start_interface(hfidd_global.p_acs[i]);
if (rc) {
@@ -404,6 +426,7 @@ hfidd_start_adapter_err:
hfidd_stop_interface(hfidd_global.p_acs[j],
hfidd_global.p_acs[j]->dds.hfi_id);
}
+ hfi_stop_nmmu(hfidd_global.p_acs[0]->dds.torr_id);
return rc;
}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index 6ec9245..320f41f 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -42,8 +42,11 @@ int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
void hfidd_release_phyp_page(caddr_t page, int size);
int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
unsigned int hfi_id, unsigned long long *state);
+int hfidd_start_nmmu(struct hfidd_acs *p_acs);
int hfidd_start_interface(struct hfidd_acs *p_acs);
int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
+long long hfi_start_nmmu(u64 chip_id, void *nmmu_info);
+long long hfi_stop_nmmu(u64 chip_id);
long long hfi_hquery_interface(u64 unit_id, u64 subtype, u64 query_p,
u64 *state);
long long hfi_start_interface(u64 unit_id);
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
index 5349e9e..2a374e6 100644
--- a/include/linux/hfi/hfidd_hcalls.h
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -39,6 +39,8 @@
#define H_HFI_START_INTERFACE 0xF000
#define H_HFI_QUERY_INTERFACE 0xF004
#define H_HFI_STOP_INTERFACE 0xF008
+#define H_NMMU_START 0xF028
+#define H_NMMU_STOP 0xF02C
#define EEH_QUERY 1
#define COMP_QUERY 2
--
1.7.3.1
^ permalink raw reply related
* [PATCH 05/27] HFI: The first few HFI-specific hypervisor calls
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
H_HFI_START_INTERFACE Notifies the hypervisor that a new instance of the DD is
starting, and any leftover state should be considered stale.
H_HFI_STOP_INTERFACE tells the hypervisor that the DD is unloading, and to
clean up any activity related to this DD instance.
H_HFI_QUERY_INTERFACE lets us get info about the HFIs that is not in the
device tree.
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/Makefile | 3 +-
drivers/net/hfi/core/hfidd_adpt.c | 139 +++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_hcalls.c | 90 ++++++++++++++++++++++
drivers/net/hfi/core/hfidd_proto.h | 12 +++
include/linux/hfi/hfidd_client.h | 8 ++
include/linux/hfi/hfidd_hcalls.h | 58 +++++++++++++++
include/linux/hfi/hfidd_internal.h | 7 ++-
7 files changed, 315 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/hfi/core/hfidd_hcalls.c
create mode 100644 include/linux/hfi/hfidd_hcalls.h
diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 6fe4e60..4e6cbd6 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -2,5 +2,6 @@
# Makefile for the HFI device driver for IBM eServer System p
#
hfi_core-objs:= hfidd_adpt.o \
- hfidd_init.o
+ hfidd_init.o \
+ hfidd_hcalls.o
obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
index d5065cf..bec838a 100644
--- a/drivers/net/hfi/core/hfidd_adpt.c
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -33,6 +33,18 @@
#include <linux/hfi/hfidd_internal.h>
#include "hfidd_proto.h"
+#define HFIDD_TIME_AGE (10 * HZ)
+
+int hfidd_age_hcall(u64 time_start)
+{
+ u64 timestamp = get_jiffies_64();
+
+ if ((timestamp - time_start) > HFIDD_TIME_AGE)
+ return 1;
+ else
+ return 0;
+}
+
int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
{
@@ -68,3 +80,130 @@ void hfidd_free_adapter(struct hfidd_acs *p_acs)
p_acs = NULL;
return;
}
+
+/* Allocate the page for the HCALL */
+int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page, caddr_t *laddr,
+ int size)
+{
+ *page = (caddr_t)__get_free_pages(GFP_KERNEL, get_order(size));
+ if (*page == NULL) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_get_phyp_page: __get_free_pages failed\n");
+ return -ENOMEM;
+ }
+
+ /* translate virtual to logical address */
+ *laddr = (caddr_t)__pa((caddr_t) *page);
+ memset(*page, 0, size);
+ return 0;
+}
+
+/* Release the page allocated for the HCALL */
+inline void hfidd_release_phyp_page(caddr_t page, int size)
+{
+ free_pages((unsigned long)page, get_order(size));
+}
+
+int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
+ unsigned int hfi_id, unsigned long long *state)
+{
+ long long hvrc;
+ int rc = 0;
+ struct hfi_query_interface *query_p;
+ caddr_t laddr = NULL;
+
+ if (subtype != COMP_QUERY && subtype != EEH_QUERY) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_query_interface: subtype not supported, %d\n",
+ subtype);
+ return -EINVAL;
+ }
+
+ if (subtype == COMP_QUERY) {
+ /* Allocate the page for the HCALL */
+ rc = hfidd_get_phyp_page(p_acs, (caddr_t *)&query_p, &laddr,
+ PAGE_SIZE_4K);
+ if (rc) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_query_interface: hfidd_get_phyp_page "
+ "failed\n");
+ return -ENOMEM;
+ }
+ }
+
+ hvrc = hfi_hquery_interface(hfi_id, subtype,
+ (unsigned long long)laddr, state);
+ if (hvrc != H_SUCCESS) {
+ rc = -EPERM;
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_query_interface: failed, state 0x%llx "
+ "hvrc 0x%llx\n", *state, hvrc);
+ goto query1;
+ }
+
+ if (subtype == COMP_QUERY) {
+ if (*state == ACTIVE) {
+ if (p_acs->state != HFI_AVAIL) {
+ p_acs->isr = query_p->local_node_id;
+ p_acs->state = HFI_AVAIL;
+ }
+ } else {
+ p_acs->state = HFI_UNAVAIL;
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_query_interface: Bad state %lld, "
+ "return ENODEV\n", *state);
+ rc = -EIO;
+ }
+ }
+
+query1:
+ if (subtype == COMP_QUERY)
+ hfidd_release_phyp_page((caddr_t)query_p, PAGE_SIZE_4K);
+ dev_printk(KERN_INFO, p_acs->hfidd_dev,
+ "hfidd_query_interface: return rc %d\n", rc);
+ return rc;
+}
+
+int hfidd_start_interface(struct hfidd_acs *p_acs)
+{
+ long long hvrc = 0;
+ int rc = 0;
+ u64 start_time = get_jiffies_64();
+
+ while (1) {
+ hvrc = hfi_start_interface(p_acs->dds.hfi_id);
+ if (hvrc != H_BUSY)
+ break;
+ if (hfidd_age_hcall(start_time))
+ break;
+ }
+ if (hvrc != H_SUCCESS) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_start_interface: HFI_START_INTERFACE failed "
+ "hvrc 0x%llx\n", hvrc);
+ rc = -EPERM;
+ }
+ return rc;
+}
+
+int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id)
+{
+ long long hvrc = 0;
+ int rc = 0;
+ u64 start_time = get_jiffies_64();
+
+ while (1) {
+ hvrc = hfi_stop_interface(hfi_id);
+ if (hvrc != H_BUSY)
+ break;
+ if (hfidd_age_hcall(start_time))
+ break;
+ }
+ if (hvrc != H_SUCCESS) {
+ dev_printk(KERN_ERR, p_acs->hfidd_dev,
+ "hfidd_stop_interface: HFI_STOP_INTERFACE failed "
+ "hvrc 0x%llx\n", hvrc);
+ rc = -EPERM;
+ }
+ return rc;
+}
diff --git a/drivers/net/hfi/core/hfidd_hcalls.c b/drivers/net/hfi/core/hfidd_hcalls.c
new file mode 100644
index 0000000..84467b3
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_hcalls.c
@@ -0,0 +1,90 @@
+/*
+ * hfidd_hcalls.c
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
+
+static inline long long h_hfi_start_interface(int token,
+ u64 HFI_chip_ID)
+{
+ return plpar_hcall_norets(token, HFI_chip_ID);
+}
+
+static inline long long h_hfi_stop_interface(int token,
+ u64 HFI_chip_ID)
+{
+ return plpar_hcall_norets(token, HFI_chip_ID);
+}
+
+static inline long long h_hfi_query_interface(int token,
+ u64 HFI_chip_ID,
+ u64 type,
+ u64 output_page_ptr,
+ u64 *state)
+{
+ long long rc;
+ u64 hyp_outputs[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(token, (unsigned long *)hyp_outputs, HFI_chip_ID, type,
+ output_page_ptr);
+ *state = hyp_outputs[0]; /* 1st ret value */
+
+ return rc;
+}
+
+long long hfi_hquery_interface(u64 unit_id, u64 subtype,
+ u64 query_p, u64 *state)
+{
+ long long hvrc;
+
+ hvrc = h_hfi_query_interface(H_HFI_QUERY_INTERFACE,
+ unit_id,
+ subtype,
+ query_p,
+ state);
+ return hvrc;
+}
+
+long long hfi_start_interface(u64 unit_id)
+{
+ return h_hfi_start_interface(H_HFI_START_INTERFACE,
+ unit_id);
+}
+
+long long hfi_stop_interface(u64 unit_id)
+{
+ long long hvrc;
+
+ hvrc = h_hfi_stop_interface(H_HFI_STOP_INTERFACE,
+ unit_id);
+ return hvrc;
+}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
index e2ed4c9..6ec9245 100644
--- a/drivers/net/hfi/core/hfidd_proto.h
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -36,5 +36,17 @@
int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
void hfidd_free_adapter(struct hfidd_acs *p_acs);
int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop);
+int hfidd_age_hcall(u64 time_start);
+int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page,
+ caddr_t *laddr, int size);
+void hfidd_release_phyp_page(caddr_t page, int size);
+int hfidd_query_interface(struct hfidd_acs *p_acs, unsigned int subtype,
+ unsigned int hfi_id, unsigned long long *state);
+int hfidd_start_interface(struct hfidd_acs *p_acs);
+int hfidd_stop_interface(struct hfidd_acs *p_acs, unsigned int hfi_id);
+long long hfi_hquery_interface(u64 unit_id, u64 subtype, u64 query_p,
+ u64 *state);
+long long hfi_start_interface(u64 unit_id);
+long long hfi_stop_interface(u64 unit_id);
#endif
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
index 28f1693..2714a27 100644
--- a/include/linux/hfi/hfidd_client.h
+++ b/include/linux/hfi/hfidd_client.h
@@ -40,4 +40,12 @@
#define HFI_DYN_WINS_DEFAULT 32
+#define PAGE_SIZE_4K 0x1000
+#define PAGE_SIZE_64K 0x10000
+#define PAGE_SIZE_1M 0x100000
+#define PAGE_SIZE_16M 0x1000000
+#define PAGE_SIZE_256M 0x10000000
+#define PAGE_SIZE_4G 0x100000000
+#define PAGE_SIZE_16G 0x400000000
+
#endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_hcalls.h b/include/linux/hfi/hfidd_hcalls.h
new file mode 100644
index 0000000..5349e9e
--- /dev/null
+++ b/include/linux/hfi/hfidd_hcalls.h
@@ -0,0 +1,58 @@
+/*
+ * hfidd_hcalls.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFIDD_HCALLS_H_
+#define _HFIDD_HCALLS_H_
+
+#include <asm/hvcall.h>
+
+/* Token IDs */
+#define H_HFI_START_INTERFACE 0xF000
+#define H_HFI_QUERY_INTERFACE 0xF004
+#define H_HFI_STOP_INTERFACE 0xF008
+
+#define EEH_QUERY 1
+#define COMP_QUERY 2
+
+/* States of Query interface */
+#define NOT_READY 0
+#define NOT_STARTED 1
+#define ACTIVE 2
+#define CLOSING 3
+#define ERROR 101
+
+struct hfi_query_interface {
+ unsigned long long hypervisor_capabilities;
+ unsigned int local_node_id;
+};
+
+#endif /* _HFIDD_HCALLS_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index fafca96..8fe313d 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -39,10 +39,12 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/device.h>
#include <linux/hfi/hfidd_client.h>
#include <linux/hfi/hfidd_adpt.h>
-
+#include <linux/hfi/hfidd_hcalls.h>
#define HFIDD_DEV_NAME "hfi"
#define HFIDD_CLASS_NAME "hfi"
@@ -65,6 +67,9 @@ struct hfidd_acs {
unsigned int index;
unsigned int acs_cnt;
unsigned int state;
+
+ unsigned int isr;
+
struct device *hfidd_dev;
struct hfidd_dds dds;
};
--
1.7.3.1
^ permalink raw reply related
* [PATCH 03/27] HFI: Add device_create/device_destroy calls for HFI devices.
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/hfidd_init.c | 52 ++++++++++++++++++++++++++++++++++++
include/linux/hfi/hfidd_internal.h | 1 +
2 files changed, 53 insertions(+), 0 deletions(-)
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index 114b772..68d6e65 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -47,6 +47,7 @@ MODULE_LICENSE("GPL v2");
struct hfidd_global hfidd_global;
EXPORT_SYMBOL_GPL(hfidd_global);
+struct device *hfidd_class_dev[MAX_HFIS + 1];
static dev_t hfidd_dev;
#define MAX_HFI_DEVS (MAX_HFIS + 1)
@@ -71,6 +72,38 @@ static const struct file_operations hfidd_fops = {
.write = hfidd_cmd_write,
};
+/* Create the hfi device */
+static int hfidd_mkdev(int ai, struct hfidd_acs *p_acs)
+{
+ char dname[128];
+ int rc = 0;
+
+ sprintf(dname, "%s%d", HFIDD_DEV_NAME, ai);
+
+ hfidd_class_dev[ai] = device_create(hfidd_global.class,
+ NULL, MKDEV(MAJOR(hfidd_dev), ai),
+ (void *)p_acs, (char *)dname);
+
+ if (IS_ERR(hfidd_class_dev[ai])) {
+ rc = PTR_ERR(hfidd_class_dev[ai]);
+ printk(KERN_ERR "%s: hfidd_mkdev: device_create for ai=%d fail"
+ " rc = %d\n", dname, ai, rc);
+ return rc;
+ }
+
+ if (ai == MAX_HFIS)
+ return 0;
+
+ p_acs->hfidd_dev = hfidd_class_dev[ai];
+ return rc;
+}
+
+/* delete the hfi device, /dev/hfi* files and sysclass files */
+static void hfidd_rmdev(int ai)
+{
+ device_destroy(hfidd_global.class, MKDEV(MAJOR(hfidd_dev), ai));
+}
+
/* Destroy the HFI class */
static inline void hfidd_destroy_class(void)
{
@@ -124,6 +157,8 @@ static void hfidd_destroy_devices(void)
{
int i;
+ for (i = 0; i <= MAX_HFIS; i++)
+ hfidd_rmdev(i);
for (i = 0; i < MAX_HFIS; i++) {
hfidd_free_adapter(hfidd_global.p_acs[i]);
hfidd_global.p_acs[i] = NULL;
@@ -156,6 +191,23 @@ static int hfidd_create_devices(void)
}
hfidd_global.acs_cnt++;
}
+
+ for (i = 0; i <= MAX_HFIS; i++) {
+ rc = hfidd_mkdev(i, hfidd_global.p_acs[i]);
+ if (rc) {
+ for (j = 0; j < i; j++)
+ hfidd_rmdev(j);
+ goto hfidd_create_devices_error0;
+ }
+ }
+ return 0;
+
+hfidd_create_devices_error0:
+ for (i = 0; i < MAX_HFIS; i++) {
+ hfidd_free_adapter(hfidd_global.p_acs[i]);
+ hfidd_global.p_acs[i] = NULL;
+ hfidd_global.acs_cnt--;
+ }
return rc;
}
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index 2c58b56..695d7f4 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -54,6 +54,7 @@ struct hfidd_acs {
unsigned int index;
unsigned int acs_cnt;
unsigned int state;
+ struct device *hfidd_dev;
};
/* DD global */
--
1.7.3.1
^ permalink raw reply related
* [PATCH 02/27] HFI: Add HFI adapter control structure
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com>
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Alloc/free of hfidd_acs to track the state of each HFI
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/hfi/core/Makefile | 3 +-
drivers/net/hfi/core/hfidd_adpt.c | 60 ++++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_init.c | 57 ++++++++++++++++++++++++++++++++++
drivers/net/hfi/core/hfidd_proto.h | 39 +++++++++++++++++++++++
include/linux/hfi/hfidd_adpt.h | 45 +++++++++++++++++++++++++++
include/linux/hfi/hfidd_internal.h | 14 ++++++++
6 files changed, 217 insertions(+), 1 deletions(-)
create mode 100644 drivers/net/hfi/core/hfidd_adpt.c
create mode 100644 drivers/net/hfi/core/hfidd_proto.h
create mode 100644 include/linux/hfi/hfidd_adpt.h
diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
index 80790c6..6fe4e60 100644
--- a/drivers/net/hfi/core/Makefile
+++ b/drivers/net/hfi/core/Makefile
@@ -1,5 +1,6 @@
#
# Makefile for the HFI device driver for IBM eServer System p
#
-hfi_core-objs:= hfidd_init.o
+hfi_core-objs:= hfidd_adpt.o \
+ hfidd_init.o
obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_adpt.c b/drivers/net/hfi/core/hfidd_adpt.c
new file mode 100644
index 0000000..d64fa38
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_adpt.c
@@ -0,0 +1,60 @@
+/*
+ * hfidd_adpt.c
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
+
+int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t devno, void *uiop)
+{
+
+ struct hfidd_acs *p_acs = NULL;
+
+ p_acs = kzalloc(sizeof(*p_acs), GFP_KERNEL);
+ if (p_acs == NULL)
+ return -ENOMEM;
+
+ p_acs->dev_num = devno;
+ p_acs->index = MINOR(devno);
+ p_acs->state = HFI_INVALID;
+ snprintf(p_acs->name, HFI_DEVICE_NAME_MAX - 1,
+ "%s%d", HFIDD_DEV_NAME, p_acs->index);
+
+ *adpt = p_acs;
+ return 0;
+}
+
+void hfidd_free_adapter(struct hfidd_acs *p_acs)
+{
+ kfree(p_acs);
+ p_acs = NULL;
+ return;
+}
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
index e03620e..114b772 100644
--- a/drivers/net/hfi/core/hfidd_init.c
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -36,6 +36,7 @@
#include <linux/device.h>
#include <linux/hfi/hfidd_internal.h>
+#include "hfidd_proto.h"
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("Device Driver for IBM eServer HFI for IBM System p");
@@ -118,10 +119,52 @@ hfidd_create_class_error1:
return rc;
}
+/* Free adapter resources and the devicese */
+static void hfidd_destroy_devices(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_HFIS; i++) {
+ hfidd_free_adapter(hfidd_global.p_acs[i]);
+ hfidd_global.p_acs[i] = NULL;
+ hfidd_global.acs_cnt--;
+ }
+}
+
+/*
+ * Create the adapter structure, allocate resources and create
+ * the hfi devices
+ */
+static int hfidd_create_devices(void)
+{
+ int i, j;
+ int rc = 0;
+
+ for (i = 0; i < MAX_HFIS; i++) {
+ rc = hfidd_alloc_adapter(&(hfidd_global.p_acs[i]),
+ MKDEV(MAJOR(hfidd_dev), i), NULL);
+ if (rc) {
+ printk(KERN_ERR "%s: hfidd_create_devices: "
+ "hfidd_alloc_adapter fail rc = %d\n",
+ HFIDD_DEV_NAME, rc);
+ for (j = 0; j < i; j++) {
+ hfidd_free_adapter(hfidd_global.p_acs[j]);
+ hfidd_global.p_acs[j] = NULL;
+ hfidd_global.acs_cnt--;
+ }
+ return rc;
+ }
+ hfidd_global.acs_cnt++;
+ }
+ return rc;
+}
+
static int __init hfidd_mod_init(void)
{
int rc = 0;
+ hfidd_global.acs_cnt = 0;
+
rc = hfidd_create_class();
if (rc < 0) {
printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_class failed"
@@ -129,12 +172,26 @@ static int __init hfidd_mod_init(void)
return -1;
}
+ rc = hfidd_create_devices();
+ if (rc < 0) {
+ printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_devices"
+ " failed rc = %d\n", HFIDD_DEV_NAME, rc);
+ goto error1;
+ }
+
printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
return 0;
+
+error1:
+ hfidd_destroy_class();
+
+ /* Returning -1 so insmod will fail */
+ return -1;
}
static void __exit hfidd_mod_exit(void)
{
+ hfidd_destroy_devices();
hfidd_destroy_class();
}
diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h
new file mode 100644
index 0000000..01a5ba2
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_proto.h
@@ -0,0 +1,39 @@
+/*
+ * hfidd_proto.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com)
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFIDD_PROTO_H_
+#define _HFIDD_PROTO_H_
+
+int hfidd_alloc_adapter(struct hfidd_acs **adpt, dev_t, void *uiop);
+void hfidd_free_adapter(struct hfidd_acs *p_acs);
+
+#endif
diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h
new file mode 100644
index 0000000..6b1432d
--- /dev/null
+++ b/include/linux/hfi/hfidd_adpt.h
@@ -0,0 +1,45 @@
+/*
+ * hfidd_adpt.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFIDD_ADPT_H_
+#define _HFIDD_ADPT_H_
+
+#include <linux/hfi/hfidd_client.h>
+
+
+/* Adpt state */
+#define HFI_INVALID 0
+#define HFI_AVAIL 1
+#define HFI_GOING_UNAVAIL 2
+#define HFI_UNAVAIL 3
+
+#endif /* _HFIDD_ADPT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
index f5de1bb..2c58b56 100644
--- a/include/linux/hfi/hfidd_internal.h
+++ b/include/linux/hfi/hfidd_internal.h
@@ -38,16 +38,30 @@
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/hfi/hfidd_client.h>
+#include <linux/hfi/hfidd_adpt.h>
#define HFIDD_DEV_NAME "hfi"
#define HFIDD_CLASS_NAME "hfi"
+#define HFI_DEVICE_NAME_MAX 64
+/* hfi global */
+struct hfidd_acs {
+ dev_t dev_num;
+ char name[HFI_DEVICE_NAME_MAX];
+ unsigned int index;
+ unsigned int acs_cnt;
+ unsigned int state;
+};
+
/* DD global */
struct hfidd_global {
struct cdev cdev;
struct class *class;
+ int acs_cnt;
+ struct hfidd_acs *p_acs[MAX_HFIS];
};
#endif
--
1.7.3.1
^ permalink raw reply related
* [PATCH 01/27] HFI: skeleton driver
From: dykmanj @ 2011-03-02 21:09 UTC (permalink / raw)
To: netdev, netdev
Cc: Jim Dykman, Piyush Chaudhary, Fu-Chung Chang, William S. Cadden,
Wen C. Chen, Scot Sakolish, Jian Xiao, Carol L. Soto,
Sarah J. Sheppard
From: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Device driver Makefile & Kconfig plumbing plus simple mod_init and mod_exit
Signed-off-by: Piyush Chaudhary <piyushc@linux.vnet.ibm.com>
Signed-off-by: Jim Dykman <dykmanj@linux.vnet.ibm.com>
Signed-off-by: Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
Signed-off-by: William S. Cadden <wscadden@linux.vnet.ibm.com>
Signed-off-by: Wen C. Chen <winstonc@linux.vnet.ibm.com>
Signed-off-by: Scot Sakolish <sakolish@linux.vnet.ibm.com>
Signed-off-by: Jian Xiao <jian@linux.vnet.ibm.com>
Signed-off-by: Carol L. Soto <clsoto@linux.vnet.ibm.com>
Signed-off-by: Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
---
drivers/net/Kconfig | 2 +
drivers/net/Makefile | 2 +
drivers/net/hfi/Makefile | 1 +
drivers/net/hfi/core/Kconfig | 8 ++
drivers/net/hfi/core/Makefile | 5 +
drivers/net/hfi/core/hfidd_init.c | 142 ++++++++++++++++++++++++++++++++++++
include/linux/Kbuild | 1 +
include/linux/hfi/Kbuild | 1 +
include/linux/hfi/hfidd_client.h | 40 ++++++++++
include/linux/hfi/hfidd_internal.h | 53 +++++++++++++
10 files changed, 255 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/hfi/Makefile
create mode 100644 drivers/net/hfi/core/Kconfig
create mode 100644 drivers/net/hfi/core/Makefile
create mode 100644 drivers/net/hfi/core/hfidd_init.c
create mode 100644 include/linux/hfi/Kbuild
create mode 100644 include/linux/hfi/hfidd_client.h
create mode 100644 include/linux/hfi/hfidd_internal.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0382332..d4ca094 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3422,4 +3422,6 @@ config VMXNET3
To compile this driver as a module, choose M here: the
module will be called vmxnet3.
+source "drivers/net/hfi/core/Kconfig"
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..f7522bc 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -302,3 +302,5 @@ obj-$(CONFIG_CAIF) += caif/
obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
obj-$(CONFIG_PCH_GBE) += pch_gbe/
obj-$(CONFIG_TILE_NET) += tile/
+
+obj-$(CONFIG_HFI) += hfi/
diff --git a/drivers/net/hfi/Makefile b/drivers/net/hfi/Makefile
new file mode 100644
index 0000000..0440cbe
--- /dev/null
+++ b/drivers/net/hfi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HFI) += core/
diff --git a/drivers/net/hfi/core/Kconfig b/drivers/net/hfi/core/Kconfig
new file mode 100644
index 0000000..3cd637c
--- /dev/null
+++ b/drivers/net/hfi/core/Kconfig
@@ -0,0 +1,8 @@
+config HFI
+ tristate "HFI driver support"
+ depends on IBMEBUS
+ ---help---
+ This driver supports the IBM System p HFI adapter.
+
+ To compile the driver as a module, choose M here. The module
+ will be called hfi_core.
diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile
new file mode 100644
index 0000000..80790c6
--- /dev/null
+++ b/drivers/net/hfi/core/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the HFI device driver for IBM eServer System p
+#
+hfi_core-objs:= hfidd_init.o
+obj-$(CONFIG_HFI) += hfi_core.o
diff --git a/drivers/net/hfi/core/hfidd_init.c b/drivers/net/hfi/core/hfidd_init.c
new file mode 100644
index 0000000..e03620e
--- /dev/null
+++ b/drivers/net/hfi/core/hfidd_init.c
@@ -0,0 +1,142 @@
+/*
+ * hfidd_init.c
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <linux/hfi/hfidd_internal.h>
+
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Device Driver for IBM eServer HFI for IBM System p");
+MODULE_AUTHOR("James Dykman <dykmanj@linux.vnet.ibm.com> and "
+ "Piyush Chaudhary <piyushc@linux.vnet.ibm.com>");
+MODULE_LICENSE("GPL v2");
+
+struct hfidd_global hfidd_global;
+EXPORT_SYMBOL_GPL(hfidd_global);
+
+static dev_t hfidd_dev;
+
+#define MAX_HFI_DEVS (MAX_HFIS + 1)
+
+/* Function to get our internal traces */
+static ssize_t hfidd_read(struct file *filep, char *buf, size_t count,
+ loff_t *pos)
+{
+ return 0;
+}
+
+/* Entry point for user space to do driver requests. */
+static ssize_t hfidd_cmd_write(struct file *filep, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return 0;
+}
+
+static const struct file_operations hfidd_fops = {
+ .owner = THIS_MODULE,
+ .read = hfidd_read,
+ .write = hfidd_cmd_write,
+};
+
+/* Destroy the HFI class */
+static inline void hfidd_destroy_class(void)
+{
+ class_destroy(hfidd_global.class);
+ cdev_del(&hfidd_global.cdev);
+ unregister_chrdev_region(hfidd_dev, MAX_HFI_DEVS);
+}
+
+/* Create the HFI class */
+static int hfidd_create_class(void)
+{
+ int rc;
+
+ rc = alloc_chrdev_region(&hfidd_dev, 0, MAX_HFI_DEVS, HFIDD_DEV_NAME);
+ if (rc) {
+ printk(KERN_ERR "%s: hfidd_create_class: alloc_chrdev_region"
+ " failed rc 0x%x\n", HFIDD_DEV_NAME, rc);
+ return rc;
+ }
+
+ cdev_init(&hfidd_global.cdev, &hfidd_fops);
+ hfidd_global.cdev.owner = THIS_MODULE;
+ kobject_set_name(&hfidd_global.cdev.kobj, HFIDD_DEV_NAME);
+ rc = cdev_add(&hfidd_global.cdev, hfidd_dev, MAX_HFI_DEVS);
+ if (rc) {
+ printk(KERN_ERR "%s: hfidd_create_class cdev_add fail"
+ " rc = %d\n", HFIDD_DEV_NAME, rc);
+ goto hfidd_create_class_error1;
+ }
+
+ hfidd_global.class = class_create(THIS_MODULE, HFIDD_CLASS_NAME);
+ if (IS_ERR(hfidd_global.class)) {
+ rc = PTR_ERR(hfidd_global.class);
+ printk(KERN_ERR "%s: hfidd_create_class class_create fail rc = %d\n",
+ HFIDD_DEV_NAME, rc);
+ goto hfidd_create_class_error2;
+ }
+
+ return rc;
+
+hfidd_create_class_error2:
+ cdev_del(&hfidd_global.cdev);
+hfidd_create_class_error1:
+ unregister_chrdev_region(hfidd_dev, MAX_HFI_DEVS);
+
+ return rc;
+}
+
+static int __init hfidd_mod_init(void)
+{
+ int rc = 0;
+
+ rc = hfidd_create_class();
+ if (rc < 0) {
+ printk(KERN_ERR "%s: hfidd_mod_init: hfidd_create_class failed"
+ " rc=%d\n", HFIDD_DEV_NAME, rc);
+ return -1;
+ }
+
+ printk(KERN_INFO "IBM hfi device driver loaded sucessfully\n");
+ return 0;
+}
+
+static void __exit hfidd_mod_exit(void)
+{
+ hfidd_destroy_class();
+}
+
+module_init(hfidd_mod_init);
+module_exit(hfidd_mod_exit);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index b0ada6f..dde085b 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -3,6 +3,7 @@ header-y += can/
header-y += caif/
header-y += dvb/
header-y += hdlc/
+header-y += hfi/
header-y += isdn/
header-y += nfsd/
header-y += raid/
diff --git a/include/linux/hfi/Kbuild b/include/linux/hfi/Kbuild
new file mode 100644
index 0000000..3a742ce
--- /dev/null
+++ b/include/linux/hfi/Kbuild
@@ -0,0 +1 @@
+header-y += hfidd_client.h
diff --git a/include/linux/hfi/hfidd_client.h b/include/linux/hfi/hfidd_client.h
new file mode 100644
index 0000000..b738f4b
--- /dev/null
+++ b/include/linux/hfi/hfidd_client.h
@@ -0,0 +1,40 @@
+/*
+ * hfidd_client.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFIDD_CLIENT_H_
+#define _HFIDD_CLIENT_H_
+
+#define MAX_TORRENTS 1
+#define MAX_HFI_PER_TORRENT 2
+#define MAX_HFIS (MAX_TORRENTS * MAX_HFI_PER_TORRENT)
+
+#endif /* _HFIDD_CLIENT_H_ */
diff --git a/include/linux/hfi/hfidd_internal.h b/include/linux/hfi/hfidd_internal.h
new file mode 100644
index 0000000..f5de1bb
--- /dev/null
+++ b/include/linux/hfi/hfidd_internal.h
@@ -0,0 +1,53 @@
+/*
+ * hfidd_internal.h
+ *
+ * HFI device driver for IBM System p
+ *
+ * Authors:
+ * Fu-Chung Chang <fcchang@linux.vnet.ibm.com>
+ * William S. Cadden <wscadden@linux.vnet.ibm.com>
+ * Wen C. Chen <winstonc@linux.vnet.ibm.com>
+ * Scot Sakolish <sakolish@linux.vnet.ibm.com>
+ * Jian Xiao <jian@linux.vnet.ibm.com>
+ * Carol L. Soto <clsoto@linux.vnet.ibm.com>
+ * Sarah J. Sheppard <sjsheppa@linux.vnet.ibm.com>
+ *
+ * (C) Copyright IBM Corp. 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _HFI_INTERNAL_H_
+#define _HFI_INTERNAL_H_
+
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <linux/hfi/hfidd_client.h>
+
+#define HFIDD_DEV_NAME "hfi"
+#define HFIDD_CLASS_NAME "hfi"
+
+/* DD global */
+struct hfidd_global {
+ struct cdev cdev;
+ struct class *class;
+};
+
+#endif
--
1.7.3.1
^ permalink raw reply related
* Re: [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Nicolas de Pesloüan @ 2011-03-02 21:05 UTC (permalink / raw)
To: Changli Gao
Cc: Jiri Pirko, netdev, davem, fubar, eric.dumazet, andy, Herbert Xu
In-Reply-To: <AANLkTikvJ3n0mSabakpBOiLJZd55ZJUGz7wM2wm0th5C@mail.gmail.com>
Le 02/03/2011 17:13, Changli Gao a écrit :
> On Wed, Mar 2, 2011 at 4:11 AM, Nicolas de Pesloüan
> <nicolas.2p.debian@gmail.com> wrote:
>> Le 01/03/2011 16:12, Changli Gao a écrit :
>>> I don't think so. Although you avoid netif_rx(), you can't avoid
>>> ptype_all handlers. In fact, all the RX handlers should has this
>>> check(), if they may modify the skb.
>>
>> Can you please develop your explanation?
>>
>> In current __netif_receive_skb() (after the recent patch from Jiri), we
>> deliver the skb to ptype_all handlers inside a loop, while possibly changing
>> skb->dev inside this loop.
>>
>> Then, at the end of __netif_receive_skb(), we loop on ptype_base, without
>> changing anything in skb.
>>
>> Should we consider ptype_*->func() to be called in a pure sequential way?
>> Should we consider that when a ptype_*->func() returns, nothing from this
>> handler will use the skb in anyway later, in a parallel way?
>>
>> Or should we, instead, consider that special precautions must be taken,
>> because protocol handlers may run in parallel for the same skb? Which kind
>> of precautions?
>>
>
> If the packets gotten by __netif_receive_skb() are unshared, the skb
> gotten by bond should be unshared, as we call prev_pt before calling
> bond. I don't see there is any relationship with the previous patch
> from Jiri. The bridge is in the same condition with bond here, and it
> checks if the skb is shared or not. Does it imply that dev->rx_handler
> may see shared skbs?
Thanks for you explanations.
My question is not strictly linked to bonding, but more general to __netif_receive_skb().
Jiri's patch added a "goto another_round" if the rx_handler changed skb->dev. (The idea was from
me). The ptype_all list_foreach_entry_rcu delivery loop is between "another_round:" and "goto
another_round", so some ptype_all handlers will receive an skb where skb->dev will have changed.
I wonder whether this might cause any troubles and if yes, what should be done to fix it.
And depending on the answer, I wonder whether we can move the ptype_base loop to the same place as
the ptype_all loop. This would allow for a better handling of orig_dev, I think.
Nicolas.
^ permalink raw reply
* Re: [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Nicolas de Pesloüan @ 2011-03-02 20:47 UTC (permalink / raw)
To: Jiri Pirko; +Cc: Andy Gospodarek, netdev, davem, fubar, eric.dumazet
In-Reply-To: <20110302100354.GB2858@psychotron.brq.redhat.com>
Le 02/03/2011 11:03, Jiri Pirko a écrit :
> Tue, Mar 01, 2011 at 09:38:43PM CET, andy@greyhouse.net wrote:
>> On Tue, Mar 01, 2011 at 10:29:07AM +0100, Jiri Pirko wrote:
>>> Unapplicable, sorry (wrong branch :(). Here's corrected patch:
>>>
>>> Subject: [PATCH net-next-2.6 v2] bonding: remove skb_share_check in handle_frame
>>>
>>> No need to do share check here.
>>>
>>> Signed-off-by: Jiri Pirko<jpirko@redhat.com>
>>> ---
>>> drivers/net/bonding/bond_main.c | 3 ---
>>> 1 files changed, 0 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>>> index 584f97b..367ea60 100644
>>> --- a/drivers/net/bonding/bond_main.c
>>> +++ b/drivers/net/bonding/bond_main.c
>>> @@ -1498,9 +1498,6 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
>>> struct net_device *slave_dev;
>>> struct net_device *bond_dev;
>>>
>>> - skb = skb_share_check(skb, GFP_ATOMIC);
>>> - if (unlikely(!skb))
>>> - return NULL;
>>> slave_dev = skb->dev;
>>> bond_dev = ACCESS_ONCE(slave_dev->master);
>>> if (unlikely(!bond_dev))
>>> --
>>> 1.7.3.4
>>>
>>
>> Why did you decide to get rid of it here rather than the 3 places in the
>> bonding driver where it is currently needed? I think this can cover
>> those cases since bond_handle_frame will be called after the ptype_all
>> handlers before any of the ptype handlers.
>
> I have already a patch prepared which converts bond ptype handlers into
> being called from bond_handle_frame. You are propably right that this
> should probably stay here.
Hi Jiri,
Do you plan to call the bonding ARP handler from inside bond_handle_frame()?
A few days ago (http://marc.info/?l=linux-netdev&m=129883949022340&w=2), I noticed that it is not
possible to call the bonding ARP handler from inside the bonding rx_handler, because some frame
processing may be required after the bonding rx_handler call, to put the frame in a suitable state
for the bonding ARP handler.
This is at least true with the following setup, eth0 -> bond0 -> bond0.100, where the ARP frames are
VLAN tagged at the time the bonding rx_handler process them.
Nicolas.
^ permalink raw reply
* [net-2.6 PATCH] net: dcbnl: check correct ops in dcbnl_ieee_set()
From: John Fastabend @ 2011-03-02 20:35 UTC (permalink / raw)
To: netdev; +Cc: john.r.fastabend, davem, shmulikr
The incorrect ops routine was being tested for in
DCB_ATTR_IEEE_PFC attributes. This patch corrects
it.
Currently, every driver implementing ieee_setets also
implements ieee_setpfc so this bug is not actualized
yet.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
net/dcb/dcbnl.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index d5074a5..c44348a 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -1193,7 +1193,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
goto err;
}
- if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
+ if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
err = ops->ieee_setpfc(netdev, pfc);
if (err)
^ permalink raw reply related
* Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Jake Edge @ 2011-03-02 20:40 UTC (permalink / raw)
To: Vasiliy Kulikov
Cc: linux-kernel, mjt, arnd, mirqus, netdev, Ben Hutchings,
David Miller, kuznet, pekkas, jmorris, yoshfuji, kaber,
eric.dumazet, therbert, xiaosuo, jesse, kees.cook, eugene,
dan.j.rosenberg, akpm
In-Reply-To: <20110302201807.GA31965@albatros>
On Wed, 2 Mar 2011 23:18:07 +0300 Vasiliy Kulikov wrote:
> As root has CAP_NET_ADMIN, the alias netdev-gre0 is tried and it
> succeeds.
Never mind, my apologies for the noise ... one always reads replies
most carefully just *after* hitting send ...
jake
--
Jake Edge - LWN - jake@lwn.net - http://lwn.net
^ permalink raw reply
* Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Jake Edge @ 2011-03-02 20:38 UTC (permalink / raw)
To: Vasiliy Kulikov
Cc: linux-kernel, mjt, arnd, mirqus, netdev, Ben Hutchings,
David Miller, kuznet, pekkas, jmorris, yoshfuji, kaber,
eric.dumazet, therbert, xiaosuo, jesse, kees.cook, eugene,
dan.j.rosenberg, akpm
In-Reply-To: <20110302201807.GA31965@albatros>
On Wed, 2 Mar 2011 23:18:07 +0300 Vasiliy Kulikov wrote:
> > and on systems that today use CAP_SYS_MODULE
>
> Since Linux 2.6.32 CAP_SYS_MODULE may not load modules via "ifconfig
> gre0". It was changed to CAP_NET_ADMIN. So nothing is broken here.
>
> > (or really the full set of
> > capabilities cuz they are running as root)?
>
> As root has CAP_NET_ADMIN, the alias netdev-gre0 is tried and it
> succeeds.
(I feel like I'm beating a dead horse here, sorry if so ...)
If I have a setuid-root program today that loads ip_gre by using the
alias "gre0", and I run that program on a kernel with this change,
won't it fail because the "gre0" alias is missing? That program
doesn't know to try "netdev-gre0". i.e. won't backward compatibility be
affected by this change?
jake
--
Jake Edge - LWN - jake@lwn.net - http://lwn.net
^ permalink raw reply
* Re: [PATCH 0/7] Final BKL removal, take 2
From: Mauro Carvalho Chehab @ 2011-03-02 20:32 UTC (permalink / raw)
To: Greg KH
Cc: Arnd Bergmann, linux-kernel, Andi Kleen, Andrew Hendry,
Arnaldo Carvalho de Melo, David Miller, Eric Dumazet,
Evgeniy Dushistov, linux-fsdevel, linux-x25, Max Vozeler,
Mikulas Patocka, netdev, Nick Bowler, Nick Piggin,
Palash Bandyopadhyay, Takahiro Hirofuchi
In-Reply-To: <20110302140428.GA630@suse.de>
Em 02-03-2011 11:04, Greg KH escreveu:
> On Wed, Mar 02, 2011 at 08:32:15AM -0300, Mauro Carvalho Chehab wrote:
>> Em 02-03-2011 01:59, Greg KH escreveu:
>>> On Wed, Mar 02, 2011 at 12:13:04AM +0100, Arnd Bergmann wrote:
>>>> This is the set of patches that remain from
>>>> my previous submission one month ago. I've
>>>> dropped the ones that have either gone into
>>>> linux-next or got a sufficient number of
>>>> Acked-by:s so I put them into my own tree.
>>>>
>>>> I've updated the usbip, hpfs, ufs and appletalk
>>>> patches according to the feedback I got.
>>>>
>>>> If possible, I'd like the three networking patches
>>>> to go through the net-next tree, and the two
>>>> staging patches through the staging tree. I'll
>>>> add the other ones to my own series if I hear
>>>> no objections.
>>>
>>> I'll queue up the staging patches in the staging-next tree in a day or
>>> so, thanks for digging them up.
>>
>> Greg,
>>
>> It is probably better to queue the staging/cx25821 patch via my tree, as this is one
>> of those staging files that it is handled via media tree. So, if it is ok
>> for you both, I'll get patch 2/7.
>
> Yes, you are right, please take it through your tree.
Patch applied on my tree, thanks!
Mauro
^ permalink raw reply
* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Nicolas de Pesloüan @ 2011-03-02 20:30 UTC (permalink / raw)
To: Herbert Xu
Cc: Jay Vosburgh, Andy Gospodarek, netdev, David Miller, Jiri Pirko
In-Reply-To: <20110302123004.GA21002@gondor.apana.org.au>
Le 02/03/2011 13:30, Herbert Xu a écrit :
> On Wed, Mar 02, 2011 at 11:10:07AM +0100, Nicolas de Pesloüan wrote:
>>
>> If one decide to configure two interfaces with the same MAC and connect them
>> to the same LAN, then we get the exact same situation. Having eth0 and eth1
>> share a single MAC and a single IP address, connected to a switch in
>> Etherchannel mode is a perfectly valid setup, while suboptimal. And if the
>> Etherchannel mode happens to be improperly configured, we end up with the
>> same problem as reported by Andy.
>
> Right. There's also the case where you have other MAC addresses
> sitting behind the bonding device, e.g., virtualisation. So basing
> it purely on the bonding device's MAC address is probably not worth
> the trouble.
>
> Cheers,
I'm afraid we miss a general way to fix the general problem. We probably need to handle the problem
at every places that can suffer from the multicast loop, until we find a general fix, if ever.
Nicolas.
^ permalink raw reply
* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Nicolas de Pesloüan @ 2011-03-02 20:26 UTC (permalink / raw)
To: Jay Vosburgh
Cc: Andy Gospodarek, netdev, David Miller, Herbert Xu, Jiri Pirko
In-Reply-To: <4D6D7C66.6050205@gmail.com>
Le 02/03/2011 00:08, Nicolas de Pesloüan a écrit :
[snip]
> Can we imagine that, at the time we change the bonding mode to -rr or
> -xor, we simply brodcast or multicast one or two frames with some random
> data and wait to see whether we receive the frame back? If we receive at
> least one frame with the same random data, in one of the slaves
> interface for this bonding, we know for sure the switch configuration is
> not "multicast loop safe". Bonding already send ARP requests/replies in
> many situations. Adding one broadcast/multicast frame at bond setup time
> is probably acceptable.
>
> And to ensure consistent results, we need to send such
> broadcast/multicast every time the link goes up for an already enslaved
> slave. This is not perfect, as the switch topology may change in a way
> that won't be detected by bonding, but still cause a new multicast loop,
> but...
>
> Knowing the switch configuration is not "multicast loop safe", we can,
> at a minimum, issue a warning, telling the user she should expect
> strange behaviors, like false duplicate address detection.
>
> And we can probably use this information into the should-drop logic, for
> mode that lack "inactive" slaves.
>
Still thinking about it:
We should drop the frame if :
the bonding interface is in -rr or -xor mode,
and we know the switch topology in front of our slaves is not "multicast
loop safe" (see above).
and the source MAC is the MAC of the bonding interface
and the destination MAC is a multicast one.
That being said, I wonder if this is only bonding related.
If one decide to configure two interfaces with the same MAC and connect
them to the same LAN, then we get the exact same situation. Having eth0
and eth1 share a single MAC and a single IP address, connected to a
switch in Etherchannel mode is a perfectly valid setup, while
suboptimal. And if the Etherchannel mode happens to be improperly
configured, we end up with the same problem as reported by Andy.
Nicolas.
[ Resent, because netdev ML didn't get it the first time ]
^ permalink raw reply
* Re: txqueuelen has wrong units; should be time
From: Chris Friesen @ 2011-03-02 20:25 UTC (permalink / raw)
To: Mikael Abrahamsson
Cc: Eric Dumazet, Albert Cahalan, David Miller, johnwheffner,
linville, jussi.kivilinna, linux-kernel, netdev
In-Reply-To: <alpine.DEB.1.10.1103020358010.7942@uplift.swm.pp.se>
On 03/01/2011 09:10 PM, Mikael Abrahamsson wrote:
> For the case when we're ourselves originating the traffic (for instance to
> a wifi card with varying speed and jitter due to retransmits on the wifi
> layer), I think it's taking the too easy way out to use the same
> mechanisms (dropping packets or marking ECN for our own originated packets
> seems really weird), here we should be able to pushback information to the
> applications somehow and do prioritization between flows since we're
> sitting on all information ourselves including the application.
Doesn't the socket tx buffer give all the app pushback necessary?
(Assuming it's set to a sane value.)
We should certainly do prioritization between flows. Perhaps if no
other information is available the scheduler priority could be used?
Chris
--
Chris Friesen
Software Developer
GENBAND
chris.friesen@genband.com
www.genband.com
^ permalink raw reply
* Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Vasiliy Kulikov @ 2011-03-02 20:18 UTC (permalink / raw)
To: Jake Edge
Cc: linux-kernel, mjt, arnd, mirqus, netdev, Ben Hutchings,
David Miller, kuznet, pekkas, jmorris, yoshfuji, kaber,
eric.dumazet, therbert, xiaosuo, jesse, kees.cook, eugene,
dan.j.rosenberg, akpm
In-Reply-To: <20110302124936.289a1915@chukar>
On Wed, Mar 02, 2011 at 12:49 -0700, Jake Edge wrote:
> On Wed, 2 Mar 2011 22:43:54 +0300 Vasiliy Kulikov wrote:
> > On Wed, Mar 02, 2011 at 12:39 -0700, Jake Edge wrote:
> > > > @@ -1765,4 +1765,4 @@ module_exit(ipgre_fini);
> > > > MODULE_LICENSE("GPL");
> > > > MODULE_ALIAS_RTNL_LINK("gre");
> > > > MODULE_ALIAS_RTNL_LINK("gretap");
> > > > -MODULE_ALIAS("gre0");
> > > > +MODULE_ALIAS_NETDEV("gre0");
> > >
> > > that is, instead of replacing MODULE_ALIAS("gre0") with the NETDEV
> > > version, don't you want both for backward compatibility?
> >
> > The networking script will run with CAP_NET_ADMIN, this would request
> > netdev-gre0 and load ip_gre.
>
> and on systems that today use CAP_SYS_MODULE
Since Linux 2.6.32 CAP_SYS_MODULE may not load modules via "ifconfig
gre0". It was changed to CAP_NET_ADMIN. So nothing is broken here.
> (or really the full set of
> capabilities cuz they are running as root)?
As root has CAP_NET_ADMIN, the alias netdev-gre0 is tried and it succeeds.
--
Vasiliy Kulikov
http://www.openwall.com - bringing security into open computing environments
^ permalink raw reply
* Re: [PATCH] via-rhine: do not abort due to invalid MAC address
From: Alex G. @ 2011-03-02 20:06 UTC (permalink / raw)
To: Roger Luethi; +Cc: David Miller, florian, netdev
In-Reply-To: <20110302195205.GA15190@core.hellgate.ch>
[-- Attachment #1: Type: text/plain, Size: 1032 bytes --]
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
On 03/02/2011 09:52 PM, Roger Luethi wrote:
> Alex, can you redo the patch accordingly?
Done and tested.
[root@nukeserv2 mrnuke]# rmmod via-rhine
[root@nukeserv2 mrnuke]# insmod via-rhine.ko
[28234.938404] via-rhine.c:v1.10-LK1.4.3 2007-03-06 Written by Donald Becker
[28234.945186] via-rhine: Invalid MAC address: ef:9f:e9:f7:f7:f7.
[28234.945518] via-rhine: Using randomly generated address:
02:0f:c4:98:a6:fd instead.
[28234.948793] eth1: VIA Rhine II at 0xfaa00000, 02:0f:c4:98:a6:fd, IRQ 23.
[28234.950223] eth1: MII PHY found at address 1, status 0x7849
advertising 01e1 Link 0000.
[root@nukeserv2 mrnuke]# ifconfig eth1
eth1 Link encap:Ethernet HWaddr 02:0F:C4:98:A6:FD
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
Interrupt:23
[-- Attachment #2: rhine.patch --]
[-- Type: text/x-patch, Size: 987 bytes --]
diff --git a/linux-2.6.35.11/drivers/net/via-rhine.c b/via-rhine.c
index 4930f9d..4c1b9e7 100644
--- a/linux-2.6.35.11/drivers/net/via-rhine.c
+++ b/via-rhine.c
@@ -762,13 +762,16 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
for (i = 0; i < 6; i++)
dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->perm_addr)) {
- rc = -EIO;
- printk(KERN_ERR "Invalid MAC address\n");
- goto err_out_unmap;
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_ERR "via-rhine: Invalid MAC address: %pM. \n",
+ dev->dev_addr);
+ /* The device may still be used normally if a valid MAC is configured */
+ random_ether_addr(dev->dev_addr);
+ printk(KERN_ERR "via-rhine: Using randomly generated address: %pM instead. \n",
+ dev->dev_addr);
}
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* For Rhine-I/II, phy_id is loaded from EEPROM */
if (!phy_id)
^ permalink raw reply related
* RE: [net-next-2.6 PATCH 02/10] ethtool: add ntuple flow specifier to network flow classifier
From: Dimitrios Michailidis @ 2011-03-02 20:03 UTC (permalink / raw)
To: Ben Hutchings
Cc: Alexander Duyck, Alexander Duyck, davem, jeffrey.t.kirsher,
netdev
In-Reply-To: <1299094046.2664.31.camel@bwh-desktop>
Ben Hutchings wrote:
> On Wed, 2011-03-02 at 11:11 -0800, Dimitrios Michailidis wrote:
> > Ben Hutchings wrote:
> > > /**
> > > * struct ethtool_flow_ext - flow spec common extension fields
> > > * @vlan_etype: EtherType for vlan tagged packet to match
> > > * @vlan_tci: VLAN tag to match
> > > * @data: Driver-dependent data to match
> > > *
> > > * Note: Additional fields may be inserted before @vlan_etype in future,
> > > * but the offset of the existing fields within the containing structure
> > > * (&struct ethtool_rx_flow_spec) will be stable.
> > > */
> > > struct ethtool_flow_ext {
> > > __be16 vlan_etype;
> > > __be16 vlan_tci;
> > > __be32 data[2];
> > > };
> >
> > I am wondering about the semantics of these vlan_* fields. Is vlan_etype the
> > Ethertype in the VLAN header or the type after it?
>
> It would be the the type in the VLAN tag. The nested ethertype is
> normally implied by flow_type to be ETH_P_IP.
>
> This does leave the question of what this would mean:
>
> struct ethtool_rx_flow_spec fs = {
> .flow_type = ... | FLOW_EXT,
> ...
> .h_ext.vlan_tci = htons(0x1234),
> .m_ext.vlan_etype = 0xffff,
> };
>
> This says the TCI must be == 0x1234 but the type can be anything. But
> the type surely has to be be one assigned for use in VLAN tags. Should
> we leave it to the driver/hardware to determine what those valid types
> are, or should we reject this as valid?
Right. Devices have some internal rules for what qualifies as a VLAN frame.
If users are given the option to specify vlan_etype what do they get?
At least we need to specify what is expected so drivers can decide if they can support it.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox