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 | |
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')
-rw-r--r-- | drivers/infiniband/hw/amso1100/c2_provider.c | 42 | ||||
-rw-r--r-- | drivers/infiniband/hw/amso1100/c2_provider.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_provider.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_provider.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_classes.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_iverbs.h | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_mrmw.c | 69 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mr.c | 38 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.h | 5 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_provider.c | 38 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_provider.h | 1 |
11 files changed, 148 insertions, 79 deletions
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 109166223c09..997cf1530762 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <asm/byteorder.h> | 56 | #include <asm/byteorder.h> |
57 | 57 | ||
58 | #include <rdma/ib_smi.h> | 58 | #include <rdma/ib_smi.h> |
59 | #include <rdma/ib_umem.h> | ||
59 | #include <rdma/ib_user_verbs.h> | 60 | #include <rdma/ib_user_verbs.h> |
60 | #include "c2.h" | 61 | #include "c2.h" |
61 | #include "c2_provider.h" | 62 | #include "c2_provider.h" |
@@ -396,6 +397,7 @@ static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd, | |||
396 | } | 397 | } |
397 | 398 | ||
398 | mr->pd = to_c2pd(ib_pd); | 399 | mr->pd = to_c2pd(ib_pd); |
400 | mr->umem = NULL; | ||
399 | pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, " | 401 | pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, " |
400 | "*iova_start %llx, first pa %llx, last pa %llx\n", | 402 | "*iova_start %llx, first pa %llx, last pa %llx\n", |
401 | __FUNCTION__, page_shift, pbl_depth, total_len, | 403 | __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) | |||
428 | return c2_reg_phys_mr(pd, &bl, 1, acc, &kva); | 430 | return c2_reg_phys_mr(pd, &bl, 1, acc, &kva); |
429 | } | 431 | } |
430 | 432 | ||
431 | static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 433 | static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
432 | int acc, struct ib_udata *udata) | 434 | u64 virt, int acc, struct ib_udata *udata) |
433 | { | 435 | { |
434 | u64 *pages; | 436 | u64 *pages; |
435 | u64 kva = 0; | 437 | u64 kva = 0; |
@@ -441,15 +443,23 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
441 | struct c2_mr *c2mr; | 443 | struct c2_mr *c2mr; |
442 | 444 | ||
443 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | 445 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); |
444 | shift = ffs(region->page_size) - 1; | ||
445 | 446 | ||
446 | c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL); | 447 | c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL); |
447 | if (!c2mr) | 448 | if (!c2mr) |
448 | return ERR_PTR(-ENOMEM); | 449 | return ERR_PTR(-ENOMEM); |
449 | c2mr->pd = c2pd; | 450 | c2mr->pd = c2pd; |
450 | 451 | ||
452 | c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); | ||
453 | if (IS_ERR(c2mr->umem)) { | ||
454 | err = PTR_ERR(c2mr->umem); | ||
455 | kfree(c2mr); | ||
456 | return ERR_PTR(err); | ||
457 | } | ||
458 | |||
459 | shift = ffs(c2mr->umem->page_size) - 1; | ||
460 | |||
451 | n = 0; | 461 | n = 0; |
452 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 462 | list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) |
453 | n += chunk->nents; | 463 | n += chunk->nents; |
454 | 464 | ||
455 | pages = kmalloc(n * sizeof(u64), GFP_KERNEL); | 465 | 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, | |||
459 | } | 469 | } |
460 | 470 | ||
461 | i = 0; | 471 | i = 0; |
462 | list_for_each_entry(chunk, ®ion->chunk_list, list) { | 472 | list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) { |
463 | for (j = 0; j < chunk->nmap; ++j) { | 473 | for (j = 0; j < chunk->nmap; ++j) { |
464 | len = sg_dma_len(&chunk->page_list[j]) >> shift; | 474 | len = sg_dma_len(&chunk->page_list[j]) >> shift; |
465 | for (k = 0; k < len; ++k) { | 475 | for (k = 0; k < len; ++k) { |
466 | pages[i++] = | 476 | pages[i++] = |
467 | sg_dma_address(&chunk->page_list[j]) + | 477 | sg_dma_address(&chunk->page_list[j]) + |
468 | (region->page_size * k); | 478 | (c2mr->umem->page_size * k); |
469 | } | 479 | } |
470 | } | 480 | } |
471 | } | 481 | } |
472 | 482 | ||
473 | kva = (u64)region->virt_base; | 483 | kva = virt; |
474 | err = c2_nsmr_register_phys_kern(to_c2dev(pd->device), | 484 | err = c2_nsmr_register_phys_kern(to_c2dev(pd->device), |
475 | pages, | 485 | pages, |
476 | region->page_size, | 486 | c2mr->umem->page_size, |
477 | i, | 487 | i, |
478 | region->length, | 488 | length, |
479 | region->offset, | 489 | c2mr->umem->offset, |
480 | &kva, | 490 | &kva, |
481 | c2_convert_access(acc), | 491 | c2_convert_access(acc), |
482 | c2mr); | 492 | c2mr); |
483 | kfree(pages); | 493 | kfree(pages); |
484 | if (err) { | 494 | if (err) |
485 | kfree(c2mr); | 495 | goto err; |
486 | return ERR_PTR(err); | ||
487 | } | ||
488 | return &c2mr->ibmr; | 496 | return &c2mr->ibmr; |
489 | 497 | ||
490 | err: | 498 | err: |
499 | ib_umem_release(c2mr->umem); | ||
491 | kfree(c2mr); | 500 | kfree(c2mr); |
492 | return ERR_PTR(err); | 501 | return ERR_PTR(err); |
493 | } | 502 | } |
@@ -502,8 +511,11 @@ static int c2_dereg_mr(struct ib_mr *ib_mr) | |||
502 | err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey); | 511 | err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey); |
503 | if (err) | 512 | if (err) |
504 | pr_debug("c2_stag_dealloc failed: %d\n", err); | 513 | pr_debug("c2_stag_dealloc failed: %d\n", err); |
505 | else | 514 | else { |
515 | if (mr->umem) | ||
516 | ib_umem_release(mr->umem); | ||
506 | kfree(mr); | 517 | kfree(mr); |
518 | } | ||
507 | 519 | ||
508 | return err; | 520 | return err; |
509 | } | 521 | } |
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/infiniband/hw/amso1100/c2_provider.h index fc906223220f..1076df2ee96a 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.h +++ b/drivers/infiniband/hw/amso1100/c2_provider.h | |||
@@ -73,6 +73,7 @@ struct c2_pd { | |||
73 | struct c2_mr { | 73 | struct c2_mr { |
74 | struct ib_mr ibmr; | 74 | struct ib_mr ibmr; |
75 | struct c2_pd *pd; | 75 | struct c2_pd *pd; |
76 | struct ib_umem *umem; | ||
76 | }; | 77 | }; |
77 | 78 | ||
78 | struct c2_av; | 79 | struct c2_av; |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index a891493fd340..e7c2c3948037 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <rdma/iw_cm.h> | 47 | #include <rdma/iw_cm.h> |
48 | #include <rdma/ib_verbs.h> | 48 | #include <rdma/ib_verbs.h> |
49 | #include <rdma/ib_smi.h> | 49 | #include <rdma/ib_smi.h> |
50 | #include <rdma/ib_umem.h> | ||
50 | #include <rdma/ib_user_verbs.h> | 51 | #include <rdma/ib_user_verbs.h> |
51 | 52 | ||
52 | #include "cxio_hal.h" | 53 | #include "cxio_hal.h" |
@@ -443,6 +444,8 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr) | |||
443 | remove_handle(rhp, &rhp->mmidr, mmid); | 444 | remove_handle(rhp, &rhp->mmidr, mmid); |
444 | if (mhp->kva) | 445 | if (mhp->kva) |
445 | kfree((void *) (unsigned long) mhp->kva); | 446 | kfree((void *) (unsigned long) mhp->kva); |
447 | if (mhp->umem) | ||
448 | ib_umem_release(mhp->umem); | ||
446 | PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp); | 449 | PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp); |
447 | kfree(mhp); | 450 | kfree(mhp); |
448 | return 0; | 451 | return 0; |
@@ -577,8 +580,8 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr, | |||
577 | } | 580 | } |
578 | 581 | ||
579 | 582 | ||
580 | static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 583 | static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
581 | int acc, struct ib_udata *udata) | 584 | u64 virt, int acc, struct ib_udata *udata) |
582 | { | 585 | { |
583 | __be64 *pages; | 586 | __be64 *pages; |
584 | int shift, n, len; | 587 | int shift, n, len; |
@@ -591,7 +594,6 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
591 | struct iwch_reg_user_mr_resp uresp; | 594 | struct iwch_reg_user_mr_resp uresp; |
592 | 595 | ||
593 | PDBG("%s ib_pd %p\n", __FUNCTION__, pd); | 596 | PDBG("%s ib_pd %p\n", __FUNCTION__, pd); |
594 | shift = ffs(region->page_size) - 1; | ||
595 | 597 | ||
596 | php = to_iwch_pd(pd); | 598 | php = to_iwch_pd(pd); |
597 | rhp = php->rhp; | 599 | rhp = php->rhp; |
@@ -599,8 +601,17 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
599 | if (!mhp) | 601 | if (!mhp) |
600 | return ERR_PTR(-ENOMEM); | 602 | return ERR_PTR(-ENOMEM); |
601 | 603 | ||
604 | mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc); | ||
605 | if (IS_ERR(mhp->umem)) { | ||
606 | err = PTR_ERR(mhp->umem); | ||
607 | kfree(mhp); | ||
608 | return ERR_PTR(err); | ||
609 | } | ||
610 | |||
611 | shift = ffs(mhp->umem->page_size) - 1; | ||
612 | |||
602 | n = 0; | 613 | n = 0; |
603 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 614 | list_for_each_entry(chunk, &mhp->umem->chunk_list, list) |
604 | n += chunk->nents; | 615 | n += chunk->nents; |
605 | 616 | ||
606 | pages = kmalloc(n * sizeof(u64), GFP_KERNEL); | 617 | 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, | |||
611 | 622 | ||
612 | i = n = 0; | 623 | i = n = 0; |
613 | 624 | ||
614 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 625 | list_for_each_entry(chunk, &mhp->umem->chunk_list, list) |
615 | for (j = 0; j < chunk->nmap; ++j) { | 626 | for (j = 0; j < chunk->nmap; ++j) { |
616 | len = sg_dma_len(&chunk->page_list[j]) >> shift; | 627 | len = sg_dma_len(&chunk->page_list[j]) >> shift; |
617 | for (k = 0; k < len; ++k) { | 628 | for (k = 0; k < len; ++k) { |
618 | pages[i++] = cpu_to_be64(sg_dma_address( | 629 | pages[i++] = cpu_to_be64(sg_dma_address( |
619 | &chunk->page_list[j]) + | 630 | &chunk->page_list[j]) + |
620 | region->page_size * k); | 631 | mhp->umem->page_size * k); |
621 | } | 632 | } |
622 | } | 633 | } |
623 | 634 | ||
@@ -625,9 +636,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
625 | mhp->attr.pdid = php->pdid; | 636 | mhp->attr.pdid = php->pdid; |
626 | mhp->attr.zbva = 0; | 637 | mhp->attr.zbva = 0; |
627 | mhp->attr.perms = iwch_ib_to_tpt_access(acc); | 638 | mhp->attr.perms = iwch_ib_to_tpt_access(acc); |
628 | mhp->attr.va_fbo = region->virt_base; | 639 | mhp->attr.va_fbo = virt; |
629 | mhp->attr.page_size = shift - 12; | 640 | mhp->attr.page_size = shift - 12; |
630 | mhp->attr.len = (u32) region->length; | 641 | mhp->attr.len = (u32) length; |
631 | mhp->attr.pbl_size = i; | 642 | mhp->attr.pbl_size = i; |
632 | err = iwch_register_mem(rhp, php, mhp, shift, pages); | 643 | err = iwch_register_mem(rhp, php, mhp, shift, pages); |
633 | kfree(pages); | 644 | kfree(pages); |
@@ -650,6 +661,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
650 | return &mhp->ibmr; | 661 | return &mhp->ibmr; |
651 | 662 | ||
652 | err: | 663 | err: |
664 | ib_umem_release(mhp->umem); | ||
653 | kfree(mhp); | 665 | kfree(mhp); |
654 | return ERR_PTR(err); | 666 | return ERR_PTR(err); |
655 | } | 667 | } |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 93bcc56756bd..48833f3f3bd0 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h | |||
@@ -73,6 +73,7 @@ struct tpt_attributes { | |||
73 | 73 | ||
74 | struct iwch_mr { | 74 | struct iwch_mr { |
75 | struct ib_mr ibmr; | 75 | struct ib_mr ibmr; |
76 | struct ib_umem *umem; | ||
76 | struct iwch_dev *rhp; | 77 | struct iwch_dev *rhp; |
77 | u64 kva; | 78 | u64 kva; |
78 | struct tpt_attributes attr; | 79 | struct tpt_attributes attr; |
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 10fb8fbafa0c..f64d42b08674 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
@@ -176,6 +176,7 @@ struct ehca_mr { | |||
176 | struct ib_mr ib_mr; /* must always be first in ehca_mr */ | 176 | struct ib_mr ib_mr; /* must always be first in ehca_mr */ |
177 | struct ib_fmr ib_fmr; /* must always be first in ehca_mr */ | 177 | struct ib_fmr ib_fmr; /* must always be first in ehca_mr */ |
178 | } ib; | 178 | } ib; |
179 | struct ib_umem *umem; | ||
179 | spinlock_t mrlock; | 180 | spinlock_t mrlock; |
180 | 181 | ||
181 | enum ehca_mr_flag flags; | 182 | enum ehca_mr_flag flags; |
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index e14b029332c8..37e7fe0908cf 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h | |||
@@ -78,8 +78,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | |||
78 | int num_phys_buf, | 78 | int num_phys_buf, |
79 | int mr_access_flags, u64 *iova_start); | 79 | int mr_access_flags, u64 *iova_start); |
80 | 80 | ||
81 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | 81 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt, |
82 | struct ib_umem *region, | ||
83 | int mr_access_flags, struct ib_udata *udata); | 82 | int mr_access_flags, struct ib_udata *udata); |
84 | 83 | ||
85 | int ehca_rereg_phys_mr(struct ib_mr *mr, | 84 | int ehca_rereg_phys_mr(struct ib_mr *mr, |
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 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index 31e70732e369..bdeef8d4f279 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c | |||
@@ -31,6 +31,7 @@ | |||
31 | * SOFTWARE. | 31 | * SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <rdma/ib_umem.h> | ||
34 | #include <rdma/ib_pack.h> | 35 | #include <rdma/ib_pack.h> |
35 | #include <rdma/ib_smi.h> | 36 | #include <rdma/ib_smi.h> |
36 | 37 | ||
@@ -147,6 +148,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd, | |||
147 | mr->mr.offset = 0; | 148 | mr->mr.offset = 0; |
148 | mr->mr.access_flags = acc; | 149 | mr->mr.access_flags = acc; |
149 | mr->mr.max_segs = num_phys_buf; | 150 | mr->mr.max_segs = num_phys_buf; |
151 | mr->umem = NULL; | ||
150 | 152 | ||
151 | m = 0; | 153 | m = 0; |
152 | n = 0; | 154 | n = 0; |
@@ -170,46 +172,56 @@ bail: | |||
170 | /** | 172 | /** |
171 | * ipath_reg_user_mr - register a userspace memory region | 173 | * ipath_reg_user_mr - register a userspace memory region |
172 | * @pd: protection domain for this memory region | 174 | * @pd: protection domain for this memory region |
173 | * @region: the user memory region | 175 | * @start: starting userspace address |
176 | * @length: length of region to register | ||
177 | * @virt_addr: virtual address to use (from HCA's point of view) | ||
174 | * @mr_access_flags: access flags for this memory region | 178 | * @mr_access_flags: access flags for this memory region |
175 | * @udata: unused by the InfiniPath driver | 179 | * @udata: unused by the InfiniPath driver |
176 | * | 180 | * |
177 | * Returns the memory region on success, otherwise returns an errno. | 181 | * Returns the memory region on success, otherwise returns an errno. |
178 | */ | 182 | */ |
179 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 183 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
180 | int mr_access_flags, struct ib_udata *udata) | 184 | u64 virt_addr, int mr_access_flags, |
185 | struct ib_udata *udata) | ||
181 | { | 186 | { |
182 | struct ipath_mr *mr; | 187 | struct ipath_mr *mr; |
188 | struct ib_umem *umem; | ||
183 | struct ib_umem_chunk *chunk; | 189 | struct ib_umem_chunk *chunk; |
184 | int n, m, i; | 190 | int n, m, i; |
185 | struct ib_mr *ret; | 191 | struct ib_mr *ret; |
186 | 192 | ||
187 | if (region->length == 0) { | 193 | if (length == 0) { |
188 | ret = ERR_PTR(-EINVAL); | 194 | ret = ERR_PTR(-EINVAL); |
189 | goto bail; | 195 | goto bail; |
190 | } | 196 | } |
191 | 197 | ||
198 | umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags); | ||
199 | if (IS_ERR(umem)) | ||
200 | return (void *) umem; | ||
201 | |||
192 | n = 0; | 202 | n = 0; |
193 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 203 | list_for_each_entry(chunk, &umem->chunk_list, list) |
194 | n += chunk->nents; | 204 | n += chunk->nents; |
195 | 205 | ||
196 | mr = alloc_mr(n, &to_idev(pd->device)->lk_table); | 206 | mr = alloc_mr(n, &to_idev(pd->device)->lk_table); |
197 | if (!mr) { | 207 | if (!mr) { |
198 | ret = ERR_PTR(-ENOMEM); | 208 | ret = ERR_PTR(-ENOMEM); |
209 | ib_umem_release(umem); | ||
199 | goto bail; | 210 | goto bail; |
200 | } | 211 | } |
201 | 212 | ||
202 | mr->mr.pd = pd; | 213 | mr->mr.pd = pd; |
203 | mr->mr.user_base = region->user_base; | 214 | mr->mr.user_base = start; |
204 | mr->mr.iova = region->virt_base; | 215 | mr->mr.iova = virt_addr; |
205 | mr->mr.length = region->length; | 216 | mr->mr.length = length; |
206 | mr->mr.offset = region->offset; | 217 | mr->mr.offset = umem->offset; |
207 | mr->mr.access_flags = mr_access_flags; | 218 | mr->mr.access_flags = mr_access_flags; |
208 | mr->mr.max_segs = n; | 219 | mr->mr.max_segs = n; |
220 | mr->umem = umem; | ||
209 | 221 | ||
210 | m = 0; | 222 | m = 0; |
211 | n = 0; | 223 | n = 0; |
212 | list_for_each_entry(chunk, ®ion->chunk_list, list) { | 224 | list_for_each_entry(chunk, &umem->chunk_list, list) { |
213 | for (i = 0; i < chunk->nents; i++) { | 225 | for (i = 0; i < chunk->nents; i++) { |
214 | void *vaddr; | 226 | void *vaddr; |
215 | 227 | ||
@@ -219,7 +231,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | |||
219 | goto bail; | 231 | goto bail; |
220 | } | 232 | } |
221 | mr->mr.map[m]->segs[n].vaddr = vaddr; | 233 | mr->mr.map[m]->segs[n].vaddr = vaddr; |
222 | mr->mr.map[m]->segs[n].length = region->page_size; | 234 | mr->mr.map[m]->segs[n].length = umem->page_size; |
223 | n++; | 235 | n++; |
224 | if (n == IPATH_SEGSZ) { | 236 | if (n == IPATH_SEGSZ) { |
225 | m++; | 237 | m++; |
@@ -253,6 +265,10 @@ int ipath_dereg_mr(struct ib_mr *ibmr) | |||
253 | i--; | 265 | i--; |
254 | kfree(mr->mr.map[i]); | 266 | kfree(mr->mr.map[i]); |
255 | } | 267 | } |
268 | |||
269 | if (mr->umem) | ||
270 | ib_umem_release(mr->umem); | ||
271 | |||
256 | kfree(mr); | 272 | kfree(mr); |
257 | return 0; | 273 | return 0; |
258 | } | 274 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 7064fc222727..088b837ebea8 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h | |||
@@ -251,6 +251,7 @@ struct ipath_sge { | |||
251 | /* Memory region */ | 251 | /* Memory region */ |
252 | struct ipath_mr { | 252 | struct ipath_mr { |
253 | struct ib_mr ibmr; | 253 | struct ib_mr ibmr; |
254 | struct ib_umem *umem; | ||
254 | struct ipath_mregion mr; /* must be last */ | 255 | struct ipath_mregion mr; /* must be last */ |
255 | }; | 256 | }; |
256 | 257 | ||
@@ -751,8 +752,8 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd, | |||
751 | struct ib_phys_buf *buffer_list, | 752 | struct ib_phys_buf *buffer_list, |
752 | int num_phys_buf, int acc, u64 *iova_start); | 753 | int num_phys_buf, int acc, u64 *iova_start); |
753 | 754 | ||
754 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 755 | struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
755 | int mr_access_flags, | 756 | u64 virt_addr, int mr_access_flags, |
756 | struct ib_udata *udata); | 757 | struct ib_udata *udata); |
757 | 758 | ||
758 | int ipath_dereg_mr(struct ib_mr *ibmr); | 759 | int ipath_dereg_mr(struct ib_mr *ibmr); |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 1c05486c3c68..6bcde1cb9688 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
@@ -37,6 +37,7 @@ | |||
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <rdma/ib_smi.h> | 39 | #include <rdma/ib_smi.h> |
40 | #include <rdma/ib_umem.h> | ||
40 | #include <rdma/ib_user_verbs.h> | 41 | #include <rdma/ib_user_verbs.h> |
41 | #include <linux/mm.h> | 42 | #include <linux/mm.h> |
42 | 43 | ||
@@ -908,6 +909,8 @@ static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) | |||
908 | return ERR_PTR(err); | 909 | return ERR_PTR(err); |
909 | } | 910 | } |
910 | 911 | ||
912 | mr->umem = NULL; | ||
913 | |||
911 | return &mr->ibmr; | 914 | return &mr->ibmr; |
912 | } | 915 | } |
913 | 916 | ||
@@ -1003,11 +1006,13 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, | |||
1003 | } | 1006 | } |
1004 | 1007 | ||
1005 | kfree(page_list); | 1008 | kfree(page_list); |
1009 | mr->umem = NULL; | ||
1010 | |||
1006 | return &mr->ibmr; | 1011 | return &mr->ibmr; |
1007 | } | 1012 | } |
1008 | 1013 | ||
1009 | static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | 1014 | static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
1010 | int acc, struct ib_udata *udata) | 1015 | u64 virt, int acc, struct ib_udata *udata) |
1011 | { | 1016 | { |
1012 | struct mthca_dev *dev = to_mdev(pd->device); | 1017 | struct mthca_dev *dev = to_mdev(pd->device); |
1013 | struct ib_umem_chunk *chunk; | 1018 | 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, | |||
1018 | int err = 0; | 1023 | int err = 0; |
1019 | int write_mtt_size; | 1024 | int write_mtt_size; |
1020 | 1025 | ||
1021 | shift = ffs(region->page_size) - 1; | ||
1022 | |||
1023 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | 1026 | mr = kmalloc(sizeof *mr, GFP_KERNEL); |
1024 | if (!mr) | 1027 | if (!mr) |
1025 | return ERR_PTR(-ENOMEM); | 1028 | return ERR_PTR(-ENOMEM); |
1026 | 1029 | ||
1030 | mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); | ||
1031 | if (IS_ERR(mr->umem)) { | ||
1032 | err = PTR_ERR(mr->umem); | ||
1033 | goto err; | ||
1034 | } | ||
1035 | |||
1036 | shift = ffs(mr->umem->page_size) - 1; | ||
1037 | |||
1027 | n = 0; | 1038 | n = 0; |
1028 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 1039 | list_for_each_entry(chunk, &mr->umem->chunk_list, list) |
1029 | n += chunk->nents; | 1040 | n += chunk->nents; |
1030 | 1041 | ||
1031 | mr->mtt = mthca_alloc_mtt(dev, n); | 1042 | mr->mtt = mthca_alloc_mtt(dev, n); |
1032 | if (IS_ERR(mr->mtt)) { | 1043 | if (IS_ERR(mr->mtt)) { |
1033 | err = PTR_ERR(mr->mtt); | 1044 | err = PTR_ERR(mr->mtt); |
1034 | goto err; | 1045 | goto err_umem; |
1035 | } | 1046 | } |
1036 | 1047 | ||
1037 | pages = (u64 *) __get_free_page(GFP_KERNEL); | 1048 | 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, | |||
1044 | 1055 | ||
1045 | write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); | 1056 | write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); |
1046 | 1057 | ||
1047 | list_for_each_entry(chunk, ®ion->chunk_list, list) | 1058 | list_for_each_entry(chunk, &mr->umem->chunk_list, list) |
1048 | for (j = 0; j < chunk->nmap; ++j) { | 1059 | for (j = 0; j < chunk->nmap; ++j) { |
1049 | len = sg_dma_len(&chunk->page_list[j]) >> shift; | 1060 | len = sg_dma_len(&chunk->page_list[j]) >> shift; |
1050 | for (k = 0; k < len; ++k) { | 1061 | for (k = 0; k < len; ++k) { |
1051 | pages[i++] = sg_dma_address(&chunk->page_list[j]) + | 1062 | pages[i++] = sg_dma_address(&chunk->page_list[j]) + |
1052 | region->page_size * k; | 1063 | mr->umem->page_size * k; |
1053 | /* | 1064 | /* |
1054 | * Be friendly to write_mtt and pass it chunks | 1065 | * Be friendly to write_mtt and pass it chunks |
1055 | * of appropriate size. | 1066 | * of appropriate size. |
@@ -1071,8 +1082,8 @@ mtt_done: | |||
1071 | if (err) | 1082 | if (err) |
1072 | goto err_mtt; | 1083 | goto err_mtt; |
1073 | 1084 | ||
1074 | err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base, | 1085 | err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length, |
1075 | region->length, convert_access(acc), mr); | 1086 | convert_access(acc), mr); |
1076 | 1087 | ||
1077 | if (err) | 1088 | if (err) |
1078 | goto err_mtt; | 1089 | goto err_mtt; |
@@ -1082,6 +1093,9 @@ mtt_done: | |||
1082 | err_mtt: | 1093 | err_mtt: |
1083 | mthca_free_mtt(dev, mr->mtt); | 1094 | mthca_free_mtt(dev, mr->mtt); |
1084 | 1095 | ||
1096 | err_umem: | ||
1097 | ib_umem_release(mr->umem); | ||
1098 | |||
1085 | err: | 1099 | err: |
1086 | kfree(mr); | 1100 | kfree(mr); |
1087 | return ERR_PTR(err); | 1101 | return ERR_PTR(err); |
@@ -1090,8 +1104,12 @@ err: | |||
1090 | static int mthca_dereg_mr(struct ib_mr *mr) | 1104 | static int mthca_dereg_mr(struct ib_mr *mr) |
1091 | { | 1105 | { |
1092 | struct mthca_mr *mmr = to_mmr(mr); | 1106 | struct mthca_mr *mmr = to_mmr(mr); |
1107 | |||
1093 | mthca_free_mr(to_mdev(mr->device), mmr); | 1108 | mthca_free_mr(to_mdev(mr->device), mmr); |
1109 | if (mmr->umem) | ||
1110 | ib_umem_release(mmr->umem); | ||
1094 | kfree(mmr); | 1111 | kfree(mmr); |
1112 | |||
1095 | return 0; | 1113 | return 0; |
1096 | } | 1114 | } |
1097 | 1115 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 1d266ac2e094..262616c8ebb6 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h | |||
@@ -73,6 +73,7 @@ struct mthca_mtt; | |||
73 | 73 | ||
74 | struct mthca_mr { | 74 | struct mthca_mr { |
75 | struct ib_mr ibmr; | 75 | struct ib_mr ibmr; |
76 | struct ib_umem *umem; | ||
76 | struct mthca_mtt *mtt; | 77 | struct mthca_mtt *mtt; |
77 | }; | 78 | }; |
78 | 79 | ||