2 * Copyright 2017 Red Hat
3 * Parts ported from amdgpu (fence wait code).
4 * Copyright 2016 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 * DRM synchronisation objects (syncobj) are a persistent objects,
33 * that contain an optional fence. The fence can be updated with a new
36 * syncobj's can be waited upon, where it will wait for the underlying
39 * syncobj's can be export to fd's and back, these fd's are opaque and
40 * have no other use case, except passing the syncobj between processes.
42 * Their primary use-case is to implement Vulkan fences and semaphores.
44 * syncobj have a kref reference count, but also have an optional file.
45 * The file is only created once the syncobj is exported.
46 * The file takes a reference on the kref.
50 #include <linux/file.h>
52 #include <linux/anon_inodes.h>
53 #include <linux/sync_file.h>
54 #include <linux/sched/signal.h>
56 #include "drm_internal.h"
57 #include <drm/drm_syncobj.h>
60 * drm_syncobj_find - lookup and reference a sync object.
61 * @file_private: drm file private pointer
62 * @handle: sync object handle to lookup.
64 * Returns a reference to the syncobj pointed to by handle or NULL.
66 struct drm_syncobj
*drm_syncobj_find(struct drm_file
*file_private
,
69 struct drm_syncobj
*syncobj
;
71 lockmgr(&file_private
->syncobj_table_lock
, LK_EXCLUSIVE
);
73 /* Check if we currently have a reference on the object */
74 syncobj
= idr_find(&file_private
->syncobj_idr
, handle
);
76 drm_syncobj_get(syncobj
);
78 lockmgr(&file_private
->syncobj_table_lock
, LK_RELEASE
);
82 EXPORT_SYMBOL(drm_syncobj_find
);
84 static void drm_syncobj_add_callback_locked(struct drm_syncobj
*syncobj
,
85 struct drm_syncobj_cb
*cb
,
86 drm_syncobj_func_t func
)
89 list_add_tail(&cb
->node
, &syncobj
->cb_list
);
93 static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj
*syncobj
,
94 struct dma_fence
**fence
,
95 struct drm_syncobj_cb
*cb
,
96 drm_syncobj_func_t func
)
100 *fence
= drm_syncobj_fence_get(syncobj
);
104 lockmgr(&syncobj
->lock
, LK_EXCLUSIVE
);
105 /* We've already tried once to get a fence and failed. Now that we
106 * have the lock, try one more time just to be sure we don't add a
107 * callback when a fence has already been set.
109 if (syncobj
->fence
) {
110 *fence
= dma_fence_get(syncobj
->fence
);
114 drm_syncobj_add_callback_locked(syncobj
, cb
, func
);
117 lockmgr(&syncobj
->lock
, LK_RELEASE
);
124 * drm_syncobj_add_callback - adds a callback to syncobj::cb_list
125 * @syncobj: Sync object to which to add the callback
126 * @cb: Callback to add
127 * @func: Func to use when initializing the drm_syncobj_cb struct
129 * This adds a callback to be called next time the fence is replaced
131 void drm_syncobj_add_callback(struct drm_syncobj
*syncobj
,
132 struct drm_syncobj_cb
*cb
,
133 drm_syncobj_func_t func
)
135 lockmgr(&syncobj
->lock
, LK_EXCLUSIVE
);
136 drm_syncobj_add_callback_locked(syncobj
, cb
, func
);
137 lockmgr(&syncobj
->lock
, LK_RELEASE
);
139 EXPORT_SYMBOL(drm_syncobj_add_callback
);
142 * drm_syncobj_add_callback - removes a callback to syncobj::cb_list
143 * @syncobj: Sync object from which to remove the callback
144 * @cb: Callback to remove
146 void drm_syncobj_remove_callback(struct drm_syncobj
*syncobj
,
147 struct drm_syncobj_cb
*cb
)
149 lockmgr(&syncobj
->lock
, LK_EXCLUSIVE
);
150 list_del_init(&cb
->node
);
151 lockmgr(&syncobj
->lock
, LK_RELEASE
);
153 EXPORT_SYMBOL(drm_syncobj_remove_callback
);
156 * drm_syncobj_replace_fence - replace fence in a sync object.
157 * @syncobj: Sync object to replace fence in
158 * @fence: fence to install in sync file.
160 * This replaces the fence on a sync object.
162 void drm_syncobj_replace_fence(struct drm_syncobj
*syncobj
,
163 struct dma_fence
*fence
)
165 struct dma_fence
*old_fence
;
166 struct drm_syncobj_cb
*cur
, *tmp
;
169 dma_fence_get(fence
);
171 lockmgr(&syncobj
->lock
, LK_EXCLUSIVE
);
173 old_fence
= syncobj
->fence
;
174 syncobj
->fence
= fence
;
176 if (fence
!= old_fence
) {
177 list_for_each_entry_safe(cur
, tmp
, &syncobj
->cb_list
, node
) {
178 list_del_init(&cur
->node
);
179 cur
->func(syncobj
, cur
);
183 lockmgr(&syncobj
->lock
, LK_RELEASE
);
185 dma_fence_put(old_fence
);
187 EXPORT_SYMBOL(drm_syncobj_replace_fence
);
189 struct drm_syncobj_null_fence
{
190 struct dma_fence base
;
194 static const char *drm_syncobj_null_fence_get_name(struct dma_fence
*fence
)
196 return "syncobjnull";
199 static bool drm_syncobj_null_fence_enable_signaling(struct dma_fence
*fence
)
201 dma_fence_enable_sw_signaling(fence
);
202 return !dma_fence_is_signaled(fence
);
205 static const struct dma_fence_ops drm_syncobj_null_fence_ops
= {
206 .get_driver_name
= drm_syncobj_null_fence_get_name
,
207 .get_timeline_name
= drm_syncobj_null_fence_get_name
,
208 .enable_signaling
= drm_syncobj_null_fence_enable_signaling
,
209 .wait
= dma_fence_default_wait
,
213 static int drm_syncobj_assign_null_handle(struct drm_syncobj
*syncobj
)
215 struct drm_syncobj_null_fence
*fence
;
216 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
220 lockinit(&fence
->lock
, "dsofl", 0, 0);
221 dma_fence_init(&fence
->base
, &drm_syncobj_null_fence_ops
,
223 dma_fence_signal(&fence
->base
);
225 drm_syncobj_replace_fence(syncobj
, &fence
->base
);
227 dma_fence_put(&fence
->base
);
232 int drm_syncobj_find_fence(struct drm_file
*file_private
,
234 struct dma_fence
**fence
)
236 struct drm_syncobj
*syncobj
= drm_syncobj_find(file_private
, handle
);
242 *fence
= drm_syncobj_fence_get(syncobj
);
246 drm_syncobj_put(syncobj
);
249 EXPORT_SYMBOL(drm_syncobj_find_fence
);
252 * drm_syncobj_free - free a sync object.
253 * @kref: kref to free.
255 * Only to be called from kref_put in drm_syncobj_put.
257 void drm_syncobj_free(struct kref
*kref
)
259 struct drm_syncobj
*syncobj
= container_of(kref
,
262 drm_syncobj_replace_fence(syncobj
, NULL
);
265 EXPORT_SYMBOL(drm_syncobj_free
);
268 * drm_syncobj_create - create a new syncobj
269 * @out_syncobj: returned syncobj
270 * @flags: DRM_SYNCOBJ_* flags
271 * @fence: if non-NULL, the syncobj will represent this fence
273 int drm_syncobj_create(struct drm_syncobj
**out_syncobj
, uint32_t flags
,
274 struct dma_fence
*fence
)
277 struct drm_syncobj
*syncobj
;
279 syncobj
= kzalloc(sizeof(struct drm_syncobj
), GFP_KERNEL
);
283 kref_init(&syncobj
->refcount
);
284 INIT_LIST_HEAD(&syncobj
->cb_list
);
285 lockinit(&syncobj
->lock
, "dsol", 0, 0);
287 if (flags
& DRM_SYNCOBJ_CREATE_SIGNALED
) {
288 ret
= drm_syncobj_assign_null_handle(syncobj
);
290 drm_syncobj_put(syncobj
);
296 drm_syncobj_replace_fence(syncobj
, fence
);
298 *out_syncobj
= syncobj
;
301 EXPORT_SYMBOL(drm_syncobj_create
);
304 * drm_syncobj_get_handle - get a handle from a syncobj
306 int drm_syncobj_get_handle(struct drm_file
*file_private
,
307 struct drm_syncobj
*syncobj
, u32
*handle
)
311 /* take a reference to put in the idr */
312 drm_syncobj_get(syncobj
);
314 idr_preload(GFP_KERNEL
);
315 lockmgr(&file_private
->syncobj_table_lock
, LK_EXCLUSIVE
);
316 ret
= idr_alloc(&file_private
->syncobj_idr
, syncobj
, 1, 0, GFP_NOWAIT
);
317 lockmgr(&file_private
->syncobj_table_lock
, LK_RELEASE
);
322 drm_syncobj_put(syncobj
);
329 EXPORT_SYMBOL(drm_syncobj_get_handle
);
331 static int drm_syncobj_create_as_handle(struct drm_file
*file_private
,
332 u32
*handle
, uint32_t flags
)
335 struct drm_syncobj
*syncobj
;
337 ret
= drm_syncobj_create(&syncobj
, flags
, NULL
);
341 ret
= drm_syncobj_get_handle(file_private
, syncobj
, handle
);
342 drm_syncobj_put(syncobj
);
346 static int drm_syncobj_destroy(struct drm_file
*file_private
,
349 struct drm_syncobj
*syncobj
;
351 lockmgr(&file_private
->syncobj_table_lock
, LK_EXCLUSIVE
);
352 syncobj
= idr_remove(&file_private
->syncobj_idr
, handle
);
353 lockmgr(&file_private
->syncobj_table_lock
, LK_RELEASE
);
358 drm_syncobj_put(syncobj
);
363 static int drm_syncobj_file_release(struct inode
*inode
, struct file
*file
)
365 struct drm_syncobj
*syncobj
= file
->private_data
;
367 drm_syncobj_put(syncobj
);
371 static const struct file_operations drm_syncobj_file_fops
= {
372 .release
= drm_syncobj_file_release
,
376 int drm_syncobj_get_fd(struct drm_syncobj
*syncobj
, int *p_fd
)
381 fd
= get_unused_fd_flags(O_CLOEXEC
);
386 file
= anon_inode_getfile("syncobj_file",
387 &drm_syncobj_file_fops
,
391 return PTR_ERR(file
);
397 drm_syncobj_get(syncobj
);
398 fd_install(fd
, file
);
403 EXPORT_SYMBOL(drm_syncobj_get_fd
);
405 static int drm_syncobj_handle_to_fd(struct drm_file
*file_private
,
406 u32 handle
, int *p_fd
)
408 struct drm_syncobj
*syncobj
= drm_syncobj_find(file_private
, handle
);
414 ret
= drm_syncobj_get_fd(syncobj
, p_fd
);
415 drm_syncobj_put(syncobj
);
420 static struct drm_syncobj
*drm_syncobj_fdget(int fd
)
422 struct file
*file
= fget(fd
);
426 if (file
->f_op
!= &drm_syncobj_file_fops
)
429 return file
->private_data
;
436 static int drm_syncobj_fd_to_handle(struct drm_file
*file_private
,
440 struct drm_syncobj
*syncobj
;
448 if (file
->f_op
!= &drm_syncobj_file_fops
) {
453 /* take a reference to put in the idr */
454 syncobj
= file
->private_data
;
455 drm_syncobj_get(syncobj
);
457 idr_preload(GFP_KERNEL
);
458 spin_lock(&file_private
->syncobj_table_lock
);
459 ret
= idr_alloc(&file_private
->syncobj_idr
, syncobj
, 1, 0, GFP_NOWAIT
);
460 spin_unlock(&file_private
->syncobj_table_lock
);
467 drm_syncobj_put(syncobj
);
475 static int drm_syncobj_import_sync_file_fence(struct drm_file
*file_private
,
478 struct dma_fence
*fence
= sync_file_get_fence(fd
);
479 struct drm_syncobj
*syncobj
;
484 syncobj
= drm_syncobj_find(file_private
, handle
);
486 dma_fence_put(fence
);
490 drm_syncobj_replace_fence(syncobj
, fence
);
491 dma_fence_put(fence
);
492 drm_syncobj_put(syncobj
);
496 static int drm_syncobj_export_sync_file(struct drm_file
*file_private
,
497 int handle
, int *p_fd
)
500 struct dma_fence
*fence
;
501 struct sync_file
*sync_file
;
502 int fd
= get_unused_fd_flags(O_CLOEXEC
);
507 ret
= drm_syncobj_find_fence(file_private
, handle
, &fence
);
511 sync_file
= sync_file_create(fence
);
513 dma_fence_put(fence
);
520 fd_install(fd
, sync_file
->file
);
529 * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time
530 * @file_private: drm file-private structure to set up
532 * Called at device open time, sets up the structure for handling refcounting
536 drm_syncobj_open(struct drm_file
*file_private
)
538 idr_init(&file_private
->syncobj_idr
);
539 lockinit(&file_private
->syncobj_table_lock
, "dsotl", 0, 0);
543 drm_syncobj_release_handle(int id
, void *ptr
, void *data
)
545 struct drm_syncobj
*syncobj
= ptr
;
547 drm_syncobj_put(syncobj
);
552 * drm_syncobj_release - release file-private sync object resources
553 * @file_private: drm file-private structure to clean up
555 * Called at close time when the filp is going away.
557 * Releases any remaining references on objects by this filp.
560 drm_syncobj_release(struct drm_file
*file_private
)
562 idr_for_each(&file_private
->syncobj_idr
,
563 &drm_syncobj_release_handle
, file_private
);
564 idr_destroy(&file_private
->syncobj_idr
);
568 drm_syncobj_create_ioctl(struct drm_device
*dev
, void *data
,
569 struct drm_file
*file_private
)
571 struct drm_syncobj_create
*args
= data
;
573 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
576 /* no valid flags yet */
577 if (args
->flags
& ~DRM_SYNCOBJ_CREATE_SIGNALED
)
580 return drm_syncobj_create_as_handle(file_private
,
581 &args
->handle
, args
->flags
);
585 drm_syncobj_destroy_ioctl(struct drm_device
*dev
, void *data
,
586 struct drm_file
*file_private
)
588 struct drm_syncobj_destroy
*args
= data
;
590 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
593 /* make sure padding is empty */
596 return drm_syncobj_destroy(file_private
, args
->handle
);
600 drm_syncobj_handle_to_fd_ioctl(struct drm_device
*dev
, void *data
,
601 struct drm_file
*file_private
)
603 struct drm_syncobj_handle
*args
= data
;
605 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
611 if (args
->flags
!= 0 &&
612 args
->flags
!= DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
)
615 if (args
->flags
& DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
)
616 return drm_syncobj_export_sync_file(file_private
, args
->handle
,
619 return drm_syncobj_handle_to_fd(file_private
, args
->handle
,
624 drm_syncobj_fd_to_handle_ioctl(struct drm_device
*dev
, void *data
,
625 struct drm_file
*file_private
)
627 struct drm_syncobj_handle
*args
= data
;
629 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
635 if (args
->flags
!= 0 &&
636 args
->flags
!= DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
)
639 if (args
->flags
& DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
)
640 return drm_syncobj_import_sync_file_fence(file_private
,
644 return drm_syncobj_fd_to_handle(file_private
, args
->fd
,
649 struct syncobj_wait_entry
{
650 struct task_struct
*task
;
651 struct dma_fence
*fence
;
652 struct dma_fence_cb fence_cb
;
653 struct drm_syncobj_cb syncobj_cb
;
656 static void syncobj_wait_fence_func(struct dma_fence
*fence
,
657 struct dma_fence_cb
*cb
)
659 struct syncobj_wait_entry
*wait
=
660 container_of(cb
, struct syncobj_wait_entry
, fence_cb
);
662 wake_up_process(wait
->task
);
665 static void syncobj_wait_syncobj_func(struct drm_syncobj
*syncobj
,
666 struct drm_syncobj_cb
*cb
)
668 struct syncobj_wait_entry
*wait
=
669 container_of(cb
, struct syncobj_wait_entry
, syncobj_cb
);
671 /* This happens inside the syncobj lock */
672 wait
->fence
= dma_fence_get(syncobj
->fence
);
673 wake_up_process(wait
->task
);
676 static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj
**syncobjs
,
682 struct syncobj_wait_entry
*entries
;
683 struct dma_fence
*fence
;
685 uint32_t signaled_count
, i
;
687 entries
= kcalloc(count
, sizeof(*entries
), GFP_KERNEL
);
691 /* Walk the list of sync objects and initialize entries. We do
692 * this up-front so that we can properly return -EINVAL if there is
693 * a syncobj with a missing fence and then never have the chance of
694 * returning -EINVAL again.
697 for (i
= 0; i
< count
; ++i
) {
698 entries
[i
].task
= current
;
699 entries
[i
].fence
= drm_syncobj_fence_get(syncobjs
[i
]);
700 if (!entries
[i
].fence
) {
701 if (flags
& DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
) {
705 goto cleanup_entries
;
709 if (dma_fence_is_signaled(entries
[i
].fence
)) {
710 if (signaled_count
== 0 && idx
)
716 /* Initialize ret to the max of timeout and 1. That way, the
717 * default return value indicates a successful wait and not a
720 ret
= max_t(signed long, timeout
, 1);
722 if (signaled_count
== count
||
723 (signaled_count
> 0 &&
724 !(flags
& DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
)))
725 goto cleanup_entries
;
727 /* There's a very annoying laxness in the dma_fence API here, in
728 * that backends are not required to automatically report when a
729 * fence is signaled prior to fence->ops->enable_signaling() being
730 * called. So here if we fail to match signaled_count, we need to
731 * fallthough and try a 0 timeout wait!
734 if (flags
& DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
) {
735 for (i
= 0; i
< count
; ++i
) {
736 drm_syncobj_fence_get_or_add_callback(syncobjs
[i
],
738 &entries
[i
].syncobj_cb
,
739 syncobj_wait_syncobj_func
);
744 set_current_state(TASK_INTERRUPTIBLE
);
747 for (i
= 0; i
< count
; ++i
) {
748 fence
= entries
[i
].fence
;
752 if (dma_fence_is_signaled(fence
) ||
753 (!entries
[i
].fence_cb
.func
&&
754 dma_fence_add_callback(fence
,
755 &entries
[i
].fence_cb
,
756 syncobj_wait_fence_func
))) {
757 /* The fence has been signaled */
758 if (flags
& DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
) {
768 if (signaled_count
== count
)
772 /* If we are doing a 0 timeout wait and we got
773 * here, then we just timed out.
779 ret
= schedule_timeout(ret
);
781 if (ret
> 0 && signal_pending(current
))
786 __set_current_state(TASK_RUNNING
);
789 for (i
= 0; i
< count
; ++i
) {
790 if (entries
[i
].syncobj_cb
.func
)
791 drm_syncobj_remove_callback(syncobjs
[i
],
792 &entries
[i
].syncobj_cb
);
793 if (entries
[i
].fence_cb
.func
)
794 dma_fence_remove_callback(entries
[i
].fence
,
795 &entries
[i
].fence_cb
);
796 dma_fence_put(entries
[i
].fence
);
804 * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
806 * @timeout_nsec: timeout nsec component in ns, 0 for poll
808 * Calculate the timeout in jiffies from an absolute time in sec/nsec.
810 static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec
)
812 ktime_t abs_timeout
, now
;
813 u64 timeout_ns
, timeout_jiffies64
;
815 /* make 0 timeout means poll - absolute 0 doesn't seem valid */
816 if (timeout_nsec
== 0)
819 abs_timeout
= ns_to_ktime(timeout_nsec
);
822 if (!ktime_after(abs_timeout
, now
))
825 timeout_ns
= ktime_to_ns(ktime_sub(abs_timeout
, now
));
827 timeout_jiffies64
= nsecs_to_jiffies64(timeout_ns
);
828 /* clamp timeout to avoid infinite timeout */
829 if (timeout_jiffies64
>= MAX_SCHEDULE_TIMEOUT
- 1)
830 return MAX_SCHEDULE_TIMEOUT
- 1;
832 return timeout_jiffies64
+ 1;
835 static int drm_syncobj_array_wait(struct drm_device
*dev
,
836 struct drm_file
*file_private
,
837 struct drm_syncobj_wait
*wait
,
838 struct drm_syncobj
**syncobjs
)
840 signed long timeout
= drm_timeout_abs_to_jiffies(wait
->timeout_nsec
);
844 ret
= drm_syncobj_array_wait_timeout(syncobjs
,
851 wait
->first_signaled
= first
;
858 static int drm_syncobj_array_find(struct drm_file
*file_private
,
859 void __user
*user_handles
,
860 uint32_t count_handles
,
861 struct drm_syncobj
***syncobjs_out
)
863 uint32_t i
, *handles
;
864 struct drm_syncobj
**syncobjs
;
867 handles
= kmalloc_array(count_handles
, sizeof(*handles
), GFP_KERNEL
);
871 if (copy_from_user(handles
, user_handles
,
872 sizeof(uint32_t) * count_handles
)) {
874 goto err_free_handles
;
877 syncobjs
= kmalloc_array(count_handles
, sizeof(*syncobjs
), GFP_KERNEL
);
878 if (syncobjs
== NULL
) {
880 goto err_free_handles
;
883 for (i
= 0; i
< count_handles
; i
++) {
884 syncobjs
[i
] = drm_syncobj_find(file_private
, handles
[i
]);
887 goto err_put_syncobjs
;
892 *syncobjs_out
= syncobjs
;
897 drm_syncobj_put(syncobjs
[i
]);
905 static void drm_syncobj_array_free(struct drm_syncobj
**syncobjs
,
909 for (i
= 0; i
< count
; i
++)
910 drm_syncobj_put(syncobjs
[i
]);
915 drm_syncobj_wait_ioctl(struct drm_device
*dev
, void *data
,
916 struct drm_file
*file_private
)
919 struct drm_syncobj_wait
*args
= data
;
920 struct drm_syncobj
**syncobjs
;
923 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
926 if (args
->flags
& ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
|
927 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
))
930 if (args
->count_handles
== 0)
933 ret
= drm_syncobj_array_find(file_private
,
934 u64_to_user_ptr(args
->handles
),
940 ret
= drm_syncobj_array_wait(dev
, file_private
,
943 drm_syncobj_array_free(syncobjs
, args
->count_handles
);
951 drm_syncobj_reset_ioctl(struct drm_device
*dev
, void *data
,
952 struct drm_file
*file_private
)
954 struct drm_syncobj_array
*args
= data
;
955 struct drm_syncobj
**syncobjs
;
959 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
965 if (args
->count_handles
== 0)
968 ret
= drm_syncobj_array_find(file_private
,
969 u64_to_user_ptr(args
->handles
),
975 for (i
= 0; i
< args
->count_handles
; i
++)
976 drm_syncobj_replace_fence(syncobjs
[i
], NULL
);
978 drm_syncobj_array_free(syncobjs
, args
->count_handles
);
984 drm_syncobj_signal_ioctl(struct drm_device
*dev
, void *data
,
985 struct drm_file
*file_private
)
987 struct drm_syncobj_array
*args
= data
;
988 struct drm_syncobj
**syncobjs
;
992 if (!drm_core_check_feature(dev
, DRIVER_SYNCOBJ
))
998 if (args
->count_handles
== 0)
1001 ret
= drm_syncobj_array_find(file_private
,
1002 u64_to_user_ptr(args
->handles
),
1003 args
->count_handles
,
1008 for (i
= 0; i
< args
->count_handles
; i
++) {
1009 ret
= drm_syncobj_assign_null_handle(syncobjs
[i
]);
1014 drm_syncobj_array_free(syncobjs
, args
->count_handles
);