]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/drm_syncobj.c
udmabuf: fix error code in map_udmabuf()
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / drm_syncobj.c
CommitLineData
e9083420
DA
1/*
2 * Copyright 2017 Red Hat
5e60a10e
DA
3 * Parts ported from amdgpu (fence wait code).
4 * Copyright 2016 Advanced Micro Devices, Inc.
e9083420
DA
5 *
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:
12 *
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
15 * Software.
16 *
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
23 * IN THE SOFTWARE.
24 *
25 * Authors:
26 *
27 */
28
29/**
30 * DOC: Overview
31 *
924fe8df
DV
32 * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are
33 * persistent objects that contain an optional fence. The fence can be updated
34 * with a new fence, or be NULL.
e9083420 35 *
5e60a10e
DA
36 * syncobj's can be waited upon, where it will wait for the underlying
37 * fence.
38 *
e9083420
DA
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.
41 *
42 * Their primary use-case is to implement Vulkan fences and semaphores.
43 *
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.
47 */
48
49#include <drm/drmP.h>
50#include <linux/file.h>
51#include <linux/fs.h>
52#include <linux/anon_inodes.h>
3ee45a3b 53#include <linux/sync_file.h>
e7aca503 54#include <linux/sched/signal.h>
e9083420
DA
55
56#include "drm_internal.h"
57#include <drm/drm_syncobj.h>
58
e28bd101
CZ
59struct drm_syncobj_stub_fence {
60 struct dma_fence base;
61 spinlock_t lock;
62};
63
64static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence)
65{
66 return "syncobjstub";
67}
68
69static bool drm_syncobj_stub_fence_enable_signaling(struct dma_fence *fence)
70{
71 return !dma_fence_is_signaled(fence);
72}
73
74static void drm_syncobj_stub_fence_release(struct dma_fence *f)
75{
76 kfree(f);
77}
78static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
79 .get_driver_name = drm_syncobj_stub_fence_get_name,
80 .get_timeline_name = drm_syncobj_stub_fence_get_name,
81 .enable_signaling = drm_syncobj_stub_fence_enable_signaling,
82 .release = drm_syncobj_stub_fence_release,
83};
84
85
e9083420
DA
86/**
87 * drm_syncobj_find - lookup and reference a sync object.
88 * @file_private: drm file private pointer
89 * @handle: sync object handle to lookup.
90 *
924fe8df
DV
91 * Returns a reference to the syncobj pointed to by handle or NULL. The
92 * reference must be released by calling drm_syncobj_put().
e9083420
DA
93 */
94struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
95 u32 handle)
96{
97 struct drm_syncobj *syncobj;
98
99 spin_lock(&file_private->syncobj_table_lock);
100
101 /* Check if we currently have a reference on the object */
102 syncobj = idr_find(&file_private->syncobj_idr, handle);
103 if (syncobj)
104 drm_syncobj_get(syncobj);
105
106 spin_unlock(&file_private->syncobj_table_lock);
107
108 return syncobj;
109}
110EXPORT_SYMBOL(drm_syncobj_find);
111
9c19fb10
JE
112static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
113 struct drm_syncobj_cb *cb,
114 drm_syncobj_func_t func)
115{
116 cb->func = func;
117 list_add_tail(&cb->node, &syncobj->cb_list);
118}
119
e7aca503
JE
120static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
121 struct dma_fence **fence,
122 struct drm_syncobj_cb *cb,
123 drm_syncobj_func_t func)
124{
125 int ret;
126
127 *fence = drm_syncobj_fence_get(syncobj);
128 if (*fence)
129 return 1;
130
131 spin_lock(&syncobj->lock);
132 /* We've already tried once to get a fence and failed. Now that we
133 * have the lock, try one more time just to be sure we don't add a
134 * callback when a fence has already been set.
135 */
136 if (syncobj->fence) {
563eaf53
VS
137 *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
138 lockdep_is_held(&syncobj->lock)));
e7aca503
JE
139 ret = 1;
140 } else {
141 *fence = NULL;
142 drm_syncobj_add_callback_locked(syncobj, cb, func);
143 ret = 0;
144 }
145 spin_unlock(&syncobj->lock);
146
147 return ret;
148}
149
9c19fb10
JE
150void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
151 struct drm_syncobj_cb *cb,
152 drm_syncobj_func_t func)
153{
154 spin_lock(&syncobj->lock);
155 drm_syncobj_add_callback_locked(syncobj, cb, func);
156 spin_unlock(&syncobj->lock);
157}
9c19fb10 158
9c19fb10
JE
159void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
160 struct drm_syncobj_cb *cb)
161{
162 spin_lock(&syncobj->lock);
163 list_del_init(&cb->node);
164 spin_unlock(&syncobj->lock);
165}
9c19fb10 166
e9083420
DA
167/**
168 * drm_syncobj_replace_fence - replace fence in a sync object.
e9083420 169 * @syncobj: Sync object to replace fence in
9a09a423 170 * @point: timeline point
e9083420
DA
171 * @fence: fence to install in sync file.
172 *
9a09a423 173 * This replaces the fence on a sync object, or a timeline point fence.
e9083420 174 */
00fc2c26 175void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
9a09a423 176 u64 point,
e9083420
DA
177 struct dma_fence *fence)
178{
00fc2c26 179 struct dma_fence *old_fence;
9c19fb10 180 struct drm_syncobj_cb *cur, *tmp;
e9083420
DA
181
182 if (fence)
183 dma_fence_get(fence);
9c19fb10
JE
184
185 spin_lock(&syncobj->lock);
186
563eaf53
VS
187 old_fence = rcu_dereference_protected(syncobj->fence,
188 lockdep_is_held(&syncobj->lock));
189 rcu_assign_pointer(syncobj->fence, fence);
9c19fb10
JE
190
191 if (fence != old_fence) {
192 list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
193 list_del_init(&cur->node);
194 cur->func(syncobj, cur);
195 }
196 }
197
198 spin_unlock(&syncobj->lock);
e9083420
DA
199
200 dma_fence_put(old_fence);
201}
202EXPORT_SYMBOL(drm_syncobj_replace_fence);
203
1fc08218
JE
204static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
205{
e28bd101 206 struct drm_syncobj_stub_fence *fence;
1fc08218
JE
207 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
208 if (fence == NULL)
209 return -ENOMEM;
210
211 spin_lock_init(&fence->lock);
e28bd101 212 dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops,
1fc08218
JE
213 &fence->lock, 0, 0);
214 dma_fence_signal(&fence->base);
215
9a09a423 216 drm_syncobj_replace_fence(syncobj, 0, &fence->base);
1fc08218
JE
217
218 dma_fence_put(&fence->base);
219
220 return 0;
221}
222
924fe8df
DV
223/**
224 * drm_syncobj_find_fence - lookup and reference the fence in a sync object
225 * @file_private: drm file private pointer
226 * @handle: sync object handle to lookup.
0a6730ea 227 * @point: timeline point
924fe8df
DV
228 * @fence: out parameter for the fence
229 *
230 * This is just a convenience function that combines drm_syncobj_find() and
231 * drm_syncobj_fence_get().
232 *
233 * Returns 0 on success or a negative error value on failure. On success @fence
234 * contains a reference to the fence, which must be released by calling
235 * dma_fence_put().
236 */
afaf5923 237int drm_syncobj_find_fence(struct drm_file *file_private,
0a6730ea 238 u32 handle, u64 point,
afaf5923 239 struct dma_fence **fence)
e9083420
DA
240{
241 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
242 int ret = 0;
243
244 if (!syncobj)
245 return -ENOENT;
246
309a5482 247 *fence = drm_syncobj_fence_get(syncobj);
e9083420
DA
248 if (!*fence) {
249 ret = -EINVAL;
250 }
251 drm_syncobj_put(syncobj);
252 return ret;
253}
afaf5923 254EXPORT_SYMBOL(drm_syncobj_find_fence);
e9083420
DA
255
256/**
257 * drm_syncobj_free - free a sync object.
258 * @kref: kref to free.
259 *
260 * Only to be called from kref_put in drm_syncobj_put.
261 */
262void drm_syncobj_free(struct kref *kref)
263{
264 struct drm_syncobj *syncobj = container_of(kref,
265 struct drm_syncobj,
266 refcount);
9a09a423 267 drm_syncobj_replace_fence(syncobj, 0, NULL);
e9083420
DA
268 kfree(syncobj);
269}
270EXPORT_SYMBOL(drm_syncobj_free);
271
1321fd2c
MO
272/**
273 * drm_syncobj_create - create a new syncobj
274 * @out_syncobj: returned syncobj
275 * @flags: DRM_SYNCOBJ_* flags
276 * @fence: if non-NULL, the syncobj will represent this fence
924fe8df
DV
277 *
278 * This is the first function to create a sync object. After creating, drivers
279 * probably want to make it available to userspace, either through
280 * drm_syncobj_get_handle() or drm_syncobj_get_fd().
281 *
282 * Returns 0 on success or a negative error value on failure.
1321fd2c
MO
283 */
284int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
285 struct dma_fence *fence)
e9083420
DA
286{
287 int ret;
288 struct drm_syncobj *syncobj;
289
290 syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
291 if (!syncobj)
292 return -ENOMEM;
293
294 kref_init(&syncobj->refcount);
9c19fb10
JE
295 INIT_LIST_HEAD(&syncobj->cb_list);
296 spin_lock_init(&syncobj->lock);
e9083420 297
1fc08218
JE
298 if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
299 ret = drm_syncobj_assign_null_handle(syncobj);
300 if (ret < 0) {
301 drm_syncobj_put(syncobj);
302 return ret;
303 }
304 }
305
1321fd2c 306 if (fence)
9a09a423 307 drm_syncobj_replace_fence(syncobj, 0, fence);
1321fd2c
MO
308
309 *out_syncobj = syncobj;
310 return 0;
311}
312EXPORT_SYMBOL(drm_syncobj_create);
313
314/**
315 * drm_syncobj_get_handle - get a handle from a syncobj
924fe8df
DV
316 * @file_private: drm file private pointer
317 * @syncobj: Sync object to export
318 * @handle: out parameter with the new handle
319 *
320 * Exports a sync object created with drm_syncobj_create() as a handle on
321 * @file_private to userspace.
322 *
323 * Returns 0 on success or a negative error value on failure.
1321fd2c
MO
324 */
325int drm_syncobj_get_handle(struct drm_file *file_private,
326 struct drm_syncobj *syncobj, u32 *handle)
327{
328 int ret;
329
330 /* take a reference to put in the idr */
331 drm_syncobj_get(syncobj);
332
e9083420
DA
333 idr_preload(GFP_KERNEL);
334 spin_lock(&file_private->syncobj_table_lock);
335 ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
336 spin_unlock(&file_private->syncobj_table_lock);
337
338 idr_preload_end();
339
340 if (ret < 0) {
341 drm_syncobj_put(syncobj);
342 return ret;
343 }
344
345 *handle = ret;
346 return 0;
347}
1321fd2c
MO
348EXPORT_SYMBOL(drm_syncobj_get_handle);
349
350static int drm_syncobj_create_as_handle(struct drm_file *file_private,
351 u32 *handle, uint32_t flags)
352{
353 int ret;
354 struct drm_syncobj *syncobj;
355
356 ret = drm_syncobj_create(&syncobj, flags, NULL);
357 if (ret)
358 return ret;
359
360 ret = drm_syncobj_get_handle(file_private, syncobj, handle);
361 drm_syncobj_put(syncobj);
362 return ret;
363}
e9083420
DA
364
365static int drm_syncobj_destroy(struct drm_file *file_private,
366 u32 handle)
367{
368 struct drm_syncobj *syncobj;
369
370 spin_lock(&file_private->syncobj_table_lock);
371 syncobj = idr_remove(&file_private->syncobj_idr, handle);
372 spin_unlock(&file_private->syncobj_table_lock);
373
374 if (!syncobj)
375 return -EINVAL;
376
377 drm_syncobj_put(syncobj);
378 return 0;
379}
380
381static int drm_syncobj_file_release(struct inode *inode, struct file *file)
382{
383 struct drm_syncobj *syncobj = file->private_data;
384
385 drm_syncobj_put(syncobj);
386 return 0;
387}
388
389static const struct file_operations drm_syncobj_file_fops = {
390 .release = drm_syncobj_file_release,
391};
392
924fe8df
DV
393/**
394 * drm_syncobj_get_fd - get a file descriptor from a syncobj
395 * @syncobj: Sync object to export
396 * @p_fd: out parameter with the new file descriptor
397 *
398 * Exports a sync object created with drm_syncobj_create() as a file descriptor.
399 *
400 * Returns 0 on success or a negative error value on failure.
401 */
684fd0af 402int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
e9083420 403{
e7cdf5c8 404 struct file *file;
e9083420
DA
405 int fd;
406
e9083420 407 fd = get_unused_fd_flags(O_CLOEXEC);
684fd0af 408 if (fd < 0)
e9083420 409 return fd;
e9083420 410
e7cdf5c8
CW
411 file = anon_inode_getfile("syncobj_file",
412 &drm_syncobj_file_fops,
413 syncobj, 0);
414 if (IS_ERR(file)) {
415 put_unused_fd(fd);
416 return PTR_ERR(file);
e9083420 417 }
e7cdf5c8
CW
418
419 drm_syncobj_get(syncobj);
420 fd_install(fd, file);
421
e9083420
DA
422 *p_fd = fd;
423 return 0;
684fd0af
MO
424}
425EXPORT_SYMBOL(drm_syncobj_get_fd);
426
427static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
428 u32 handle, int *p_fd)
429{
430 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
431 int ret;
432
433 if (!syncobj)
434 return -EINVAL;
435
436 ret = drm_syncobj_get_fd(syncobj, p_fd);
e9083420
DA
437 drm_syncobj_put(syncobj);
438 return ret;
439}
440
e9083420
DA
441static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
442 int fd, u32 *handle)
443{
e7cdf5c8
CW
444 struct drm_syncobj *syncobj;
445 struct file *file;
e9083420
DA
446 int ret;
447
e7cdf5c8
CW
448 file = fget(fd);
449 if (!file)
e9083420
DA
450 return -EINVAL;
451
e7cdf5c8
CW
452 if (file->f_op != &drm_syncobj_file_fops) {
453 fput(file);
454 return -EINVAL;
455 }
456
e9083420 457 /* take a reference to put in the idr */
e7cdf5c8 458 syncobj = file->private_data;
e9083420
DA
459 drm_syncobj_get(syncobj);
460
461 idr_preload(GFP_KERNEL);
462 spin_lock(&file_private->syncobj_table_lock);
463 ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
464 spin_unlock(&file_private->syncobj_table_lock);
465 idr_preload_end();
466
e7cdf5c8
CW
467 if (ret > 0) {
468 *handle = ret;
469 ret = 0;
470 } else
471 drm_syncobj_put(syncobj);
472
473 fput(file);
474 return ret;
e9083420
DA
475}
476
a32c94af
VS
477static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
478 int fd, int handle)
3ee45a3b
DA
479{
480 struct dma_fence *fence = sync_file_get_fence(fd);
481 struct drm_syncobj *syncobj;
482
483 if (!fence)
484 return -EINVAL;
485
486 syncobj = drm_syncobj_find(file_private, handle);
487 if (!syncobj) {
488 dma_fence_put(fence);
489 return -ENOENT;
490 }
491
9a09a423 492 drm_syncobj_replace_fence(syncobj, 0, fence);
3ee45a3b
DA
493 dma_fence_put(fence);
494 drm_syncobj_put(syncobj);
495 return 0;
496}
497
a32c94af
VS
498static int drm_syncobj_export_sync_file(struct drm_file *file_private,
499 int handle, int *p_fd)
3ee45a3b
DA
500{
501 int ret;
502 struct dma_fence *fence;
503 struct sync_file *sync_file;
504 int fd = get_unused_fd_flags(O_CLOEXEC);
505
506 if (fd < 0)
507 return fd;
508
0a6730ea 509 ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
3ee45a3b
DA
510 if (ret)
511 goto err_put_fd;
512
513 sync_file = sync_file_create(fence);
514
515 dma_fence_put(fence);
516
517 if (!sync_file) {
518 ret = -EINVAL;
519 goto err_put_fd;
520 }
521
522 fd_install(fd, sync_file->file);
523
524 *p_fd = fd;
525 return 0;
526err_put_fd:
527 put_unused_fd(fd);
528 return ret;
529}
e9083420
DA
530/**
531 * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time
e9083420
DA
532 * @file_private: drm file-private structure to set up
533 *
534 * Called at device open time, sets up the structure for handling refcounting
535 * of sync objects.
536 */
537void
538drm_syncobj_open(struct drm_file *file_private)
539{
e86584c5 540 idr_init_base(&file_private->syncobj_idr, 1);
e9083420
DA
541 spin_lock_init(&file_private->syncobj_table_lock);
542}
543
544static int
545drm_syncobj_release_handle(int id, void *ptr, void *data)
546{
547 struct drm_syncobj *syncobj = ptr;
548
549 drm_syncobj_put(syncobj);
550 return 0;
551}
552
553/**
554 * drm_syncobj_release - release file-private sync object resources
e9083420
DA
555 * @file_private: drm file-private structure to clean up
556 *
557 * Called at close time when the filp is going away.
558 *
559 * Releases any remaining references on objects by this filp.
560 */
561void
562drm_syncobj_release(struct drm_file *file_private)
563{
564 idr_for_each(&file_private->syncobj_idr,
565 &drm_syncobj_release_handle, file_private);
566 idr_destroy(&file_private->syncobj_idr);
567}
568
569int
570drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
571 struct drm_file *file_private)
572{
573 struct drm_syncobj_create *args = data;
574
575 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
576 return -ENODEV;
577
578 /* no valid flags yet */
1fc08218 579 if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
e9083420
DA
580 return -EINVAL;
581
1321fd2c
MO
582 return drm_syncobj_create_as_handle(file_private,
583 &args->handle, args->flags);
e9083420
DA
584}
585
586int
587drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data,
588 struct drm_file *file_private)
589{
590 struct drm_syncobj_destroy *args = data;
591
592 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
593 return -ENODEV;
594
595 /* make sure padding is empty */
596 if (args->pad)
597 return -EINVAL;
598 return drm_syncobj_destroy(file_private, args->handle);
599}
600
601int
602drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
603 struct drm_file *file_private)
604{
605 struct drm_syncobj_handle *args = data;
606
607 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
608 return -ENODEV;
609
3ee45a3b 610 if (args->pad)
e9083420
DA
611 return -EINVAL;
612
3ee45a3b
DA
613 if (args->flags != 0 &&
614 args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
615 return -EINVAL;
616
617 if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
618 return drm_syncobj_export_sync_file(file_private, args->handle,
619 &args->fd);
620
e9083420
DA
621 return drm_syncobj_handle_to_fd(file_private, args->handle,
622 &args->fd);
623}
624
625int
626drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
627 struct drm_file *file_private)
628{
629 struct drm_syncobj_handle *args = data;
630
631 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
632 return -ENODEV;
633
3ee45a3b
DA
634 if (args->pad)
635 return -EINVAL;
636
637 if (args->flags != 0 &&
638 args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
e9083420
DA
639 return -EINVAL;
640
3ee45a3b
DA
641 if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
642 return drm_syncobj_import_sync_file_fence(file_private,
643 args->fd,
644 args->handle);
645
e9083420
DA
646 return drm_syncobj_fd_to_handle(file_private, args->fd,
647 &args->handle);
648}
5e60a10e 649
e7aca503
JE
650struct syncobj_wait_entry {
651 struct task_struct *task;
652 struct dma_fence *fence;
653 struct dma_fence_cb fence_cb;
654 struct drm_syncobj_cb syncobj_cb;
655};
656
657static void syncobj_wait_fence_func(struct dma_fence *fence,
658 struct dma_fence_cb *cb)
659{
660 struct syncobj_wait_entry *wait =
661 container_of(cb, struct syncobj_wait_entry, fence_cb);
662
663 wake_up_process(wait->task);
664}
665
666static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
667 struct drm_syncobj_cb *cb)
668{
669 struct syncobj_wait_entry *wait =
670 container_of(cb, struct syncobj_wait_entry, syncobj_cb);
671
672 /* This happens inside the syncobj lock */
563eaf53
VS
673 wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
674 lockdep_is_held(&syncobj->lock)));
e7aca503
JE
675 wake_up_process(wait->task);
676}
677
678static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
679 uint32_t count,
680 uint32_t flags,
681 signed long timeout,
682 uint32_t *idx)
683{
684 struct syncobj_wait_entry *entries;
685 struct dma_fence *fence;
686 signed long ret;
687 uint32_t signaled_count, i;
688
689 entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
690 if (!entries)
691 return -ENOMEM;
692
693 /* Walk the list of sync objects and initialize entries. We do
694 * this up-front so that we can properly return -EINVAL if there is
695 * a syncobj with a missing fence and then never have the chance of
696 * returning -EINVAL again.
697 */
698 signaled_count = 0;
699 for (i = 0; i < count; ++i) {
700 entries[i].task = current;
701 entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
702 if (!entries[i].fence) {
703 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
704 continue;
705 } else {
706 ret = -EINVAL;
707 goto cleanup_entries;
708 }
709 }
710
711 if (dma_fence_is_signaled(entries[i].fence)) {
712 if (signaled_count == 0 && idx)
713 *idx = i;
714 signaled_count++;
715 }
716 }
717
718 /* Initialize ret to the max of timeout and 1. That way, the
719 * default return value indicates a successful wait and not a
720 * timeout.
721 */
722 ret = max_t(signed long, timeout, 1);
723
724 if (signaled_count == count ||
725 (signaled_count > 0 &&
726 !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
727 goto cleanup_entries;
728
729 /* There's a very annoying laxness in the dma_fence API here, in
730 * that backends are not required to automatically report when a
731 * fence is signaled prior to fence->ops->enable_signaling() being
732 * called. So here if we fail to match signaled_count, we need to
733 * fallthough and try a 0 timeout wait!
734 */
735
736 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
737 for (i = 0; i < count; ++i) {
738 drm_syncobj_fence_get_or_add_callback(syncobjs[i],
739 &entries[i].fence,
740 &entries[i].syncobj_cb,
741 syncobj_wait_syncobj_func);
742 }
743 }
744
745 do {
746 set_current_state(TASK_INTERRUPTIBLE);
747
748 signaled_count = 0;
749 for (i = 0; i < count; ++i) {
750 fence = entries[i].fence;
751 if (!fence)
752 continue;
753
754 if (dma_fence_is_signaled(fence) ||
755 (!entries[i].fence_cb.func &&
756 dma_fence_add_callback(fence,
757 &entries[i].fence_cb,
758 syncobj_wait_fence_func))) {
759 /* The fence has been signaled */
760 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) {
761 signaled_count++;
762 } else {
763 if (idx)
764 *idx = i;
765 goto done_waiting;
766 }
767 }
768 }
769
770 if (signaled_count == count)
771 goto done_waiting;
772
773 if (timeout == 0) {
774 /* If we are doing a 0 timeout wait and we got
775 * here, then we just timed out.
776 */
777 ret = 0;
778 goto done_waiting;
779 }
780
781 ret = schedule_timeout(ret);
782
783 if (ret > 0 && signal_pending(current))
784 ret = -ERESTARTSYS;
785 } while (ret > 0);
786
787done_waiting:
788 __set_current_state(TASK_RUNNING);
789
790cleanup_entries:
791 for (i = 0; i < count; ++i) {
792 if (entries[i].syncobj_cb.func)
793 drm_syncobj_remove_callback(syncobjs[i],
794 &entries[i].syncobj_cb);
795 if (entries[i].fence_cb.func)
796 dma_fence_remove_callback(entries[i].fence,
797 &entries[i].fence_cb);
798 dma_fence_put(entries[i].fence);
799 }
800 kfree(entries);
801
802 return ret;
803}
804
5e60a10e
DA
805/**
806 * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
807 *
808 * @timeout_nsec: timeout nsec component in ns, 0 for poll
809 *
810 * Calculate the timeout in jiffies from an absolute time in sec/nsec.
811 */
812static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
813{
814 ktime_t abs_timeout, now;
815 u64 timeout_ns, timeout_jiffies64;
816
817 /* make 0 timeout means poll - absolute 0 doesn't seem valid */
818 if (timeout_nsec == 0)
819 return 0;
820
821 abs_timeout = ns_to_ktime(timeout_nsec);
822 now = ktime_get();
823
824 if (!ktime_after(abs_timeout, now))
825 return 0;
826
827 timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
828
829 timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
830 /* clamp timeout to avoid infinite timeout */
831 if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
832 return MAX_SCHEDULE_TIMEOUT - 1;
833
834 return timeout_jiffies64 + 1;
835}
836
e7aca503
JE
837static int drm_syncobj_array_wait(struct drm_device *dev,
838 struct drm_file *file_private,
839 struct drm_syncobj_wait *wait,
840 struct drm_syncobj **syncobjs)
5e60a10e
DA
841{
842 signed long timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
843 signed long ret = 0;
844 uint32_t first = ~0;
845
e7aca503
JE
846 ret = drm_syncobj_array_wait_timeout(syncobjs,
847 wait->count_handles,
848 wait->flags,
849 timeout, &first);
5e60a10e
DA
850 if (ret < 0)
851 return ret;
852
853 wait->first_signaled = first;
854 if (ret == 0)
855 return -ETIME;
856 return 0;
857}
858
3e6fb72d 859static int drm_syncobj_array_find(struct drm_file *file_private,
9e554462
VS
860 void __user *user_handles,
861 uint32_t count_handles,
3e6fb72d 862 struct drm_syncobj ***syncobjs_out)
5e60a10e 863{
3e6fb72d 864 uint32_t i, *handles;
e7aca503 865 struct drm_syncobj **syncobjs;
3e6fb72d 866 int ret;
5e60a10e 867
3e6fb72d 868 handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
5e60a10e
DA
869 if (handles == NULL)
870 return -ENOMEM;
871
3e6fb72d
JE
872 if (copy_from_user(handles, user_handles,
873 sizeof(uint32_t) * count_handles)) {
5e60a10e
DA
874 ret = -EFAULT;
875 goto err_free_handles;
876 }
877
3e6fb72d
JE
878 syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
879 if (syncobjs == NULL) {
5e60a10e
DA
880 ret = -ENOMEM;
881 goto err_free_handles;
882 }
883
3e6fb72d 884 for (i = 0; i < count_handles; i++) {
e7aca503
JE
885 syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
886 if (!syncobjs[i]) {
887 ret = -ENOENT;
3e6fb72d 888 goto err_put_syncobjs;
e7aca503 889 }
5e60a10e
DA
890 }
891
3e6fb72d
JE
892 kfree(handles);
893 *syncobjs_out = syncobjs;
894 return 0;
5e60a10e 895
3e6fb72d 896err_put_syncobjs:
e7aca503
JE
897 while (i-- > 0)
898 drm_syncobj_put(syncobjs[i]);
899 kfree(syncobjs);
5e60a10e
DA
900err_free_handles:
901 kfree(handles);
902
903 return ret;
904}
3e6fb72d
JE
905
906static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
907 uint32_t count)
908{
909 uint32_t i;
910 for (i = 0; i < count; i++)
911 drm_syncobj_put(syncobjs[i]);
912 kfree(syncobjs);
913}
914
915int
916drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
917 struct drm_file *file_private)
918{
919 struct drm_syncobj_wait *args = data;
920 struct drm_syncobj **syncobjs;
921 int ret = 0;
922
923 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
924 return -ENODEV;
925
926 if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
927 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
928 return -EINVAL;
929
930 if (args->count_handles == 0)
931 return -EINVAL;
932
933 ret = drm_syncobj_array_find(file_private,
934 u64_to_user_ptr(args->handles),
935 args->count_handles,
936 &syncobjs);
937 if (ret < 0)
938 return ret;
939
940 ret = drm_syncobj_array_wait(dev, file_private,
941 args, syncobjs);
942
943 drm_syncobj_array_free(syncobjs, args->count_handles);
944
945 return ret;
946}
aa4035d2
JE
947
948int
949drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
950 struct drm_file *file_private)
951{
952 struct drm_syncobj_array *args = data;
953 struct drm_syncobj **syncobjs;
954 uint32_t i;
955 int ret;
956
957 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
958 return -ENODEV;
959
960 if (args->pad != 0)
961 return -EINVAL;
962
963 if (args->count_handles == 0)
964 return -EINVAL;
965
966 ret = drm_syncobj_array_find(file_private,
967 u64_to_user_ptr(args->handles),
968 args->count_handles,
969 &syncobjs);
970 if (ret < 0)
971 return ret;
972
973 for (i = 0; i < args->count_handles; i++)
9a09a423 974 drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
aa4035d2
JE
975
976 drm_syncobj_array_free(syncobjs, args->count_handles);
977
978 return 0;
979}
ffa9443f
JE
980
981int
982drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
983 struct drm_file *file_private)
984{
985 struct drm_syncobj_array *args = data;
986 struct drm_syncobj **syncobjs;
987 uint32_t i;
988 int ret;
989
990 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
991 return -ENODEV;
992
993 if (args->pad != 0)
994 return -EINVAL;
995
996 if (args->count_handles == 0)
997 return -EINVAL;
998
999 ret = drm_syncobj_array_find(file_private,
1000 u64_to_user_ptr(args->handles),
1001 args->count_handles,
1002 &syncobjs);
1003 if (ret < 0)
1004 return ret;
1005
1006 for (i = 0; i < args->count_handles; i++) {
1007 ret = drm_syncobj_assign_null_handle(syncobjs[i]);
1008 if (ret < 0)
1009 break;
1010 }
1011
1012 drm_syncobj_array_free(syncobjs, args->count_handles);
1013
1014 return ret;
1015}