lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Mon, 25 Apr 2011 17:23:53 -0400 From: dykmanj@...ux.vnet.ibm.com To: netdev@...r.kernel.org Cc: Jim Dykman <dykmanj@...ux.vnet.ibm.com>, Piyush Chaudhary <piyushc@...ux.vnet.ibm.com>, Fu-Chung Chang <fcchang@...ux.vnet.ibm.com>, " William S. Cadden" <wscadden@...ux.vnet.ibm.com>, " Wen C. Chen" <winstonc@...ux.vnet.ibm.com>, Scot Sakolish <sakolish@...ux.vnet.ibm.com>, Jian Xiao <jian@...ux.vnet.ibm.com>, " Carol L. Soto" <clsoto@...ux.vnet.ibm.com>, " Sarah J. Sheppard" <sjsheppa@...ux.vnet.ibm.com> Subject: [PATCH v4 13/27] HFI: Send and receive fifo address translation From: Jim Dykman <dykmanj@...ux.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@...ux.vnet.ibm.com> Signed-off-by: Jim Dykman <dykmanj@...ux.vnet.ibm.com> Signed-off-by: Fu-Chung Chang <fcchang@...ux.vnet.ibm.com> Signed-off-by: William S. Cadden <wscadden@...ux.vnet.ibm.com> Signed-off-by: Wen C. Chen <winstonc@...ux.vnet.ibm.com> Signed-off-by: Scot Sakolish <sakolish@...ux.vnet.ibm.com> Signed-off-by: Jian Xiao <jian@...ux.vnet.ibm.com> Signed-off-by: Carol L. Soto <clsoto@...ux.vnet.ibm.com> Signed-off-by: Sarah J. Sheppard <sjsheppa@...ux.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 69fc7fa..1fbd6a6 100644 --- a/include/linux/hfi/hfidd_internal.h +++ b/include/linux/hfi/hfidd_internal.h @@ -62,6 +62,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@...ux.vnet.ibm.com> + * William S. Cadden <wscadden@...ux.vnet.ibm.com> + * Wen C. Chen <winstonc@...ux.vnet.ibm.com> + * Scot Sakolish <sakolish@...ux.vnet.ibm.com> + * Jian Xiao <jian@...ux.vnet.ibm.com> + * Carol L. Soto <clsoto@...ux.vnet.ibm.com> + * Sarah J. Sheppard <sjsheppa@...ux.vnet.ibm.com> + * + * (C) Copyright IBM Corp. 2010 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _HFIDD_XLAT_MAP_H_ +#define _HFIDD_XLAT_MAP_H_ + +#include <linux/hfi/hfidd_client.h> + +/* + * So we can shift rather than divide! + */ +#define PAGE_SHIFT_2K 11 +#define PAGE_SHIFT_4K 12 +#define PAGE_SHIFT_64K 16 +#define PAGE_SHIFT_1M 20 +#define PAGE_SHIFT_16M 24 +#define PAGE_SHIFT_4G 32 + +struct page_num_code { + union { + unsigned long long llu_value; + struct num_and_code { + unsigned int pg_num; + unsigned int pg_code; + } fields; + } num_code; +}; + +struct hfidd_vlxmem { + unsigned long long page_sz; /* actual page size */ + unsigned int num_page; /* calculated using actual + page size */ + unsigned int rsvd; + struct page_num_code num_page_sz; /* page num and size code + mapping */ + unsigned long long map_page_sz; /* page size used for mapping */ + caddr_t m_addr; /* aligned address start for + mapping */ + caddr_t v_addr; /* user given vaddr */ + caddr_t e_addr; + + unsigned long long len; + unsigned long long access_flag; + void *l_pages; + + unsigned long long mr_handle; + unsigned int l_key; + + struct task *xd; + + int num_kpage; /* num of kernel pages */ + atomic_t *share_cnt; /* # of processes sharing this + submr */ + unsigned int num_chunks; /* number of chunks the mr is + divided */ + caddr_t mr_addr; /* aligned submr starting + address */ + void *page_list; /* struct page_list */ + unsigned int liobn; /* logical I/O bus number */ +}; + +#endif -- 1.7.3.5 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists