summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_syncobj.c89
1 files changed, 58 insertions, 31 deletions
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index cccd3bd194c6..15e74ca61760 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -798,58 +798,43 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
return 0;
}
-int
-drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_private)
+static int drm_syncobj_array_find(struct drm_file *file_private,
+ void *user_handles, uint32_t count_handles,
+ struct drm_syncobj ***syncobjs_out)
{
- struct drm_syncobj_wait *args = data;
- uint32_t *handles;
+ uint32_t i, *handles;
struct drm_syncobj **syncobjs;
- int ret = 0;
- uint32_t i;
-
- if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
- return -ENODEV;
-
- if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
- DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
- return -EINVAL;
-
- if (args->count_handles == 0)
- return -EINVAL;
+ int ret;
- /* Get the handles from userspace */
- handles = kmalloc_array(args->count_handles, sizeof(uint32_t),
- GFP_KERNEL);
+ handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
if (handles == NULL)
return -ENOMEM;
- if (copy_from_user(handles,
- u64_to_user_ptr(args->handles),
- sizeof(uint32_t) * args->count_handles)) {
+ if (copy_from_user(handles, user_handles,
+ sizeof(uint32_t) * count_handles)) {
ret = -EFAULT;
goto err_free_handles;
}
- syncobjs = kcalloc(args->count_handles,
- sizeof(struct drm_syncobj *), GFP_KERNEL);
- if (!syncobjs) {
+ syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
+ if (syncobjs == NULL) {
ret = -ENOMEM;
goto err_free_handles;
}
- for (i = 0; i < args->count_handles; i++) {
+ for (i = 0; i < count_handles; i++) {
syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
if (!syncobjs[i]) {
ret = -ENOENT;
- goto err_free_fence_array;
+ goto err_put_syncobjs;
}
}
- ret = drm_syncobj_array_wait(dev, file_private,
- args, syncobjs);
+ kfree(handles);
+ *syncobjs_out = syncobjs;
+ return 0;
-err_free_fence_array:
+err_put_syncobjs:
while (i-- > 0)
drm_syncobj_put(syncobjs[i]);
kfree(syncobjs);
@@ -858,3 +843,45 @@ err_free_handles:
return ret;
}
+
+static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
+ uint32_t count)
+{
+ uint32_t i;
+ for (i = 0; i < count; i++)
+ drm_syncobj_put(syncobjs[i]);
+ kfree(syncobjs);
+}
+
+int
+drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_private)
+{
+ struct drm_syncobj_wait *args = data;
+ struct drm_syncobj **syncobjs;
+ int ret = 0;
+
+ if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+ return -ENODEV;
+
+ if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
+ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
+ return -EINVAL;
+
+ if (args->count_handles == 0)
+ return -EINVAL;
+
+ ret = drm_syncobj_array_find(file_private,
+ u64_to_user_ptr(args->handles),
+ args->count_handles,
+ &syncobjs);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_syncobj_array_wait(dev, file_private,
+ args, syncobjs);
+
+ drm_syncobj_array_free(syncobjs, args->count_handles);
+
+ return ret;
+}