diff options
Diffstat (limited to 'drivers/misc/genwqe/card_utils.c')
-rw-r--r-- | drivers/misc/genwqe/card_utils.c | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 147b83011b58..8f2e6442d88b 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -296,7 +296,7 @@ static int genwqe_sgl_size(int num_pages) * from user-space into the cached pages. */ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, - void __user *user_addr, size_t user_size) + void __user *user_addr, size_t user_size, int write) { int rc; struct pci_dev *pci_dev = cd->pci_dev; @@ -312,6 +312,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, sgl->user_addr = user_addr; sgl->user_size = user_size; + sgl->write = write; sgl->sgl_size = genwqe_sgl_size(sgl->nr_pages); if (get_order(sgl->sgl_size) > MAX_ORDER) { @@ -476,14 +477,20 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) { int rc = 0; + size_t offset; + unsigned long res; struct pci_dev *pci_dev = cd->pci_dev; if (sgl->fpage) { - if (copy_to_user(sgl->user_addr, sgl->fpage + sgl->fpage_offs, - sgl->fpage_size)) { - dev_err(&pci_dev->dev, "[%s] err: copying fpage!\n", - __func__); - rc = -EFAULT; + if (sgl->write) { + res = copy_to_user(sgl->user_addr, + sgl->fpage + sgl->fpage_offs, sgl->fpage_size); + if (res) { + dev_err(&pci_dev->dev, + "[%s] err: copying fpage! (res=%lu)\n", + __func__, res); + rc = -EFAULT; + } } __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage, sgl->fpage_dma_addr); @@ -491,12 +498,16 @@ int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) sgl->fpage_dma_addr = 0; } if (sgl->lpage) { - if (copy_to_user(sgl->user_addr + sgl->user_size - - sgl->lpage_size, sgl->lpage, - sgl->lpage_size)) { - dev_err(&pci_dev->dev, "[%s] err: copying lpage!\n", - __func__); - rc = -EFAULT; + if (sgl->write) { + offset = sgl->user_size - sgl->lpage_size; + res = copy_to_user(sgl->user_addr + offset, sgl->lpage, + sgl->lpage_size); + if (res) { + dev_err(&pci_dev->dev, + "[%s] err: copying lpage! (res=%lu)\n", + __func__, res); + rc = -EFAULT; + } } __genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage, sgl->lpage_dma_addr); @@ -513,22 +524,16 @@ int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) } /** - * free_user_pages() - Give pinned pages back + * genwqe_free_user_pages() - Give pinned pages back * - * Documentation of get_user_pages is in mm/memory.c: + * Documentation of get_user_pages is in mm/gup.c: * * If the page is written to, set_page_dirty (or set_page_dirty_lock, * as appropriate) must be called after the page is finished with, and * before put_page is called. - * - * FIXME Could be of use to others and might belong in the generic - * code, if others agree. E.g. - * ll_free_user_pages in drivers/staging/lustre/lustre/llite/rw26.c - * ceph_put_page_vector in net/ceph/pagevec.c - * maybe more? */ -static int free_user_pages(struct page **page_list, unsigned int nr_pages, - int dirty) +static int genwqe_free_user_pages(struct page **page_list, + unsigned int nr_pages, int dirty) { unsigned int i; @@ -566,7 +571,7 @@ static int free_user_pages(struct page **page_list, unsigned int nr_pages, * Return: 0 if success */ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, - unsigned long size, struct ddcb_requ *req) + unsigned long size) { int rc = -EINVAL; unsigned long data, offs; @@ -599,14 +604,14 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, /* pin user pages in memory */ rc = get_user_pages_fast(data & PAGE_MASK, /* page aligned addr */ m->nr_pages, - 1, /* write by caller */ + m->write, /* readable/writable */ m->page_list); /* ptrs to pages */ if (rc < 0) goto fail_get_user_pages; /* assumption: get_user_pages can be killed by signals. */ if (rc < m->nr_pages) { - free_user_pages(m->page_list, rc, 0); + genwqe_free_user_pages(m->page_list, rc, m->write); rc = -EFAULT; goto fail_get_user_pages; } @@ -618,7 +623,7 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, return 0; fail_free_user_pages: - free_user_pages(m->page_list, m->nr_pages, 0); + genwqe_free_user_pages(m->page_list, m->nr_pages, m->write); fail_get_user_pages: kfree(m->page_list); @@ -636,8 +641,7 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, * @cd: pointer to genwqe device * @m: mapping params */ -int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, - struct ddcb_requ *req) +int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m) { struct pci_dev *pci_dev = cd->pci_dev; @@ -651,7 +655,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, genwqe_unmap_pages(cd, m->dma_list, m->nr_pages); if (m->page_list) { - free_user_pages(m->page_list, m->nr_pages, 1); + genwqe_free_user_pages(m->page_list, m->nr_pages, m->write); kfree(m->page_list); m->page_list = NULL; |