diff options
author | Roland Dreier <rolandd@cisco.com> | 2007-03-04 19:15:11 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-05-08 21:00:37 -0400 |
commit | f7c6a7b5d59980b076abbf2ceeb8735591290285 (patch) | |
tree | 29c35b47052bba87f031a4744d8ad12ff5187149 /drivers/infiniband/hw/ehca/ehca_mrmw.c | |
parent | 36f021b579d195cdc5fa6f3e2bab198b4bf70643 (diff) |
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>
Diffstat (limited to 'drivers/infiniband/hw/ehca/ehca_mrmw.c')
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_mrmw.c | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index d22ab563633f..84c5bb498563 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c | |||
@@ -39,6 +39,8 @@ | |||
39 | * POSSIBILITY OF SUCH DAMAGE. | 39 | * POSSIBILITY OF SUCH DAMAGE. |
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include <rdma/ib_umem.h> | ||
43 | |||
42 | #include <asm/current.h> | 44 | #include <asm/current.h> |
43 | 45 | ||
44 | #include "ehca_iverbs.h" | 46 | #include "ehca_iverbs.h" |
@@ -238,10 +240,8 @@ reg_phys_mr_exit0: | |||
238 | 240 | ||
239 | /*----------------------------------------------------------------------*/ | 241 | /*----------------------------------------------------------------------*/ |
240 | 242 | ||
241 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | 243 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt, |
242 | struct ib_umem *region, | 244 | int mr_access_flags, struct ib_udata *udata) |
243 | int mr_access_flags, | ||
244 | struct ib_udata *udata) | ||
245 | { | 245 | { |
246 | struct ib_mr *ib_mr; | 246 | struct ib_mr *ib_mr; |
247 | struct ehca_mr *e_mr; | 247 | struct ehca_mr *e_mr; |
@@ -257,11 +257,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | |||
257 | ehca_gen_err("bad pd=%p", pd); | 257 | ehca_gen_err("bad pd=%p", pd); |
258 | return ERR_PTR(-EFAULT); | 258 | return ERR_PTR(-EFAULT); |
259 | } | 259 | } |
260 | if (!region) { | 260 | |
261 | ehca_err(pd->device, "bad input values: region=%p", region); | ||
262 | ib_mr = ERR_PTR(-EINVAL); | ||
263 | goto reg_user_mr_exit0; | ||
264 | } | ||
265 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | 261 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && |
266 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || | 262 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || |
267 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && | 263 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && |
@@ -275,17 +271,10 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | |||
275 | ib_mr = ERR_PTR(-EINVAL); | 271 | ib_mr = ERR_PTR(-EINVAL); |
276 | goto reg_user_mr_exit0; | 272 | goto reg_user_mr_exit0; |
277 | } | 273 | } |
278 | if (region->page_size != PAGE_SIZE) { | ||
279 | ehca_err(pd->device, "page size not supported, " | ||
280 | "region->page_size=%x", region->page_size); | ||
281 | ib_mr = ERR_PTR(-EINVAL); | ||
282 | goto reg_user_mr_exit0; | ||
283 | } | ||
284 | 274 | ||
285 | if ((region->length == 0) || | 275 | if (length == 0 || virt + length < virt) { |
286 | ((region->virt_base + region->length) < region->virt_base)) { | ||
287 | ehca_err(pd->device, "bad input values: length=%lx " | 276 | ehca_err(pd->device, "bad input values: length=%lx " |
288 | "virt_base=%lx", region->length, region->virt_base); | 277 | "virt_base=%lx", length, virt); |
289 | ib_mr = ERR_PTR(-EINVAL); | 278 | ib_mr = ERR_PTR(-EINVAL); |
290 | goto reg_user_mr_exit0; | 279 | goto reg_user_mr_exit0; |
291 | } | 280 | } |
@@ -297,40 +286,55 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | |||
297 | goto reg_user_mr_exit0; | 286 | goto reg_user_mr_exit0; |
298 | } | 287 | } |
299 | 288 | ||
289 | e_mr->umem = ib_umem_get(pd->uobject->context, start, length, | ||
290 | mr_access_flags); | ||
291 | if (IS_ERR(e_mr->umem)) { | ||
292 | ib_mr = (void *) e_mr->umem; | ||
293 | goto reg_user_mr_exit1; | ||
294 | } | ||
295 | |||
296 | if (e_mr->umem->page_size != PAGE_SIZE) { | ||
297 | ehca_err(pd->device, "page size not supported, " | ||
298 | "e_mr->umem->page_size=%x", e_mr->umem->page_size); | ||
299 | ib_mr = ERR_PTR(-EINVAL); | ||
300 | goto reg_user_mr_exit2; | ||
301 | } | ||
302 | |||
300 | /* determine number of MR pages */ | 303 | /* determine number of MR pages */ |
301 | num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length + | 304 | num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) / |
302 | PAGE_SIZE - 1) / PAGE_SIZE); | 305 | PAGE_SIZE); |
303 | num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length + | 306 | num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) / |
304 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | 307 | EHCA_PAGESIZE); |
305 | 308 | ||
306 | /* register MR on HCA */ | 309 | /* register MR on HCA */ |
307 | pginfo.type = EHCA_MR_PGI_USER; | 310 | pginfo.type = EHCA_MR_PGI_USER; |
308 | pginfo.num_pages = num_pages_mr; | 311 | pginfo.num_pages = num_pages_mr; |
309 | pginfo.num_4k = num_pages_4k; | 312 | pginfo.num_4k = num_pages_4k; |
310 | pginfo.region = region; | 313 | pginfo.region = e_mr->umem; |
311 | pginfo.next_4k = region->offset / EHCA_PAGESIZE; | 314 | pginfo.next_4k = e_mr->umem->offset / EHCA_PAGESIZE; |
312 | pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk, | 315 | pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk, |
313 | (®ion->chunk_list), | 316 | (&e_mr->umem->chunk_list), |
314 | list); | 317 | list); |
315 | 318 | ||
316 | ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base, | 319 | ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd, |
317 | region->length, mr_access_flags, e_pd, &pginfo, | 320 | &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey); |
318 | &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey); | ||
319 | if (ret) { | 321 | if (ret) { |
320 | ib_mr = ERR_PTR(ret); | 322 | ib_mr = ERR_PTR(ret); |
321 | goto reg_user_mr_exit1; | 323 | goto reg_user_mr_exit2; |
322 | } | 324 | } |
323 | 325 | ||
324 | /* successful registration of all pages */ | 326 | /* successful registration of all pages */ |
325 | return &e_mr->ib.ib_mr; | 327 | return &e_mr->ib.ib_mr; |
326 | 328 | ||
329 | reg_user_mr_exit2: | ||
330 | ib_umem_release(e_mr->umem); | ||
327 | reg_user_mr_exit1: | 331 | reg_user_mr_exit1: |
328 | ehca_mr_delete(e_mr); | 332 | ehca_mr_delete(e_mr); |
329 | reg_user_mr_exit0: | 333 | reg_user_mr_exit0: |
330 | if (IS_ERR(ib_mr)) | 334 | if (IS_ERR(ib_mr)) |
331 | ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x" | 335 | ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x" |
332 | " udata=%p", | 336 | " udata=%p", |
333 | PTR_ERR(ib_mr), pd, region, mr_access_flags, udata); | 337 | PTR_ERR(ib_mr), pd, mr_access_flags, udata); |
334 | return ib_mr; | 338 | return ib_mr; |
335 | } /* end ehca_reg_user_mr() */ | 339 | } /* end ehca_reg_user_mr() */ |
336 | 340 | ||
@@ -596,6 +600,9 @@ int ehca_dereg_mr(struct ib_mr *mr) | |||
596 | goto dereg_mr_exit0; | 600 | goto dereg_mr_exit0; |
597 | } | 601 | } |
598 | 602 | ||
603 | if (e_mr->umem) | ||
604 | ib_umem_release(e_mr->umem); | ||
605 | |||
599 | /* successful deregistration */ | 606 | /* successful deregistration */ |
600 | ehca_mr_delete(e_mr); | 607 | ehca_mr_delete(e_mr); |
601 | 608 | ||