aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/uverbs_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/uverbs_cmd.c')
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c306
1 files changed, 206 insertions, 100 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index a9f048990dfcd..e3707de3e1b90 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -355,7 +355,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
goto err_free;
resp.async_fd = ret;
- filp = ib_uverbs_alloc_event_file(file, 1);
+ filp = ib_uverbs_alloc_event_file(file, IB_UVERBS_EVENT_FILE_ASYNC);
if (IS_ERR(filp)) {
ret = PTR_ERR(filp);
goto err_fd;
@@ -933,49 +933,38 @@ void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev,
xrcd_table_delete(dev, inode);
}
-ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
- const char __user *buf, int in_len,
- int out_len)
+static ssize_t ib_uverbs_reg_mr_common(struct ib_uverbs_file *file,
+ struct ib_uverbs_reg_mmu_notify_mr *cmd,
+ struct ib_uverbs_reg_mr_resp *resp,
+ struct ib_udata *udata,
+ bool do_notify)
{
- struct ib_uverbs_reg_mr cmd;
- struct ib_uverbs_reg_mr_resp resp;
- struct ib_udata udata;
- struct ib_uobject *uobj;
- struct ib_pd *pd;
- struct ib_mr *mr;
- 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);
+ struct ib_umr_object *obj;
+ struct ib_pd *pd;
+ struct ib_mr *mr;
+ int ret;
- if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
+ if ((cmd->start & ~PAGE_MASK) != (cmd->hca_va & ~PAGE_MASK))
return -EINVAL;
ret = ib_check_mr_access(cmd.access_flags);
if (ret)
return ret;
- uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
- if (!uobj)
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
return -ENOMEM;
- init_uobj(uobj, 0, file->ucontext, &mr_lock_class);
- down_write(&uobj->mutex);
+ init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext, &mr_lock_class);
+ down_write(&obj->uevent.uobject.mutex);
- pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ pd = idr_read_pd(cmd->pd_handle, file->ucontext);
if (!pd) {
ret = -EINVAL;
goto err_free;
}
- if (cmd.access_flags & IB_ACCESS_ON_DEMAND) {
+ if (cmd->access_flags & IB_ACCESS_ON_DEMAND) {
struct ib_device_attr attr;
ret = ib_query_device(pd->device, &attr);
@@ -987,8 +976,8 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
}
}
- mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va,
- cmd.access_flags, &udata);
+ mr = pd->device->reg_user_mr(pd, cmd->start, cmd->length, cmd->hca_va,
+ cmd->access_flags, &udata);
if (IS_ERR(mr)) {
ret = PTR_ERR(mr);
goto err_put;
@@ -996,22 +985,22 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
mr->device = pd->device;
mr->pd = pd;
- mr->uobject = uobj;
+ mr->uobject = &obj->uevent.uobject;
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
- uobj->object = mr;
- ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj);
+ obj->uevent.uobject.object = mr;
+ ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uevent.uobject);
if (ret)
goto err_unreg;
memset(&resp, 0, sizeof resp);
- resp.lkey = mr->lkey;
- resp.rkey = mr->rkey;
- resp.mr_handle = uobj->id;
+ resp->lkey = mr->lkey;
+ resp->rkey = mr->rkey;
+ resp->mr_handle = obj->uevent.uobject.id;
- if (copy_to_user((void __user *) (unsigned long) cmd.response,
- &resp, sizeof resp)) {
+ if (copy_to_user((void __user *) (unsigned long) cmd->response,
+ resp, sizeof *resp)) {
ret = -EFAULT;
goto err_copy;
}
@@ -1019,17 +1008,23 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
put_pd_read(pd);
mutex_lock(&file->mutex);
- list_add_tail(&uobj->list, &file->ucontext->mr_list);
+ list_add_tail(&obj->uevent.uobject.list, &file->ucontext->mr_list);
mutex_unlock(&file->mutex);
- uobj->live = 1;
+ obj->uevent.uobject.live = 1;
- up_write(&uobj->mutex);
+ if (do_notify)
+ ib_ummunotify_register_range(&file->mmu_notify_context,
+ &obj->range);
+ else
+ ib_ummunotify_clear_range(&obj->range);
- return in_len;
+ up_write(&obj->uevent.uobject.mutex);
+
+ return 0;
err_copy:
- idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
+ idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uevent.uobject);
err_unreg:
ib_dereg_mr(mr);
@@ -1038,7 +1033,7 @@ err_put:
put_pd_read(pd);
err_free:
- put_uobj_write(uobj);
+ put_uobj_write(&obj->uevent.uobject);
return ret;
}
@@ -1135,23 +1130,79 @@ put_uobjs:
return ret;
}
-ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
- const char __user *buf, int in_len,
- int out_len)
+ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
{
- struct ib_uverbs_dereg_mr cmd;
- struct ib_mr *mr;
- struct ib_uobject *uobj;
- int ret = -EINVAL;
+ struct ib_uverbs_reg_mr cmd;
+ struct ib_uverbs_reg_mmu_notify_mr not_cmd;
+ struct ib_uverbs_reg_mr_resp resp;
+ struct ib_udata udata;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext);
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ not_cmd.response = cmd.response;
+ not_cmd.user_handle = 0;
+ not_cmd.start = cmd.start;
+ not_cmd.length = cmd.length;
+ not_cmd.hca_va = cmd.hca_va;
+ not_cmd.pd_handle = cmd.pd_handle;
+ not_cmd.access_flags = cmd.access_flags;
+
+ ret = ib_uverbs_reg_mr_common(file, &not_cmd, &resp, &udata, false);
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_reg_mmu_notify_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_reg_mmu_notify_mr cmd;
+ struct ib_uverbs_reg_mr_resp resp;
+ struct ib_udata udata;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (!ib_ummunotify_context_used(&file->mmu_notify_context))
+ return -EINVAL;
+
+ 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);
+
+ ret = ib_uverbs_reg_mr_common(file, &cmd, &resp, &udata, true);
+ return ret ? ret : in_len;
+}
+
+static ssize_t ib_uverbs_dereg_mr_common(struct ib_uverbs_file *file,
+ int mr_handle,
+ u32 *events_reported)
+{
+ struct ib_uobject *uobj;
+ struct ib_mr *mr;
+ struct ib_umr_object *obj;
+ int ret;
+
+ uobj = idr_write_uobj(&ib_uverbs_mr_idr, mr_handle, file->ucontext);
if (!uobj)
return -EINVAL;
mr = uobj->object;
+ obj = container_of(uobj, struct ib_umr_object, uevent.uobject);
ret = ib_dereg_mr(mr);
if (!ret)
@@ -1162,15 +1213,60 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
if (ret)
return ret;
+ ib_ummunotify_unregister_range(&file->mmu_notify_context,
+ &obj->range);
+
idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
mutex_lock(&file->mutex);
list_del(&uobj->list);
mutex_unlock(&file->mutex);
+ ib_uverbs_release_uevent(file, &obj->uevent);
+
+ if (events_reported)
+ *events_reported = obj->uevent.events_reported;
+
put_uobj(uobj);
- return in_len;
+ return 0;
+}
+
+ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_dereg_mr cmd;
+ int ret;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_uverbs_dereg_mr_common(file, cmd.mr_handle, NULL);
+
+ return ret ? ret : in_len;
+}
+
+
+ssize_t ib_uverbs_dereg_mmu_notify_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_dereg_mmu_notify_mr cmd;
+ struct ib_uverbs_dereg_mmu_notify_mr_resp resp;
+ int ret;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_uverbs_dereg_mr_common(file, cmd.mr_handle,
+ &resp.events_reported);
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return ret ? ret : in_len;
}
ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
@@ -1313,7 +1409,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
return ret;
resp.fd = ret;
- filp = ib_uverbs_alloc_event_file(file, 0);
+ filp = ib_uverbs_alloc_event_file(file, IB_UVERBS_EVENT_FILE_COMP);
if (IS_ERR(filp)) {
put_unused_fd(resp.fd);
return PTR_ERR(filp);
@@ -3295,63 +3391,73 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
return ret ? ret : in_len;
}
-int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
- struct ib_udata *ucore,
- struct ib_udata *uhw)
+ssize_t ib_uverbs_create_mmu_notify_channel(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
{
- struct ib_uverbs_ex_query_device_resp resp;
- struct ib_uverbs_ex_query_device cmd;
- struct ib_device_attr attr;
- struct ib_device *device;
- int err;
+ struct ib_uverbs_create_mmu_notify_channel cmd;
+ struct ib_uverbs_create_mmu_notify_channel_resp resp;
+ struct file *filp;
+ int ret;
- device = file->device->ib_dev;
- if (ucore->inlen < sizeof(cmd))
- return -EINVAL;
+ if (out_len < sizeof resp)
+ return -ENOSPC;
- err = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
- if (err)
- return err;
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
- if (cmd.comp_mask)
- return -EINVAL;
+ mutex_lock(&file->mutex);
- if (cmd.reserved)
- return -EINVAL;
+ if (file->mmu_notify_file) {
+ ret = -EINVAL;
+ goto err;
+ }
- resp.response_length = offsetof(typeof(resp), odp_caps);
+ ret = get_unused_fd();
+ if (ret < 0)
+ goto err;
+ resp.fd = ret;
- if (ucore->outlen < resp.response_length)
- return -ENOSPC;
+ filp = ib_uverbs_alloc_event_file(file, IB_UVERBS_EVENT_FILE_MMU_NOTIFY);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto err_put_fd;
+ }
- err = device->query_device(device, &attr);
- if (err)
- return err;
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_fput;
+ }
- copy_query_dev_fields(file, &resp.base, &attr);
- resp.comp_mask = 0;
+ ret = ib_ummunotify_init_context(&file->mmu_notify_context,
+ ib_uverbs_mr_event_handler);
+ if (ret)
+ goto err_fput;
- if (ucore->outlen < resp.response_length + sizeof(resp.odp_caps))
- goto end;
+ file->mmu_notify_counter = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!file->mmu_notify_counter) {
+ ret = -ENOMEM;
+ goto err_context;
+ }
-#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- resp.odp_caps.general_caps = attr.odp_caps.general_caps;
- resp.odp_caps.per_transport_caps.rc_odp_caps =
- attr.odp_caps.per_transport_caps.rc_odp_caps;
- resp.odp_caps.per_transport_caps.uc_odp_caps =
- attr.odp_caps.per_transport_caps.uc_odp_caps;
- resp.odp_caps.per_transport_caps.ud_odp_caps =
- attr.odp_caps.per_transport_caps.ud_odp_caps;
- resp.odp_caps.reserved = 0;
-#else
- memset(&resp.odp_caps, 0, sizeof(resp.odp_caps));
-#endif
- resp.response_length += sizeof(resp.odp_caps);
+ file->mmu_notify_file = filp->private_data;
+ fd_install(resp.fd, filp);
-end:
- err = ib_copy_to_udata(ucore, &resp, resp.response_length);
- if (err)
- return err;
+ mutex_unlock(&file->mutex);
- return 0;
+ return in_len;
+
+err_context:
+ ib_ummunotify_cleanup_context(&file->mmu_notify_context);
+
+err_fput:
+ fput(filp);
+
+err_put_fd:
+ put_unused_fd(resp.fd);
+
+err:
+ mutex_unlock(&file->mutex);
+ return ret;
}