tree ba512b75aaef8bf0c89ab4f75b80c75af5ead60c
parent d41fcc6705eddd04f7218c985b6da35435ed73cc
author Roland Dreier <[EMAIL PROTECTED]> Fri, 19 Aug 2005 02:24:13 -0700
committer Roland Dreier <[EMAIL PROTECTED]> Sat, 27 Aug 2005 10:37:37 -0700

[PATCH] IB: userspace SRQ support

Add SRQ support to userspace verbs module.  This adds several commands
and associated structures, but it's OK to do this without bumping the
ABI version because the commands are added at the end of the list so
they don't change the existing numbering.  There are two cases to
worry about:

1. New kernel, old userspace.  This is OK because old userspace simply
   won't try to use the new SRQ commands.  None of the old commands are
   changed.

2. Old kernel, new userspace.  This works perfectly as long as
   userspace doesn't try to use SRQ commands.  If userspace tries to
   use SRQ commands, it will get EINVAL, which is perfectly
   reasonable: the kernel doesn't support SRQs, so we couldn't do any
   better.

Signed-off-by: Roland Dreier <[EMAIL PROTECTED]>

 drivers/infiniband/core/uverbs.h           |    5 
 drivers/infiniband/core/uverbs_cmd.c       |  182 ++++++++++++++++++++++++++++-
 drivers/infiniband/core/uverbs_main.c      |   20 +++
 drivers/infiniband/include/ib_user_verbs.h |   35 +++++
 4 files changed, 238 insertions(+), 4 deletions(-)

diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -99,10 +99,12 @@ extern struct idr ib_uverbs_mw_idr;
 extern struct idr ib_uverbs_ah_idr;
 extern struct idr ib_uverbs_cq_idr;
 extern struct idr ib_uverbs_qp_idr;
+extern struct idr ib_uverbs_srq_idr;
 
 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
 
 int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
                void *addr, size_t size, int write);
@@ -131,5 +133,8 @@ IB_UVERBS_DECLARE_CMD(modify_qp);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(attach_mcast);
 IB_UVERBS_DECLARE_CMD(detach_mcast);
+IB_UVERBS_DECLARE_CMD(create_srq);
+IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(destroy_srq);
 
 #endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c 
b/drivers/infiniband/core/uverbs_cmd.c
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -724,6 +724,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uv
        struct ib_uobject              *uobj;
        struct ib_pd                   *pd;
        struct ib_cq                   *scq, *rcq;
+       struct ib_srq                  *srq;
        struct ib_qp                   *qp;
        struct ib_qp_init_attr          attr;
        int ret;
@@ -747,10 +748,12 @@ ssize_t ib_uverbs_create_qp(struct ib_uv
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
        rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
+       srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL;
 
        if (!pd  || pd->uobject->context  != file->ucontext ||
            !scq || scq->uobject->context != file->ucontext ||
-           !rcq || rcq->uobject->context != file->ucontext) {
+           !rcq || rcq->uobject->context != file->ucontext ||
+           (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) {
                ret = -EINVAL;
                goto err_up;
        }
@@ -759,7 +762,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uv
        attr.qp_context    = file;
        attr.send_cq       = scq;
        attr.recv_cq       = rcq;
-       attr.srq           = NULL;
+       attr.srq           = srq;
        attr.sq_sig_type   = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : 
IB_SIGNAL_REQ_WR;
        attr.qp_type       = cmd.qp_type;
 
@@ -1004,3 +1007,178 @@ ssize_t ib_uverbs_detach_mcast(struct ib
 
        return ret ? ret : in_len;
 }
+
+ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
+                            const char __user *buf, int in_len,
+                            int out_len)
+{
+       struct ib_uverbs_create_srq      cmd;
+       struct ib_uverbs_create_srq_resp resp;
+       struct ib_udata                  udata;
+       struct ib_uobject               *uobj;
+       struct ib_pd                    *pd;
+       struct ib_srq                   *srq;
+       struct ib_srq_init_attr          attr;
+       int ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+       if (!uobj)
+               return -ENOMEM;
+
+       down(&ib_uverbs_idr_mutex);
+
+       pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+
+       if (!pd || pd->uobject->context != file->ucontext) {
+               ret = -EINVAL;
+               goto err_up;
+       }
+
+       attr.event_handler  = ib_uverbs_srq_event_handler;
+       attr.srq_context    = file;
+       attr.attr.max_wr    = cmd.max_wr;
+       attr.attr.max_sge   = cmd.max_sge;
+       attr.attr.srq_limit = cmd.srq_limit;
+
+       uobj->user_handle = cmd.user_handle;
+       uobj->context     = file->ucontext;
+
+       srq = pd->device->create_srq(pd, &attr, &udata);
+       if (IS_ERR(srq)) {
+               ret = PTR_ERR(srq);
+               goto err_up;
+       }
+
+       srq->device        = pd->device;
+       srq->pd            = pd;
+       srq->uobject       = uobj;
+       srq->event_handler = attr.event_handler;
+       srq->srq_context   = attr.srq_context;
+       atomic_inc(&pd->usecnt);
+       atomic_set(&srq->usecnt, 0);
+
+       memset(&resp, 0, sizeof resp);
+
+retry:
+       if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto err_destroy;
+       }
+
+       ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id);
+
+       if (ret == -EAGAIN)
+               goto retry;
+       if (ret)
+               goto err_destroy;
+
+       resp.srq_handle = uobj->id;
+
+       spin_lock_irq(&file->ucontext->lock);
+       list_add_tail(&uobj->list, &file->ucontext->srq_list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp)) {
+               ret = -EFAULT;
+               goto err_list;
+       }
+
+       up(&ib_uverbs_idr_mutex);
+
+       return in_len;
+
+err_list:
+       spin_lock_irq(&file->ucontext->lock);
+       list_del(&uobj->list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+err_destroy:
+       ib_destroy_srq(srq);
+
+err_up:
+       up(&ib_uverbs_idr_mutex);
+
+       kfree(uobj);
+       return ret;
+}
+
+ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
+                            const char __user *buf, int in_len,
+                            int out_len)
+{
+       struct ib_uverbs_modify_srq cmd;
+       struct ib_srq              *srq;
+       struct ib_srq_attr          attr;
+       int                         ret;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       down(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (!srq || srq->uobject->context != file->ucontext) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       attr.max_wr    = cmd.max_wr;
+       attr.max_sge   = cmd.max_sge;
+       attr.srq_limit = cmd.srq_limit;
+
+       ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
+
+out:
+       up(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
+                             const char __user *buf, int in_len,
+                             int out_len)
+{
+       struct ib_uverbs_destroy_srq cmd;
+       struct ib_srq               *srq;
+       struct ib_uobject           *uobj;
+       int                          ret = -EINVAL;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       down(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (!srq || srq->uobject->context != file->ucontext)
+               goto out;
+
+       uobj = srq->uobject;
+
+       ret = ib_destroy_srq(srq);
+       if (ret)
+               goto out;
+
+       idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
+
+       spin_lock_irq(&file->ucontext->lock);
+       list_del(&uobj->list);
+       spin_unlock_irq(&file->ucontext->lock);
+
+       kfree(uobj);
+
+out:
+       up(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c 
b/drivers/infiniband/core/uverbs_main.c
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -69,6 +69,7 @@ DEFINE_IDR(ib_uverbs_mw_idr);
 DEFINE_IDR(ib_uverbs_ah_idr);
 DEFINE_IDR(ib_uverbs_cq_idr);
 DEFINE_IDR(ib_uverbs_qp_idr);
+DEFINE_IDR(ib_uverbs_srq_idr);
 
 static spinlock_t map_lock;
 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -93,6 +94,9 @@ static ssize_t (*uverbs_cmd_table[])(str
        [IB_USER_VERBS_CMD_DESTROY_QP]    = ib_uverbs_destroy_qp,
        [IB_USER_VERBS_CMD_ATTACH_MCAST]  = ib_uverbs_attach_mcast,
        [IB_USER_VERBS_CMD_DETACH_MCAST]  = ib_uverbs_detach_mcast,
+       [IB_USER_VERBS_CMD_CREATE_SRQ]    = ib_uverbs_create_srq,
+       [IB_USER_VERBS_CMD_MODIFY_SRQ]    = ib_uverbs_modify_srq,
+       [IB_USER_VERBS_CMD_DESTROY_SRQ]   = ib_uverbs_destroy_srq,
 };
 
 static struct vfsmount *uverbs_event_mnt;
@@ -127,7 +131,14 @@ static int ib_dealloc_ucontext(struct ib
                kfree(uobj);
        }
 
-       /* XXX Free SRQs */
+       list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
+               struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id);
+               idr_remove(&ib_uverbs_srq_idr, uobj->id);
+               ib_destroy_srq(srq);
+               list_del(&uobj->list);
+               kfree(uobj);
+       }
+
        /* XXX Free MWs */
 
        list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
@@ -346,6 +357,13 @@ void ib_uverbs_qp_event_handler(struct i
                                event->event);
 }
 
+void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr)
+{
+       ib_uverbs_async_handler(context_ptr,
+                               event->element.srq->uobject->user_handle,
+                               event->event);
+}
+
 static void ib_uverbs_event_handler(struct ib_event_handler *handler,
                                    struct ib_event *event)
 {
diff --git a/drivers/infiniband/include/ib_user_verbs.h 
b/drivers/infiniband/include/ib_user_verbs.h
--- a/drivers/infiniband/include/ib_user_verbs.h
+++ b/drivers/infiniband/include/ib_user_verbs.h
@@ -78,7 +78,12 @@ enum {
        IB_USER_VERBS_CMD_POST_SEND,
        IB_USER_VERBS_CMD_POST_RECV,
        IB_USER_VERBS_CMD_ATTACH_MCAST,
-       IB_USER_VERBS_CMD_DETACH_MCAST
+       IB_USER_VERBS_CMD_DETACH_MCAST,
+       IB_USER_VERBS_CMD_CREATE_SRQ,
+       IB_USER_VERBS_CMD_MODIFY_SRQ,
+       IB_USER_VERBS_CMD_QUERY_SRQ,
+       IB_USER_VERBS_CMD_DESTROY_SRQ,
+       IB_USER_VERBS_CMD_POST_SRQ_RECV
 };
 
 /*
@@ -386,4 +391,32 @@ struct ib_uverbs_detach_mcast {
        __u64 driver_data[0];
 };
 
+struct ib_uverbs_create_srq {
+       __u64 response;
+       __u64 user_handle;
+       __u32 pd_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_srq_resp {
+       __u32 srq_handle;
+};
+
+struct ib_uverbs_modify_srq {
+       __u32 srq_handle;
+       __u32 attr_mask;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u32 reserved;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_destroy_srq {
+       __u32 srq_handle;
+};
+
 #endif /* IB_USER_VERBS_H */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to