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/core/uverbs_cmd.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/core/uverbs_cmd.c')
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 60 |
1 files changed, 20 insertions, 40 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index bab66769be1..01d70084aeb 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2005 Topspin Communications. All rights reserved. |
3 | * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. |
4 | * Copyright (c) 2005 PathScale, Inc. All rights reserved. | 4 | * Copyright (c) 2005 PathScale, Inc. All rights reserved. |
5 | * Copyright (c) 2006 Mellanox Technologies. All rights reserved. | 5 | * Copyright (c) 2006 Mellanox Technologies. All rights reserved. |
6 | * | 6 | * |
@@ -295,6 +295,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | |||
295 | INIT_LIST_HEAD(&ucontext->qp_list); | 295 | INIT_LIST_HEAD(&ucontext->qp_list); |
296 | INIT_LIST_HEAD(&ucontext->srq_list); | 296 | INIT_LIST_HEAD(&ucontext->srq_list); |
297 | INIT_LIST_HEAD(&ucontext->ah_list); | 297 | INIT_LIST_HEAD(&ucontext->ah_list); |
298 | ucontext->closing = 0; | ||
298 | 299 | ||
299 | resp.num_comp_vectors = file->device->num_comp_vectors; | 300 | resp.num_comp_vectors = file->device->num_comp_vectors; |
300 | 301 | ||
@@ -573,7 +574,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
573 | struct ib_uverbs_reg_mr cmd; | 574 | struct ib_uverbs_reg_mr cmd; |
574 | struct ib_uverbs_reg_mr_resp resp; | 575 | struct ib_uverbs_reg_mr_resp resp; |
575 | struct ib_udata udata; | 576 | struct ib_udata udata; |
576 | struct ib_umem_object *obj; | 577 | struct ib_uobject *uobj; |
577 | struct ib_pd *pd; | 578 | struct ib_pd *pd; |
578 | struct ib_mr *mr; | 579 | struct ib_mr *mr; |
579 | int ret; | 580 | int ret; |
@@ -599,35 +600,21 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
599 | !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) | 600 | !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) |
600 | return -EINVAL; | 601 | return -EINVAL; |
601 | 602 | ||
602 | obj = kmalloc(sizeof *obj, GFP_KERNEL); | 603 | uobj = kmalloc(sizeof *uobj, GFP_KERNEL); |
603 | if (!obj) | 604 | if (!uobj) |
604 | return -ENOMEM; | 605 | return -ENOMEM; |
605 | 606 | ||
606 | init_uobj(&obj->uobject, 0, file->ucontext, &mr_lock_key); | 607 | init_uobj(uobj, 0, file->ucontext, &mr_lock_key); |
607 | down_write(&obj->uobject.mutex); | 608 | down_write(&uobj->mutex); |
608 | |||
609 | /* | ||
610 | * We ask for writable memory if any access flags other than | ||
611 | * "remote read" are set. "Local write" and "remote write" | ||
612 | * obviously require write access. "Remote atomic" can do | ||
613 | * things like fetch and add, which will modify memory, and | ||
614 | * "MW bind" can change permissions by binding a window. | ||
615 | */ | ||
616 | ret = ib_umem_get(file->device->ib_dev, &obj->umem, | ||
617 | (void *) (unsigned long) cmd.start, cmd.length, | ||
618 | !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ)); | ||
619 | if (ret) | ||
620 | goto err_free; | ||
621 | |||
622 | obj->umem.virt_base = cmd.hca_va; | ||
623 | 609 | ||
624 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); | 610 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); |
625 | if (!pd) { | 611 | if (!pd) { |
626 | ret = -EINVAL; | 612 | ret = -EINVAL; |
627 | goto err_release; | 613 | goto err_free; |
628 | } | 614 | } |
629 | 615 | ||
630 | mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); | 616 | mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va, |
617 | cmd.access_flags, &udata); | ||
631 | if (IS_ERR(mr)) { | 618 | if (IS_ERR(mr)) { |
632 | ret = PTR_ERR(mr); | 619 | ret = PTR_ERR(mr); |
633 | goto err_put; | 620 | goto err_put; |
@@ -635,19 +622,19 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
635 | 622 | ||
636 | mr->device = pd->device; | 623 | mr->device = pd->device; |
637 | mr->pd = pd; | 624 | mr->pd = pd; |
638 | mr->uobject = &obj->uobject; | 625 | mr->uobject = uobj; |
639 | atomic_inc(&pd->usecnt); | 626 | atomic_inc(&pd->usecnt); |
640 | atomic_set(&mr->usecnt, 0); | 627 | atomic_set(&mr->usecnt, 0); |
641 | 628 | ||
642 | obj->uobject.object = mr; | 629 | uobj->object = mr; |
643 | ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uobject); | 630 | ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj); |
644 | if (ret) | 631 | if (ret) |
645 | goto err_unreg; | 632 | goto err_unreg; |
646 | 633 | ||
647 | memset(&resp, 0, sizeof resp); | 634 | memset(&resp, 0, sizeof resp); |
648 | resp.lkey = mr->lkey; | 635 | resp.lkey = mr->lkey; |
649 | resp.rkey = mr->rkey; | 636 | resp.rkey = mr->rkey; |
650 | resp.mr_handle = obj->uobject.id; | 637 | resp.mr_handle = uobj->id; |
651 | 638 | ||
652 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 639 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
653 | &resp, sizeof resp)) { | 640 | &resp, sizeof resp)) { |
@@ -658,17 +645,17 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
658 | put_pd_read(pd); | 645 | put_pd_read(pd); |
659 | 646 | ||
660 | mutex_lock(&file->mutex); | 647 | mutex_lock(&file->mutex); |
661 | list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); | 648 | list_add_tail(&uobj->list, &file->ucontext->mr_list); |
662 | mutex_unlock(&file->mutex); | 649 | mutex_unlock(&file->mutex); |
663 | 650 | ||
664 | obj->uobject.live = 1; | 651 | uobj->live = 1; |
665 | 652 | ||
666 | up_write(&obj->uobject.mutex); | 653 | up_write(&uobj->mutex); |
667 | 654 | ||
668 | return in_len; | 655 | return in_len; |
669 | 656 | ||
670 | err_copy: | 657 | err_copy: |
671 | idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uobject); | 658 | idr_remove_uobj(&ib_uverbs_mr_idr, uobj); |
672 | 659 | ||
673 | err_unreg: | 660 | err_unreg: |
674 | ib_dereg_mr(mr); | 661 | ib_dereg_mr(mr); |
@@ -676,11 +663,8 @@ err_unreg: | |||
676 | err_put: | 663 | err_put: |
677 | put_pd_read(pd); | 664 | put_pd_read(pd); |
678 | 665 | ||
679 | err_release: | ||
680 | ib_umem_release(file->device->ib_dev, &obj->umem); | ||
681 | |||
682 | err_free: | 666 | err_free: |
683 | put_uobj_write(&obj->uobject); | 667 | put_uobj_write(uobj); |
684 | return ret; | 668 | return ret; |
685 | } | 669 | } |
686 | 670 | ||
@@ -691,7 +675,6 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
691 | struct ib_uverbs_dereg_mr cmd; | 675 | struct ib_uverbs_dereg_mr cmd; |
692 | struct ib_mr *mr; | 676 | struct ib_mr *mr; |
693 | struct ib_uobject *uobj; | 677 | struct ib_uobject *uobj; |
694 | struct ib_umem_object *memobj; | ||
695 | int ret = -EINVAL; | 678 | int ret = -EINVAL; |
696 | 679 | ||
697 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 680 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
@@ -701,8 +684,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
701 | if (!uobj) | 684 | if (!uobj) |
702 | return -EINVAL; | 685 | return -EINVAL; |
703 | 686 | ||
704 | memobj = container_of(uobj, struct ib_umem_object, uobject); | 687 | mr = uobj->object; |
705 | mr = uobj->object; | ||
706 | 688 | ||
707 | ret = ib_dereg_mr(mr); | 689 | ret = ib_dereg_mr(mr); |
708 | if (!ret) | 690 | if (!ret) |
@@ -719,8 +701,6 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
719 | list_del(&uobj->list); | 701 | list_del(&uobj->list); |
720 | mutex_unlock(&file->mutex); | 702 | mutex_unlock(&file->mutex); |
721 | 703 | ||
722 | ib_umem_release(file->device->ib_dev, &memobj->umem); | ||
723 | |||
724 | put_uobj(uobj); | 704 | put_uobj(uobj); |
725 | 705 | ||
726 | return in_len; | 706 | return in_len; |