From patchwork Thu Apr 21 21:38:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: dykmanj@linux.vnet.ibm.com X-Patchwork-Id: 92465 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 1AE92B6FD3 for ; Fri, 22 Apr 2011 07:39:54 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755236Ab1DUVjl (ORCPT ); Thu, 21 Apr 2011 17:39:41 -0400 Received: from e1.ny.us.ibm.com ([32.97.182.141]:47332 "EHLO e1.ny.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753881Ab1DUVjj (ORCPT ); Thu, 21 Apr 2011 17:39:39 -0400 Received: from d01relay05.pok.ibm.com (d01relay05.pok.ibm.com [9.56.227.237]) by e1.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p3LLSvqC027307 for ; Thu, 21 Apr 2011 17:28:57 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay05.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p3LLdCn3124374 for ; Thu, 21 Apr 2011 17:39:18 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p3LLd9xA012583 for ; Thu, 21 Apr 2011 17:39:11 -0400 Received: from c250f05gpfs06.ppd.pok.ibm.com (c250f05gpfs06.ppd.pok.ibm.com [9.114.87.187]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p3LLd8uO012447; Thu, 21 Apr 2011 17:39:09 -0400 From: dykmanj@linux.vnet.ibm.com To: netdev@vger.kernel.org Cc: Jim Dykman , Piyush Chaudhary , Fu-Chung Chang , " William S. Cadden" , " Wen C. Chen" , Scot Sakolish , Jian Xiao , " Carol L. Soto" , " Sarah J. Sheppard" Subject: [PATCH v3 12/27] HFI: Sanity check send and receive fifo parameters Date: Thu, 21 Apr 2011 17:38:42 -0400 Message-Id: <1303421937-2325-13-git-send-email-dykmanj@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.3.5 In-Reply-To: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com> References: <1303421937-2325-1-git-send-email-dykmanj@linux.vnet.ibm.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Jim Dykman Signed-off-by: Piyush Chaudhary Signed-off-by: Jim Dykman Signed-off-by: Fu-Chung Chang Signed-off-by: William S. Cadden Signed-off-by: Wen C. Chen Signed-off-by: Scot Sakolish Signed-off-by: Jian Xiao Signed-off-by: Carol L. Soto Signed-off-by: Sarah J. Sheppard --- drivers/net/hfi/core/Makefile | 1 + drivers/net/hfi/core/hfidd_proto.h | 3 + drivers/net/hfi/core/hfidd_window.c | 177 +++++++++++++++++++++++++++++++++++ drivers/net/hfi/core/hfidd_xlat.c | 131 ++++++++++++++++++++++++++ include/linux/hfi/hfidd_adpt.h | 17 ++++ 5 files changed, 329 insertions(+), 0 deletions(-) create mode 100644 drivers/net/hfi/core/hfidd_xlat.c diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile index 0224a57..8d5558d 100644 --- a/drivers/net/hfi/core/Makefile +++ b/drivers/net/hfi/core/Makefile @@ -4,5 +4,6 @@ hfi_core-objs:= hfidd_adpt.o \ hfidd_window.o \ hfidd_init.o \ + hfidd_xlat.o \ hfidd_hcalls.o obj-$(CONFIG_HFI) += hfi_core.o diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h index e7f2901..66ea5da 100644 --- a/drivers/net/hfi/core/hfidd_proto.h +++ b/drivers/net/hfi/core/hfidd_proto.h @@ -39,6 +39,9 @@ int hfidd_alloc_windows(struct hfidd_acs *p_acs); void hfidd_free_windows(struct hfidd_acs *p_acs); int hfidd_init_adapter(struct hfidd_acs *p_acs, void *uiop); int hfidd_age_hcall(u64 time_start); +int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr, + unsigned int is_userspace, unsigned int length, + unsigned long long *page_size); int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace, struct hfi_client_info *user_p, struct hfi_client_info *out_p); diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c index cc775e3..5a4f395 100644 --- a/drivers/net/hfi/core/hfidd_window.c +++ b/drivers/net/hfi/core/hfidd_window.c @@ -35,6 +35,153 @@ #include "hfidd_proto.h" #include +#define FINISH_VECTOR_LENGTH 1 +/* Validate send fifo parameters needed for open window */ +static int hfi_check_sfifo_parm(struct hfidd_acs *p_acs, + unsigned int is_userspace, + struct hfidd_window *win_p, + struct hfi_client_info *client_p) +{ + int rc = 0; + unsigned long long page_sz; + unsigned long long fv_page_sz; + + /* Validate the sfifo size */ + if ((client_p->sfifo.size < HFI_SFIFO_SIZE_MIN) || + (client_p->sfifo.size > HFI_SFIFO_SIZE_MAX)) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: invalid sfifo " + "size = 0x%llx\n", + client_p->sfifo.size); + return -EINVAL; + } + + /* + * Validate the address of sfifo is 4k aligned, and finish vector + * is cache-line aligned + */ + if ((client_p->sfifo.eaddr.use.allu) & PAGE_MASK_4K) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: not page aligned, " + "sfifo_addr = 0x%llx\n", + client_p->sfifo.eaddr.use.allu); + return -EINVAL; + } + + if ((client_p->sfifo_finish_vec.use.allu) & HFI_CACHE_LINE_MASK) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: not cache aligned, " + "sfifo_finishvec = 0x%llx\n", + client_p->sfifo_finish_vec.use.allu); + return -EINVAL; + } + /* + * Validate the send finish vector are within 4K bytes of end of sfifo + */ + if (((client_p->sfifo_finish_vec.use.kptr - + (client_p->sfifo.eaddr.use.kptr + + client_p->sfifo.size)) >= PAGE_SIZE_4K)) { + + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: fv too far away, " + "sfifo_addr = 0x%llx\n", + client_p->sfifo.eaddr.use.allu); + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: fv too far away, " + "sfifo_finishvec = 0x%llx\n", + client_p->sfifo_finish_vec.use.allu); + return -EINVAL; + } + + /* Validate page size of sFifo */ + rc = hfidd_get_page_size(p_acs, client_p->sfifo.eaddr.use.kptr, + is_userspace, client_p->sfifo.size, &page_sz); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: fail in sfifo page size, " + "rc=0x%x\n", rc); + return rc; + } + + /* Find out the page size of send finish vector */ + rc = hfidd_get_page_size(p_acs, client_p->sfifo_finish_vec.use.kptr, + is_userspace, FINISH_VECTOR_LENGTH, &fv_page_sz); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: fail in fv page size, " + "rc=0x%x\n", rc); + return rc; + } + + /* The page size of finish vector must be the same as sfifo */ + if (page_sz != fv_page_sz) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_sfifo_parm: diff page sz sf=0x%llx, " + "fv0=0x%llx\n", page_sz, fv_page_sz); + return -EINVAL; + } + return 0; +} + +static int hfi_check_rfifo_parm(struct hfidd_acs *p_acs, + unsigned int is_userspace, + struct hfidd_window *win_p, + struct hfi_client_info *client_p) +{ + int rc = 0; + unsigned long long page_sz; + + /* Validate the rfifo size */ + if ((client_p->rfifo.size < HFI_RFIFO_SIZE_MIN) || + (client_p->rfifo.size > HFI_RFIFO_SIZE_MAX)) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_rfifo_parm: invalid rfifo size = 0x%llx\n", + client_p->rfifo.size); + return -EINVAL; + } + + /* Validate the address of rfifo is 4K aligned */ + if ((client_p->rfifo.eaddr.use.allu) & PAGE_MASK_4K) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_rfifo_parm: not cache aligned, " + "rfifo_addr = 0x%llx\n", + client_p->rfifo.eaddr.use.allu); + return -EINVAL; + } + + /* Validate page size of rFifo */ + rc = hfidd_get_page_size(p_acs, client_p->rfifo.eaddr.use.kptr, + is_userspace, client_p->rfifo.size, &page_sz); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_check_rfifo_parm: fail in rfifo page size, " + "rc=0x%x\n", rc); + return rc; + } + return 0; +} + +/* Validate window parameters to setup the fifos and RDMA function */ +static int hfi_validate_window_request(struct hfidd_acs *p_acs, + unsigned int is_userspace, struct hfi_client_info *client_p) +{ + int rc = 0; + struct hfidd_window *win_p; + + /* Check every input parameters..... */ + win_p = hfi_window(p_acs, client_p->window); + + /* Check the request of sFifo */ + rc = hfi_check_sfifo_parm(p_acs, is_userspace, win_p, client_p); + if (rc) + return rc; + /* Check the request of rFifo */ + rc = hfi_check_rfifo_parm(p_acs, is_userspace, win_p, client_p); + if (rc) + return rc; + return rc; +} + /* Validate the type, state and job id for RESERVED window */ static int hfi_validate_reserve_window_id(struct hfidd_acs *p_acs, struct hfi_client_info *client_p) @@ -164,12 +311,29 @@ static inline int hfi_validate_window_id(struct hfidd_acs *p_acs, return rc; } +static inline void hfi_restore_window_parm(struct hfidd_acs *p_acs, + struct hfidd_window *win_p) +{ + if (win_p->type != HFIDD_RESERVE_WIN) { + win_p->type = HFIDD_DYNAMIC_WIN; + win_p->job_id = 0; + if (win_p->state != WIN_HERROR) + win_p->state = WIN_AVAILABLE; + } else { + if (win_p->state != WIN_HERROR) + win_p->state = WIN_RESERVED; + } + win_p->pid = 0; + win_p->is_ip = 0; +} + /* Validate window number and type for open window request */ static int hfi_validate_window_parm(struct hfidd_acs *p_acs, unsigned int is_userspace, struct hfi_client_info *client_p) { int rc = 0; + struct hfidd_window *win_p; /* Validate the window number */ rc = hfi_validate_window_id(p_acs, client_p, is_userspace); @@ -179,6 +343,19 @@ static int hfi_validate_window_parm(struct hfidd_acs *p_acs, "failed, rc = 0x%x\n", rc); return rc; } + + rc = hfi_validate_window_request(p_acs, is_userspace, client_p); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_validate_window_parm: " + "hfi_validate_window_request failed, rc = 0x%x\n", rc); + win_p = hfi_window(p_acs, client_p->window); + spin_lock(&(win_p->win_lock)); + hfi_restore_window_parm(p_acs, win_p); + spin_unlock(&(win_p->win_lock)); + return rc; + } + return 0; } diff --git a/drivers/net/hfi/core/hfidd_xlat.c b/drivers/net/hfi/core/hfidd_xlat.c new file mode 100644 index 0000000..23236cc --- /dev/null +++ b/drivers/net/hfi/core/hfidd_xlat.c @@ -0,0 +1,131 @@ +/* + * hfidd_xlat.c + * + * HFI device driver for IBM System p + * + * Authors: + * Fu-Chung Chang + * William S. Cadden + * Wen C. Chen + * Scot Sakolish + * Jian Xiao + * Carol L. Soto + * Sarah J. Sheppard + * + * (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 +#include +#include + +#include +#include "hfidd_proto.h" + +int hfidd_get_page_size(struct hfidd_acs *p_acs, void *addr, + unsigned int is_userspace, + unsigned int length, + unsigned long long *page_size) +{ + int rc = 0; + int i; + int num_pages; + struct page **page_list; + struct vm_area_struct **vma_list; + unsigned long long offset; + + if (!is_userspace) { + *page_size = PAGE_SIZE; + return 0; + } + + offset = (unsigned long long)addr & ~PAGE_MASK; + num_pages = PAGE_ALIGN(length + offset) >> PAGE_SHIFT; + + page_list = kzalloc(num_pages * sizeof(struct page *), + GFP_KERNEL); + if (page_list == NULL) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_get_page_size: kzalloc failed for page_list\n"); + return -ENOMEM; + } + + vma_list = kzalloc(num_pages * sizeof(struct vm_area_struct **), + GFP_KERNEL); + if (vma_list == NULL) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_get_page_size: kzalloc failed for vma_list\n"); + rc = -ENOMEM; + goto out1; + } + + down_read(¤t->mm->mmap_sem); + rc = get_user_pages(current, current->mm, + (unsigned long long)addr, + num_pages, 1, 0, /* yes write, no force */ + page_list, vma_list); + up_read(¤t->mm->mmap_sem); + + if (rc < num_pages) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_get_page_size: get_user_pages failed rc = %d " + "and numpages %d\n", rc, num_pages); + if (rc < 0) + goto out2; + num_pages = rc; + rc = -ENOMEM; + goto out3; + } + + rc = 0; + *page_size = PAGE_SIZE; + for (i = 0; i < num_pages; i++) { + /* check for huge pages */ + if (is_vm_hugetlb_page(vma_list[i])) { + /* Find huge page size */ + *page_size = huge_page_size(hstate_vma(vma_list[i])); + break; + } + } + + /* If memory has huge page size, check if all pages are huge pages */ + if (*page_size != PAGE_SIZE) { + for (i = 0; i < num_pages; i++) { + /* if not huge page, set to PAGE_SIZE */ + if (!is_vm_hugetlb_page(vma_list[i])) { + *page_size = PAGE_SIZE; + break; + } + } + } + if (*page_size == PAGE_SIZE_16G) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_get_page_size: Large page size " + "0x%llx use 4G\n", *page_size); + *page_size = PAGE_SIZE_4G; + } + +out3: + for (i = 0; i < num_pages; i++) + page_cache_release(page_list[i]); +out2: + kfree(vma_list); +out1: + kfree(page_list); + return rc; +} diff --git a/include/linux/hfi/hfidd_adpt.h b/include/linux/hfi/hfidd_adpt.h index babdb14..a41825f 100644 --- a/include/linux/hfi/hfidd_adpt.h +++ b/include/linux/hfi/hfidd_adpt.h @@ -36,6 +36,16 @@ #include +#define HFI_SFIFO_SIZE_MIN 0x10000 /* min = 64K software limit */ +#define HFI_SFIFO_SIZE_MAX 0x800000 /* max = 8M */ + +#define HFI_RFIFO_SIZE_MIN 0x1000 /* min = 4K */ +#define HFI_RFIFO_SIZE_MAX 0x8000000 /* max = 128M */ + +#define HFI_CACHE_LINE_SIZE 0x80 +#define HFI_CACHE_LINE_MASK (HFI_CACHE_LINE_SIZE - 1) +#define HFI_CACHE_LINE_SHIFT 7 + #define HFI_WNUM_SHIFT 32 #define HFI_CAUNUM_SHIFT 32 #define HFI_SHIFT_OCTANT 3 @@ -57,4 +67,11 @@ #define WIN_PENDING 6 #define WIN_FAIL_CLOSE 7 +#define PAGE_MASK_4K (PAGE_SIZE_4K - 1) +#define PAGE_MASK_64K (PAGE_SIZE_64K - 1) +#define PAGE_MASK_1M (PAGE_SIZE_1M - 1) +#define PAGE_MASK_16M (PAGE_SIZE_16M - 1) +#define PAGE_MASK_4G (PAGE_SIZE_4G - 1) +#define PAGE_MASK_16G (PAGE_SIZE_16G - 1) + #endif /* _HFIDD_ADPT_H_ */