IB/uverbs: Export ib_umem_get()/ib_umem_release() to modules
Export ib_umem_get()/ib_umem_release() and put low-level drivers in control of when to call ib_umem_get() to pin and DMA map userspace, rather than always calling it in ib_uverbs_reg_mr() before calling the low-level driver's reg_user_mr method. Also move these functions to be in the ib_core module instead of ib_uverbs, so that driver modules using them do not depend on ib_uverbs. This has a number of advantages: - It is better design from the standpoint of making generic code a library that can be used or overridden by device-specific code as the details of specific devices dictate. - Drivers that do not need to pin userspace memory regions do not need to take the performance hit of calling ib_mem_get(). For example, although I have not tried to implement it in this patch, the ipath driver should be able to avoid pinning memory and just use copy_{to,from}_user() to access userspace memory regions. - Buffers that need special mapping treatment can be identified by the low-level driver. For example, it may be possible to solve some Altix-specific memory ordering issues with mthca CQs in userspace by mapping CQ buffers with extra flags. - Drivers that need to pin and DMA map userspace memory for things other than memory regions can use ib_umem_get() directly, instead of hacks using extra parameters to their reg_phys_mr method. For example, the mlx4 driver that is pending being merged needs to pin and DMA map QP and CQ buffers, but it does not need to create a memory key for these buffers. So the cleanest solution is for mlx4 to call ib_umem_get() in the create_qp and create_cq methods. Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <rdma/ib_smi.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
#include <rdma/ib_user_verbs.h>
|
||||
#include "c2.h"
|
||||
#include "c2_provider.h"
|
||||
@@ -396,6 +397,7 @@ static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
|
||||
}
|
||||
|
||||
mr->pd = to_c2pd(ib_pd);
|
||||
mr->umem = NULL;
|
||||
pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
|
||||
"*iova_start %llx, first pa %llx, last pa %llx\n",
|
||||
__FUNCTION__, page_shift, pbl_depth, total_len,
|
||||
@@ -428,8 +430,8 @@ static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
|
||||
return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
|
||||
}
|
||||
|
||||
static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int acc, struct ib_udata *udata)
|
||||
static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt, int acc, struct ib_udata *udata)
|
||||
{
|
||||
u64 *pages;
|
||||
u64 kva = 0;
|
||||
@@ -441,15 +443,23 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
struct c2_mr *c2mr;
|
||||
|
||||
pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
|
||||
shift = ffs(region->page_size) - 1;
|
||||
|
||||
c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
|
||||
if (!c2mr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
c2mr->pd = c2pd;
|
||||
|
||||
c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
|
||||
if (IS_ERR(c2mr->umem)) {
|
||||
err = PTR_ERR(c2mr->umem);
|
||||
kfree(c2mr);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
shift = ffs(c2mr->umem->page_size) - 1;
|
||||
|
||||
n = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &c2mr->umem->chunk_list, list)
|
||||
n += chunk->nents;
|
||||
|
||||
pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
|
||||
@@ -459,35 +469,34 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
}
|
||||
|
||||
i = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list) {
|
||||
list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) {
|
||||
for (j = 0; j < chunk->nmap; ++j) {
|
||||
len = sg_dma_len(&chunk->page_list[j]) >> shift;
|
||||
for (k = 0; k < len; ++k) {
|
||||
pages[i++] =
|
||||
sg_dma_address(&chunk->page_list[j]) +
|
||||
(region->page_size * k);
|
||||
(c2mr->umem->page_size * k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kva = (u64)region->virt_base;
|
||||
kva = virt;
|
||||
err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
|
||||
pages,
|
||||
region->page_size,
|
||||
c2mr->umem->page_size,
|
||||
i,
|
||||
region->length,
|
||||
region->offset,
|
||||
length,
|
||||
c2mr->umem->offset,
|
||||
&kva,
|
||||
c2_convert_access(acc),
|
||||
c2mr);
|
||||
kfree(pages);
|
||||
if (err) {
|
||||
kfree(c2mr);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
if (err)
|
||||
goto err;
|
||||
return &c2mr->ibmr;
|
||||
|
||||
err:
|
||||
ib_umem_release(c2mr->umem);
|
||||
kfree(c2mr);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
@@ -502,8 +511,11 @@ static int c2_dereg_mr(struct ib_mr *ib_mr)
|
||||
err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
|
||||
if (err)
|
||||
pr_debug("c2_stag_dealloc failed: %d\n", err);
|
||||
else
|
||||
else {
|
||||
if (mr->umem)
|
||||
ib_umem_release(mr->umem);
|
||||
kfree(mr);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@@ -73,6 +73,7 @@ struct c2_pd {
|
||||
struct c2_mr {
|
||||
struct ib_mr ibmr;
|
||||
struct c2_pd *pd;
|
||||
struct ib_umem *umem;
|
||||
};
|
||||
|
||||
struct c2_av;
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include <rdma/iw_cm.h>
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <rdma/ib_smi.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
#include <rdma/ib_user_verbs.h>
|
||||
|
||||
#include "cxio_hal.h"
|
||||
@@ -443,6 +444,8 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr)
|
||||
remove_handle(rhp, &rhp->mmidr, mmid);
|
||||
if (mhp->kva)
|
||||
kfree((void *) (unsigned long) mhp->kva);
|
||||
if (mhp->umem)
|
||||
ib_umem_release(mhp->umem);
|
||||
PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp);
|
||||
kfree(mhp);
|
||||
return 0;
|
||||
@@ -577,8 +580,8 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
|
||||
}
|
||||
|
||||
|
||||
static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int acc, struct ib_udata *udata)
|
||||
static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt, int acc, struct ib_udata *udata)
|
||||
{
|
||||
__be64 *pages;
|
||||
int shift, n, len;
|
||||
@@ -591,7 +594,6 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
struct iwch_reg_user_mr_resp uresp;
|
||||
|
||||
PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
|
||||
shift = ffs(region->page_size) - 1;
|
||||
|
||||
php = to_iwch_pd(pd);
|
||||
rhp = php->rhp;
|
||||
@@ -599,8 +601,17 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
if (!mhp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc);
|
||||
if (IS_ERR(mhp->umem)) {
|
||||
err = PTR_ERR(mhp->umem);
|
||||
kfree(mhp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
shift = ffs(mhp->umem->page_size) - 1;
|
||||
|
||||
n = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
|
||||
n += chunk->nents;
|
||||
|
||||
pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
|
||||
@@ -611,13 +622,13 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
|
||||
i = n = 0;
|
||||
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
|
||||
for (j = 0; j < chunk->nmap; ++j) {
|
||||
len = sg_dma_len(&chunk->page_list[j]) >> shift;
|
||||
for (k = 0; k < len; ++k) {
|
||||
pages[i++] = cpu_to_be64(sg_dma_address(
|
||||
&chunk->page_list[j]) +
|
||||
region->page_size * k);
|
||||
mhp->umem->page_size * k);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,9 +636,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
mhp->attr.pdid = php->pdid;
|
||||
mhp->attr.zbva = 0;
|
||||
mhp->attr.perms = iwch_ib_to_tpt_access(acc);
|
||||
mhp->attr.va_fbo = region->virt_base;
|
||||
mhp->attr.va_fbo = virt;
|
||||
mhp->attr.page_size = shift - 12;
|
||||
mhp->attr.len = (u32) region->length;
|
||||
mhp->attr.len = (u32) length;
|
||||
mhp->attr.pbl_size = i;
|
||||
err = iwch_register_mem(rhp, php, mhp, shift, pages);
|
||||
kfree(pages);
|
||||
@@ -650,6 +661,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
return &mhp->ibmr;
|
||||
|
||||
err:
|
||||
ib_umem_release(mhp->umem);
|
||||
kfree(mhp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
@@ -73,6 +73,7 @@ struct tpt_attributes {
|
||||
|
||||
struct iwch_mr {
|
||||
struct ib_mr ibmr;
|
||||
struct ib_umem *umem;
|
||||
struct iwch_dev *rhp;
|
||||
u64 kva;
|
||||
struct tpt_attributes attr;
|
||||
|
@@ -176,6 +176,7 @@ struct ehca_mr {
|
||||
struct ib_mr ib_mr; /* must always be first in ehca_mr */
|
||||
struct ib_fmr ib_fmr; /* must always be first in ehca_mr */
|
||||
} ib;
|
||||
struct ib_umem *umem;
|
||||
spinlock_t mrlock;
|
||||
|
||||
enum ehca_mr_flag flags;
|
||||
|
@@ -78,8 +78,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
|
||||
int num_phys_buf,
|
||||
int mr_access_flags, u64 *iova_start);
|
||||
|
||||
struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
|
||||
struct ib_umem *region,
|
||||
struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
|
||||
int mr_access_flags, struct ib_udata *udata);
|
||||
|
||||
int ehca_rereg_phys_mr(struct ib_mr *mr,
|
||||
|
@@ -39,6 +39,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <rdma/ib_umem.h>
|
||||
|
||||
#include <asm/current.h>
|
||||
|
||||
#include "ehca_iverbs.h"
|
||||
@@ -238,10 +240,8 @@ reg_phys_mr_exit0:
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
|
||||
struct ib_umem *region,
|
||||
int mr_access_flags,
|
||||
struct ib_udata *udata)
|
||||
struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
|
||||
int mr_access_flags, struct ib_udata *udata)
|
||||
{
|
||||
struct ib_mr *ib_mr;
|
||||
struct ehca_mr *e_mr;
|
||||
@@ -257,11 +257,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
|
||||
ehca_gen_err("bad pd=%p", pd);
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
if (!region) {
|
||||
ehca_err(pd->device, "bad input values: region=%p", region);
|
||||
ib_mr = ERR_PTR(-EINVAL);
|
||||
goto reg_user_mr_exit0;
|
||||
}
|
||||
|
||||
if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
|
||||
!(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
|
||||
((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
|
||||
@@ -275,17 +271,10 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
|
||||
ib_mr = ERR_PTR(-EINVAL);
|
||||
goto reg_user_mr_exit0;
|
||||
}
|
||||
if (region->page_size != PAGE_SIZE) {
|
||||
ehca_err(pd->device, "page size not supported, "
|
||||
"region->page_size=%x", region->page_size);
|
||||
ib_mr = ERR_PTR(-EINVAL);
|
||||
goto reg_user_mr_exit0;
|
||||
}
|
||||
|
||||
if ((region->length == 0) ||
|
||||
((region->virt_base + region->length) < region->virt_base)) {
|
||||
if (length == 0 || virt + length < virt) {
|
||||
ehca_err(pd->device, "bad input values: length=%lx "
|
||||
"virt_base=%lx", region->length, region->virt_base);
|
||||
"virt_base=%lx", length, virt);
|
||||
ib_mr = ERR_PTR(-EINVAL);
|
||||
goto reg_user_mr_exit0;
|
||||
}
|
||||
@@ -297,40 +286,55 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
|
||||
goto reg_user_mr_exit0;
|
||||
}
|
||||
|
||||
e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
|
||||
mr_access_flags);
|
||||
if (IS_ERR(e_mr->umem)) {
|
||||
ib_mr = (void *) e_mr->umem;
|
||||
goto reg_user_mr_exit1;
|
||||
}
|
||||
|
||||
if (e_mr->umem->page_size != PAGE_SIZE) {
|
||||
ehca_err(pd->device, "page size not supported, "
|
||||
"e_mr->umem->page_size=%x", e_mr->umem->page_size);
|
||||
ib_mr = ERR_PTR(-EINVAL);
|
||||
goto reg_user_mr_exit2;
|
||||
}
|
||||
|
||||
/* determine number of MR pages */
|
||||
num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length +
|
||||
PAGE_SIZE - 1) / PAGE_SIZE);
|
||||
num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length +
|
||||
EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
|
||||
num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
|
||||
PAGE_SIZE);
|
||||
num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
|
||||
EHCA_PAGESIZE);
|
||||
|
||||
/* register MR on HCA */
|
||||
pginfo.type = EHCA_MR_PGI_USER;
|
||||
pginfo.num_pages = num_pages_mr;
|
||||
pginfo.num_4k = num_pages_4k;
|
||||
pginfo.region = region;
|
||||
pginfo.next_4k = region->offset / EHCA_PAGESIZE;
|
||||
pginfo.region = e_mr->umem;
|
||||
pginfo.next_4k = e_mr->umem->offset / EHCA_PAGESIZE;
|
||||
pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
|
||||
(®ion->chunk_list),
|
||||
(&e_mr->umem->chunk_list),
|
||||
list);
|
||||
|
||||
ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base,
|
||||
region->length, mr_access_flags, e_pd, &pginfo,
|
||||
&e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
|
||||
ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
|
||||
&pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
|
||||
if (ret) {
|
||||
ib_mr = ERR_PTR(ret);
|
||||
goto reg_user_mr_exit1;
|
||||
goto reg_user_mr_exit2;
|
||||
}
|
||||
|
||||
/* successful registration of all pages */
|
||||
return &e_mr->ib.ib_mr;
|
||||
|
||||
reg_user_mr_exit2:
|
||||
ib_umem_release(e_mr->umem);
|
||||
reg_user_mr_exit1:
|
||||
ehca_mr_delete(e_mr);
|
||||
reg_user_mr_exit0:
|
||||
if (IS_ERR(ib_mr))
|
||||
ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x"
|
||||
ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x"
|
||||
" udata=%p",
|
||||
PTR_ERR(ib_mr), pd, region, mr_access_flags, udata);
|
||||
PTR_ERR(ib_mr), pd, mr_access_flags, udata);
|
||||
return ib_mr;
|
||||
} /* end ehca_reg_user_mr() */
|
||||
|
||||
@@ -596,6 +600,9 @@ int ehca_dereg_mr(struct ib_mr *mr)
|
||||
goto dereg_mr_exit0;
|
||||
}
|
||||
|
||||
if (e_mr->umem)
|
||||
ib_umem_release(e_mr->umem);
|
||||
|
||||
/* successful deregistration */
|
||||
ehca_mr_delete(e_mr);
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <rdma/ib_umem.h>
|
||||
#include <rdma/ib_pack.h>
|
||||
#include <rdma/ib_smi.h>
|
||||
|
||||
@@ -147,6 +148,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
|
||||
mr->mr.offset = 0;
|
||||
mr->mr.access_flags = acc;
|
||||
mr->mr.max_segs = num_phys_buf;
|
||||
mr->umem = NULL;
|
||||
|
||||
m = 0;
|
||||
n = 0;
|
||||
@@ -170,46 +172,56 @@ bail:
|
||||
/**
|
||||
* ipath_reg_user_mr - register a userspace memory region
|
||||
* @pd: protection domain for this memory region
|
||||
* @region: the user memory region
|
||||
* @start: starting userspace address
|
||||
* @length: length of region to register
|
||||
* @virt_addr: virtual address to use (from HCA's point of view)
|
||||
* @mr_access_flags: access flags for this memory region
|
||||
* @udata: unused by the InfiniPath driver
|
||||
*
|
||||
* Returns the memory region on success, otherwise returns an errno.
|
||||
*/
|
||||
struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int mr_access_flags, struct ib_udata *udata)
|
||||
struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt_addr, int mr_access_flags,
|
||||
struct ib_udata *udata)
|
||||
{
|
||||
struct ipath_mr *mr;
|
||||
struct ib_umem *umem;
|
||||
struct ib_umem_chunk *chunk;
|
||||
int n, m, i;
|
||||
struct ib_mr *ret;
|
||||
|
||||
if (region->length == 0) {
|
||||
if (length == 0) {
|
||||
ret = ERR_PTR(-EINVAL);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags);
|
||||
if (IS_ERR(umem))
|
||||
return (void *) umem;
|
||||
|
||||
n = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &umem->chunk_list, list)
|
||||
n += chunk->nents;
|
||||
|
||||
mr = alloc_mr(n, &to_idev(pd->device)->lk_table);
|
||||
if (!mr) {
|
||||
ret = ERR_PTR(-ENOMEM);
|
||||
ib_umem_release(umem);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
mr->mr.pd = pd;
|
||||
mr->mr.user_base = region->user_base;
|
||||
mr->mr.iova = region->virt_base;
|
||||
mr->mr.length = region->length;
|
||||
mr->mr.offset = region->offset;
|
||||
mr->mr.user_base = start;
|
||||
mr->mr.iova = virt_addr;
|
||||
mr->mr.length = length;
|
||||
mr->mr.offset = umem->offset;
|
||||
mr->mr.access_flags = mr_access_flags;
|
||||
mr->mr.max_segs = n;
|
||||
mr->umem = umem;
|
||||
|
||||
m = 0;
|
||||
n = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list) {
|
||||
list_for_each_entry(chunk, &umem->chunk_list, list) {
|
||||
for (i = 0; i < chunk->nents; i++) {
|
||||
void *vaddr;
|
||||
|
||||
@@ -219,7 +231,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
goto bail;
|
||||
}
|
||||
mr->mr.map[m]->segs[n].vaddr = vaddr;
|
||||
mr->mr.map[m]->segs[n].length = region->page_size;
|
||||
mr->mr.map[m]->segs[n].length = umem->page_size;
|
||||
n++;
|
||||
if (n == IPATH_SEGSZ) {
|
||||
m++;
|
||||
@@ -253,6 +265,10 @@ int ipath_dereg_mr(struct ib_mr *ibmr)
|
||||
i--;
|
||||
kfree(mr->mr.map[i]);
|
||||
}
|
||||
|
||||
if (mr->umem)
|
||||
ib_umem_release(mr->umem);
|
||||
|
||||
kfree(mr);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -251,6 +251,7 @@ struct ipath_sge {
|
||||
/* Memory region */
|
||||
struct ipath_mr {
|
||||
struct ib_mr ibmr;
|
||||
struct ib_umem *umem;
|
||||
struct ipath_mregion mr; /* must be last */
|
||||
};
|
||||
|
||||
@@ -751,8 +752,8 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
|
||||
struct ib_phys_buf *buffer_list,
|
||||
int num_phys_buf, int acc, u64 *iova_start);
|
||||
|
||||
struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int mr_access_flags,
|
||||
struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt_addr, int mr_access_flags,
|
||||
struct ib_udata *udata);
|
||||
|
||||
int ipath_dereg_mr(struct ib_mr *ibmr);
|
||||
|
@@ -37,6 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <rdma/ib_smi.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
#include <rdma/ib_user_verbs.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
@@ -908,6 +909,8 @@ static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
mr->umem = NULL;
|
||||
|
||||
return &mr->ibmr;
|
||||
}
|
||||
|
||||
@@ -1003,11 +1006,13 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
|
||||
}
|
||||
|
||||
kfree(page_list);
|
||||
mr->umem = NULL;
|
||||
|
||||
return &mr->ibmr;
|
||||
}
|
||||
|
||||
static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int acc, struct ib_udata *udata)
|
||||
static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt, int acc, struct ib_udata *udata)
|
||||
{
|
||||
struct mthca_dev *dev = to_mdev(pd->device);
|
||||
struct ib_umem_chunk *chunk;
|
||||
@@ -1018,20 +1023,26 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
int err = 0;
|
||||
int write_mtt_size;
|
||||
|
||||
shift = ffs(region->page_size) - 1;
|
||||
|
||||
mr = kmalloc(sizeof *mr, GFP_KERNEL);
|
||||
if (!mr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
|
||||
if (IS_ERR(mr->umem)) {
|
||||
err = PTR_ERR(mr->umem);
|
||||
goto err;
|
||||
}
|
||||
|
||||
shift = ffs(mr->umem->page_size) - 1;
|
||||
|
||||
n = 0;
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &mr->umem->chunk_list, list)
|
||||
n += chunk->nents;
|
||||
|
||||
mr->mtt = mthca_alloc_mtt(dev, n);
|
||||
if (IS_ERR(mr->mtt)) {
|
||||
err = PTR_ERR(mr->mtt);
|
||||
goto err;
|
||||
goto err_umem;
|
||||
}
|
||||
|
||||
pages = (u64 *) __get_free_page(GFP_KERNEL);
|
||||
@@ -1044,12 +1055,12 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
|
||||
|
||||
write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
|
||||
|
||||
list_for_each_entry(chunk, ®ion->chunk_list, list)
|
||||
list_for_each_entry(chunk, &mr->umem->chunk_list, list)
|
||||
for (j = 0; j < chunk->nmap; ++j) {
|
||||
len = sg_dma_len(&chunk->page_list[j]) >> shift;
|
||||
for (k = 0; k < len; ++k) {
|
||||
pages[i++] = sg_dma_address(&chunk->page_list[j]) +
|
||||
region->page_size * k;
|
||||
mr->umem->page_size * k;
|
||||
/*
|
||||
* Be friendly to write_mtt and pass it chunks
|
||||
* of appropriate size.
|
||||
@@ -1071,8 +1082,8 @@ mtt_done:
|
||||
if (err)
|
||||
goto err_mtt;
|
||||
|
||||
err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base,
|
||||
region->length, convert_access(acc), mr);
|
||||
err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length,
|
||||
convert_access(acc), mr);
|
||||
|
||||
if (err)
|
||||
goto err_mtt;
|
||||
@@ -1082,6 +1093,9 @@ mtt_done:
|
||||
err_mtt:
|
||||
mthca_free_mtt(dev, mr->mtt);
|
||||
|
||||
err_umem:
|
||||
ib_umem_release(mr->umem);
|
||||
|
||||
err:
|
||||
kfree(mr);
|
||||
return ERR_PTR(err);
|
||||
@@ -1090,8 +1104,12 @@ err:
|
||||
static int mthca_dereg_mr(struct ib_mr *mr)
|
||||
{
|
||||
struct mthca_mr *mmr = to_mmr(mr);
|
||||
|
||||
mthca_free_mr(to_mdev(mr->device), mmr);
|
||||
if (mmr->umem)
|
||||
ib_umem_release(mmr->umem);
|
||||
kfree(mmr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -73,6 +73,7 @@ struct mthca_mtt;
|
||||
|
||||
struct mthca_mr {
|
||||
struct ib_mr ibmr;
|
||||
struct ib_umem *umem;
|
||||
struct mthca_mtt *mtt;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user