From mboxrd@z Thu Jan 1 00:00:00 1970 From: dykmanj@linux.vnet.ibm.com Subject: [PATCH 18/27] HFI: Map window registers into user process Date: Wed, 2 Mar 2011 16:10:04 -0500 Message-ID: <1299100213-8770-18-git-send-email-dykmanj@linux.vnet.ibm.com> References: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com> Cc: Jim Dykman , Piyush Chaudhary , Fu-Chung Chang , " William S. Cadden" , " Wen C. Chen" , Scot Sakolish , Jian Xiao , " Carol L. Soto" , " Sarah J. Sheppard" Return-path: Received: from e3.ny.us.ibm.com ([32.97.182.143]:55627 "EHLO e3.ny.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757563Ab1CBVK3 (ORCPT ); Wed, 2 Mar 2011 16:10:29 -0500 Received: from d01dlp01.pok.ibm.com (d01dlp01.pok.ibm.com [9.56.224.56]) by e3.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p22KoQr4016512 for ; Wed, 2 Mar 2011 15:50:26 -0500 Received: from d01relay05.pok.ibm.com (d01relay05.pok.ibm.com [9.56.227.237]) by d01dlp01.pok.ibm.com (Postfix) with ESMTP id F171138C803D for ; Wed, 2 Mar 2011 16:10:27 -0500 (EST) Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay05.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p22LASTM230978 for ; Wed, 2 Mar 2011 16:10:28 -0500 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p22LARFC032346 for ; Wed, 2 Mar 2011 16:10:28 -0500 To: netdev@vger.kernel.org In-Reply-To: <1299100213-8770-1-git-send-email-dykmanj@linux.vnet.ibm.com> To: netdev@vger.kernel.org Sender: netdev-owner@vger.kernel.org List-ID: From: Jim Dykman User-space applications send and receive without kernel involvement, once the window is open. A page of hardware registers controlling the appropriate window is mapped into the user's address space. Signed-off-by: Piyush Chaudhary 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_map.c | 99 +++++++++++++++++++++++++++++++++++ drivers/net/hfi/core/hfidd_proto.h | 4 ++ drivers/net/hfi/core/hfidd_window.c | 51 ++++++++++++++++++- 4 files changed, 154 insertions(+), 1 deletions(-) create mode 100644 drivers/net/hfi/core/hfidd_map.c diff --git a/drivers/net/hfi/core/Makefile b/drivers/net/hfi/core/Makefile index 8d5558d..3adf07e 100644 --- a/drivers/net/hfi/core/Makefile +++ b/drivers/net/hfi/core/Makefile @@ -5,5 +5,6 @@ hfi_core-objs:= hfidd_adpt.o \ hfidd_window.o \ hfidd_init.o \ hfidd_xlat.o \ + hfidd_map.o \ hfidd_hcalls.o obj-$(CONFIG_HFI) += hfi_core.o diff --git a/drivers/net/hfi/core/hfidd_map.c b/drivers/net/hfi/core/hfidd_map.c new file mode 100644 index 0000000..816e7ae --- /dev/null +++ b/drivers/net/hfi/core/hfidd_map.c @@ -0,0 +1,99 @@ +/* + * hfidd_map.c + * + * HFI device driver for IBM System p + * + * Authors: + * Fu-Chung Chang + * 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 + +int hfidd_mmap(struct hfidd_acs *p_acs, void **eaddr, int size, + unsigned long vm_flag, unsigned long long busaddr, + unsigned long long offset) +{ + struct vm_area_struct *vma; + unsigned long vsize; + int rc; + + down_write(¤t->mm->mmap_sem); + *eaddr = (void *)do_mmap(NULL, (unsigned long)*eaddr, size, PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, + offset); + up_write(¤t->mm->mmap_sem); + if (*eaddr) { + vma = find_vma(current->mm, (u64) *eaddr); + if (!vma) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_mmap: find_vma failed\n"); + return -ENOMEM; + } + } else { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_mmap: do_mmap failed\n"); + return -ENOMEM; + } + + vsize = vma->vm_end - vma->vm_start; + if (vsize != size) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_mmap: Wrong sizes: vsize = %ld " + "size = %d\n", vsize, size); + return -EINVAL; + } + + if (vm_flag == VM_RESERVED) + vma->vm_page_prot = pgprot_val(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= vm_flag; + + rc = remap_pfn_range(vma, vma->vm_start, busaddr >> PAGE_SHIFT, size, + vma->vm_page_prot); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_mmap: remap_pfn_range failed\n"); + return -ENOMEM; + } + + return 0; +} + +int hfidd_unmap(void *addr, int size) +{ + int rc = 0; + struct mm_struct *mm = current->mm; + + if (mm && (addr != NULL)) { + down_write(&mm->mmap_sem); + rc = do_munmap(mm, (unsigned long)addr, size); + up_write(&mm->mmap_sem); + } + + return rc; +} diff --git a/drivers/net/hfi/core/hfidd_proto.h b/drivers/net/hfi/core/hfidd_proto.h index c4ed215..1f7fe80 100644 --- a/drivers/net/hfi/core/hfidd_proto.h +++ b/drivers/net/hfi/core/hfidd_proto.h @@ -57,6 +57,10 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace, int hfi_register_rpages(struct hfidd_acs *p_acs, unsigned long long mr_handle, unsigned int submr, struct hfidd_vlxmem *xtab_p, unsigned int *mapped_pages); +int hfidd_mmap(struct hfidd_acs *p_acs, void **eaddr, int size, + unsigned long vm_flag, unsigned long long busaddr, + unsigned long long offset); +int hfidd_unmap(void *addr, int size); int hfidd_get_phyp_page(struct hfidd_acs *p_acs, caddr_t *page, caddr_t *laddr, int size); void hfidd_release_phyp_page(caddr_t page, int size); diff --git a/drivers/net/hfi/core/hfidd_window.c b/drivers/net/hfi/core/hfidd_window.c index 3a9fea9..4ee96f8 100644 --- a/drivers/net/hfi/core/hfidd_window.c +++ b/drivers/net/hfi/core/hfidd_window.c @@ -875,6 +875,44 @@ setup_window_parm_err1: return rc; } +/* Map the window mmio registers - only user space window */ +static int hfi_map_mmio_regs(struct hfidd_acs *p_acs, + unsigned int is_userspace, + struct hfidd_window *win_p, + struct hfi_client_info *client_p) +{ + int rc = 0; + unsigned long long offset; + void *tmp_eaddr; + + if (!is_userspace) { + /* No translation, just pass back the logical address */ + client_p->mmio_regs.use.kptr = (void *)win_p->mmio_regs; + win_p->client_info.mmio_regs.use.kptr = + (void *)win_p->mmio_regs; + } else { + /* + * Translate mmio_regs from logical to effective address: 1st + * page + */ + tmp_eaddr = 0; + offset = (client_p->window) << PAGE_SHIFT_64K; + rc = hfidd_mmap(p_acs, &tmp_eaddr, PAGE_SIZE_64K, + VM_RESERVED | VM_IO, + (long long)win_p->mmio_regs, offset); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfi_map_mmio_regs: hfidd_mmap mmio_regs " + "failed, rc = 0x%x, mmio_regs = 0x%llx\n", + rc, (unsigned long long)win_p->mmio_regs); + return rc; + } + client_p->mmio_regs.use.kptr = tmp_eaddr; + win_p->client_info.mmio_regs.use.kptr = tmp_eaddr; + } + return 0; +} + /* * Allows an user/kernel window to send/receive network traffic thru HFI * adapter. This function will allocate the system resources needed to open @@ -941,6 +979,14 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace, goto hfidd_open_window_func_err4; } + rc = hfi_map_mmio_regs(p_acs, is_userspace, win_p, local_p); + if (rc) { + dev_printk(KERN_ERR, p_acs->hfidd_dev, + "hfidd_open_window_func: hfi_map_mmio_regs " + "failed, rc = 0x%x\n", rc); + goto hfidd_open_window_func_err4; + } + /* tell user the local ISR id */ local_p->local_isrid = p_acs->isr; win_p->client_info.local_isrid = p_acs->isr; @@ -952,7 +998,7 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace, dev_printk(KERN_ERR, p_acs->hfidd_dev, "hfidd_open_window_func: hfi_copy_to_user " "failed, rc = 0x%x\n", rc); - goto hfidd_open_window_func_err4; + goto hfidd_open_window_func_err5; } spin_lock(&(win_p->win_lock)); @@ -964,6 +1010,9 @@ int hfidd_open_window_func(struct hfidd_acs *p_acs, unsigned int is_userspace, kfree(local_p); return rc; +hfidd_open_window_func_err5: + if (is_userspace) + hfidd_unmap(local_p->mmio_regs.use.kptr, PAGE_SIZE_64K); hfidd_open_window_func_err4: hfi_destroy_window_parm(p_acs, is_userspace, win_p, local_p); hfidd_open_window_func_err3: -- 1.7.3.1