Line data Source code
1 : /*
2 : * Copyright 2017 Red Hat
3 : * Parts ported from amdgpu (fence wait code).
4 : * Copyright 2016 Advanced Micro Devices, Inc.
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 : *
32 : * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a
33 : * container for a synchronization primitive which can be used by userspace
34 : * to explicitly synchronize GPU commands, can be shared between userspace
35 : * processes, and can be shared between different DRM drivers.
36 : * Their primary use-case is to implement Vulkan fences and semaphores.
37 : * The syncobj userspace API provides ioctls for several operations:
38 : *
39 : * - Creation and destruction of syncobjs
40 : * - Import and export of syncobjs to/from a syncobj file descriptor
41 : * - Import and export a syncobj's underlying fence to/from a sync file
42 : * - Reset a syncobj (set its fence to NULL)
43 : * - Signal a syncobj (set a trivially signaled fence)
44 : * - Wait for a syncobj's fence to appear and be signaled
45 : *
46 : * The syncobj userspace API also provides operations to manipulate a syncobj
47 : * in terms of a timeline of struct &dma_fence_chain rather than a single
48 : * struct &dma_fence, through the following operations:
49 : *
50 : * - Signal a given point on the timeline
51 : * - Wait for a given point to appear and/or be signaled
52 : * - Import and export from/to a given point of a timeline
53 : *
54 : * At it's core, a syncobj is simply a wrapper around a pointer to a struct
55 : * &dma_fence which may be NULL.
56 : * When a syncobj is first created, its pointer is either NULL or a pointer
57 : * to an already signaled fence depending on whether the
58 : * &DRM_SYNCOBJ_CREATE_SIGNALED flag is passed to
59 : * &DRM_IOCTL_SYNCOBJ_CREATE.
60 : *
61 : * If the syncobj is considered as a binary (its state is either signaled or
62 : * unsignaled) primitive, when GPU work is enqueued in a DRM driver to signal
63 : * the syncobj, the syncobj's fence is replaced with a fence which will be
64 : * signaled by the completion of that work.
65 : * If the syncobj is considered as a timeline primitive, when GPU work is
66 : * enqueued in a DRM driver to signal the a given point of the syncobj, a new
67 : * struct &dma_fence_chain pointing to the DRM driver's fence and also
68 : * pointing to the previous fence that was in the syncobj. The new struct
69 : * &dma_fence_chain fence replace the syncobj's fence and will be signaled by
70 : * completion of the DRM driver's work and also any work associated with the
71 : * fence previously in the syncobj.
72 : *
73 : * When GPU work which waits on a syncobj is enqueued in a DRM driver, at the
74 : * time the work is enqueued, it waits on the syncobj's fence before
75 : * submitting the work to hardware. That fence is either :
76 : *
77 : * - The syncobj's current fence if the syncobj is considered as a binary
78 : * primitive.
79 : * - The struct &dma_fence associated with a given point if the syncobj is
80 : * considered as a timeline primitive.
81 : *
82 : * If the syncobj's fence is NULL or not present in the syncobj's timeline,
83 : * the enqueue operation is expected to fail.
84 : *
85 : * With binary syncobj, all manipulation of the syncobjs's fence happens in
86 : * terms of the current fence at the time the ioctl is called by userspace
87 : * regardless of whether that operation is an immediate host-side operation
88 : * (signal or reset) or or an operation which is enqueued in some driver
89 : * queue. &DRM_IOCTL_SYNCOBJ_RESET and &DRM_IOCTL_SYNCOBJ_SIGNAL can be used
90 : * to manipulate a syncobj from the host by resetting its pointer to NULL or
91 : * setting its pointer to a fence which is already signaled.
92 : *
93 : * With a timeline syncobj, all manipulation of the synobj's fence happens in
94 : * terms of a u64 value referring to point in the timeline. See
95 : * dma_fence_chain_find_seqno() to see how a given point is found in the
96 : * timeline.
97 : *
98 : * Note that applications should be careful to always use timeline set of
99 : * ioctl() when dealing with syncobj considered as timeline. Using a binary
100 : * set of ioctl() with a syncobj considered as timeline could result incorrect
101 : * synchronization. The use of binary syncobj is supported through the
102 : * timeline set of ioctl() by using a point value of 0, this will reproduce
103 : * the behavior of the binary set of ioctl() (for example replace the
104 : * syncobj's fence when signaling).
105 : *
106 : *
107 : * Host-side wait on syncobjs
108 : * --------------------------
109 : *
110 : * &DRM_IOCTL_SYNCOBJ_WAIT takes an array of syncobj handles and does a
111 : * host-side wait on all of the syncobj fences simultaneously.
112 : * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL is set, the wait ioctl will wait on
113 : * all of the syncobj fences to be signaled before it returns.
114 : * Otherwise, it returns once at least one syncobj fence has been signaled
115 : * and the index of a signaled fence is written back to the client.
116 : *
117 : * Unlike the enqueued GPU work dependencies which fail if they see a NULL
118 : * fence in a syncobj, if &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is set,
119 : * the host-side wait will first wait for the syncobj to receive a non-NULL
120 : * fence and then wait on that fence.
121 : * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is not set and any one of the
122 : * syncobjs in the array has a NULL fence, -EINVAL will be returned.
123 : * Assuming the syncobj starts off with a NULL fence, this allows a client
124 : * to do a host wait in one thread (or process) which waits on GPU work
125 : * submitted in another thread (or process) without having to manually
126 : * synchronize between the two.
127 : * This requirement is inherited from the Vulkan fence API.
128 : *
129 : * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj
130 : * handles as well as an array of u64 points and does a host-side wait on all
131 : * of syncobj fences at the given points simultaneously.
132 : *
133 : * &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT also adds the ability to wait for a given
134 : * fence to materialize on the timeline without waiting for the fence to be
135 : * signaled by using the &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE flag. This
136 : * requirement is inherited from the wait-before-signal behavior required by
137 : * the Vulkan timeline semaphore API.
138 : *
139 : * Alternatively, &DRM_IOCTL_SYNCOBJ_EVENTFD can be used to wait without
140 : * blocking: an eventfd will be signaled when the syncobj is. This is useful to
141 : * integrate the wait in an event loop.
142 : *
143 : *
144 : * Import/export of syncobjs
145 : * -------------------------
146 : *
147 : * &DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE and &DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
148 : * provide two mechanisms for import/export of syncobjs.
149 : *
150 : * The first lets the client import or export an entire syncobj to a file
151 : * descriptor.
152 : * These fd's are opaque and have no other use case, except passing the
153 : * syncobj between processes.
154 : * All exported file descriptors and any syncobj handles created as a
155 : * result of importing those file descriptors own a reference to the
156 : * same underlying struct &drm_syncobj and the syncobj can be used
157 : * persistently across all the processes with which it is shared.
158 : * The syncobj is freed only once the last reference is dropped.
159 : * Unlike dma-buf, importing a syncobj creates a new handle (with its own
160 : * reference) for every import instead of de-duplicating.
161 : * The primary use-case of this persistent import/export is for shared
162 : * Vulkan fences and semaphores.
163 : *
164 : * The second import/export mechanism, which is indicated by
165 : * &DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE or
166 : * &DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE lets the client
167 : * import/export the syncobj's current fence from/to a &sync_file.
168 : * When a syncobj is exported to a sync file, that sync file wraps the
169 : * sycnobj's fence at the time of export and any later signal or reset
170 : * operations on the syncobj will not affect the exported sync file.
171 : * When a sync file is imported into a syncobj, the syncobj's fence is set
172 : * to the fence wrapped by that sync file.
173 : * Because sync files are immutable, resetting or signaling the syncobj
174 : * will not affect any sync files whose fences have been imported into the
175 : * syncobj.
176 : *
177 : *
178 : * Import/export of timeline points in timeline syncobjs
179 : * -----------------------------------------------------
180 : *
181 : * &DRM_IOCTL_SYNCOBJ_TRANSFER provides a mechanism to transfer a struct
182 : * &dma_fence_chain of a syncobj at a given u64 point to another u64 point
183 : * into another syncobj.
184 : *
185 : * Note that if you want to transfer a struct &dma_fence_chain from a given
186 : * point on a timeline syncobj from/into a binary syncobj, you can use the
187 : * point 0 to mean take/replace the fence in the syncobj.
188 : */
189 :
190 : #include <linux/anon_inodes.h>
191 : #include <linux/dma-fence-unwrap.h>
192 : #include <linux/eventfd.h>
193 : #include <linux/file.h>
194 : #include <linux/fs.h>
195 : #include <linux/sched/signal.h>
196 : #include <linux/sync_file.h>
197 : #include <linux/uaccess.h>
198 :
199 : #include <drm/drm.h>
200 : #include <drm/drm_drv.h>
201 : #include <drm/drm_file.h>
202 : #include <drm/drm_gem.h>
203 : #include <drm/drm_print.h>
204 : #include <drm/drm_syncobj.h>
205 : #include <drm/drm_utils.h>
206 :
207 : #include "drm_internal.h"
208 :
209 : struct syncobj_wait_entry {
210 : struct list_head node;
211 : struct task_struct *task;
212 : struct dma_fence *fence;
213 : struct dma_fence_cb fence_cb;
214 : u64 point;
215 : };
216 :
217 : static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
218 : struct syncobj_wait_entry *wait);
219 :
220 : struct syncobj_eventfd_entry {
221 : struct list_head node;
222 : struct dma_fence *fence;
223 : struct dma_fence_cb fence_cb;
224 : struct drm_syncobj *syncobj;
225 : struct eventfd_ctx *ev_fd_ctx;
226 : u64 point;
227 : u32 flags;
228 : };
229 :
230 : static void
231 : syncobj_eventfd_entry_func(struct drm_syncobj *syncobj,
232 : struct syncobj_eventfd_entry *entry);
233 :
234 : /**
235 : * drm_syncobj_find - lookup and reference a sync object.
236 : * @file_private: drm file private pointer
237 : * @handle: sync object handle to lookup.
238 : *
239 : * Returns a reference to the syncobj pointed to by handle or NULL. The
240 : * reference must be released by calling drm_syncobj_put().
241 : */
242 0 : struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
243 : u32 handle)
244 : {
245 : struct drm_syncobj *syncobj;
246 :
247 0 : spin_lock(&file_private->syncobj_table_lock);
248 :
249 : /* Check if we currently have a reference on the object */
250 0 : syncobj = idr_find(&file_private->syncobj_idr, handle);
251 0 : if (syncobj)
252 : drm_syncobj_get(syncobj);
253 :
254 0 : spin_unlock(&file_private->syncobj_table_lock);
255 :
256 0 : return syncobj;
257 : }
258 : EXPORT_SYMBOL(drm_syncobj_find);
259 :
260 0 : static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
261 : struct syncobj_wait_entry *wait)
262 : {
263 : struct dma_fence *fence;
264 :
265 0 : if (wait->fence)
266 0 : return;
267 :
268 0 : spin_lock(&syncobj->lock);
269 : /* We've already tried once to get a fence and failed. Now that we
270 : * have the lock, try one more time just to be sure we don't add a
271 : * callback when a fence has already been set.
272 : */
273 0 : fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
274 0 : if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
275 0 : dma_fence_put(fence);
276 0 : list_add_tail(&wait->node, &syncobj->cb_list);
277 0 : } else if (!fence) {
278 0 : wait->fence = dma_fence_get_stub();
279 : } else {
280 0 : wait->fence = fence;
281 : }
282 0 : spin_unlock(&syncobj->lock);
283 : }
284 :
285 : static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
286 : struct syncobj_wait_entry *wait)
287 : {
288 0 : if (!wait->node.next)
289 : return;
290 :
291 0 : spin_lock(&syncobj->lock);
292 0 : list_del_init(&wait->node);
293 0 : spin_unlock(&syncobj->lock);
294 : }
295 :
296 : static void
297 0 : syncobj_eventfd_entry_free(struct syncobj_eventfd_entry *entry)
298 : {
299 0 : eventfd_ctx_put(entry->ev_fd_ctx);
300 0 : dma_fence_put(entry->fence);
301 : /* This happens either inside the syncobj lock, or after the node has
302 : * already been removed from the list.
303 : */
304 0 : list_del(&entry->node);
305 0 : kfree(entry);
306 0 : }
307 :
308 : static void
309 : drm_syncobj_add_eventfd(struct drm_syncobj *syncobj,
310 : struct syncobj_eventfd_entry *entry)
311 : {
312 0 : spin_lock(&syncobj->lock);
313 0 : list_add_tail(&entry->node, &syncobj->ev_fd_list);
314 0 : syncobj_eventfd_entry_func(syncobj, entry);
315 0 : spin_unlock(&syncobj->lock);
316 : }
317 :
318 : /**
319 : * drm_syncobj_add_point - add new timeline point to the syncobj
320 : * @syncobj: sync object to add timeline point do
321 : * @chain: chain node to use to add the point
322 : * @fence: fence to encapsulate in the chain node
323 : * @point: sequence number to use for the point
324 : *
325 : * Add the chain node as new timeline point to the syncobj.
326 : */
327 0 : void drm_syncobj_add_point(struct drm_syncobj *syncobj,
328 : struct dma_fence_chain *chain,
329 : struct dma_fence *fence,
330 : uint64_t point)
331 : {
332 : struct syncobj_wait_entry *wait_cur, *wait_tmp;
333 : struct syncobj_eventfd_entry *ev_fd_cur, *ev_fd_tmp;
334 : struct dma_fence *prev;
335 :
336 0 : dma_fence_get(fence);
337 :
338 0 : spin_lock(&syncobj->lock);
339 :
340 0 : prev = drm_syncobj_fence_get(syncobj);
341 : /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
342 0 : if (prev && prev->seqno >= point)
343 0 : DRM_DEBUG("You are adding an unorder point to timeline!\n");
344 0 : dma_fence_chain_init(chain, prev, fence, point);
345 0 : rcu_assign_pointer(syncobj->fence, &chain->base);
346 :
347 0 : list_for_each_entry_safe(wait_cur, wait_tmp, &syncobj->cb_list, node)
348 0 : syncobj_wait_syncobj_func(syncobj, wait_cur);
349 0 : list_for_each_entry_safe(ev_fd_cur, ev_fd_tmp, &syncobj->ev_fd_list, node)
350 0 : syncobj_eventfd_entry_func(syncobj, ev_fd_cur);
351 0 : spin_unlock(&syncobj->lock);
352 :
353 : /* Walk the chain once to trigger garbage collection */
354 0 : dma_fence_chain_for_each(fence, prev);
355 0 : dma_fence_put(prev);
356 0 : }
357 : EXPORT_SYMBOL(drm_syncobj_add_point);
358 :
359 : /**
360 : * drm_syncobj_replace_fence - replace fence in a sync object.
361 : * @syncobj: Sync object to replace fence in
362 : * @fence: fence to install in sync file.
363 : *
364 : * This replaces the fence on a sync object.
365 : */
366 0 : void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
367 : struct dma_fence *fence)
368 : {
369 : struct dma_fence *old_fence;
370 : struct syncobj_wait_entry *wait_cur, *wait_tmp;
371 : struct syncobj_eventfd_entry *ev_fd_cur, *ev_fd_tmp;
372 :
373 0 : if (fence)
374 : dma_fence_get(fence);
375 :
376 0 : spin_lock(&syncobj->lock);
377 :
378 0 : old_fence = rcu_dereference_protected(syncobj->fence,
379 : lockdep_is_held(&syncobj->lock));
380 0 : rcu_assign_pointer(syncobj->fence, fence);
381 :
382 0 : if (fence != old_fence) {
383 0 : list_for_each_entry_safe(wait_cur, wait_tmp, &syncobj->cb_list, node)
384 0 : syncobj_wait_syncobj_func(syncobj, wait_cur);
385 0 : list_for_each_entry_safe(ev_fd_cur, ev_fd_tmp, &syncobj->ev_fd_list, node)
386 0 : syncobj_eventfd_entry_func(syncobj, ev_fd_cur);
387 : }
388 :
389 0 : spin_unlock(&syncobj->lock);
390 :
391 0 : dma_fence_put(old_fence);
392 0 : }
393 : EXPORT_SYMBOL(drm_syncobj_replace_fence);
394 :
395 : /**
396 : * drm_syncobj_assign_null_handle - assign a stub fence to the sync object
397 : * @syncobj: sync object to assign the fence on
398 : *
399 : * Assign a already signaled stub fence to the sync object.
400 : */
401 0 : static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
402 : {
403 0 : struct dma_fence *fence = dma_fence_allocate_private_stub(ktime_get());
404 :
405 0 : if (!fence)
406 : return -ENOMEM;
407 :
408 0 : drm_syncobj_replace_fence(syncobj, fence);
409 0 : dma_fence_put(fence);
410 0 : return 0;
411 : }
412 :
413 : /* 5s default for wait submission */
414 : #define DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT 5000000000ULL
415 : /**
416 : * drm_syncobj_find_fence - lookup and reference the fence in a sync object
417 : * @file_private: drm file private pointer
418 : * @handle: sync object handle to lookup.
419 : * @point: timeline point
420 : * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
421 : * @fence: out parameter for the fence
422 : *
423 : * This is just a convenience function that combines drm_syncobj_find() and
424 : * drm_syncobj_fence_get().
425 : *
426 : * Returns 0 on success or a negative error value on failure. On success @fence
427 : * contains a reference to the fence, which must be released by calling
428 : * dma_fence_put().
429 : */
430 0 : int drm_syncobj_find_fence(struct drm_file *file_private,
431 : u32 handle, u64 point, u64 flags,
432 : struct dma_fence **fence)
433 : {
434 0 : struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
435 : struct syncobj_wait_entry wait;
436 0 : u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
437 : int ret;
438 :
439 0 : if (!syncobj)
440 : return -ENOENT;
441 :
442 : /* Waiting for userspace with locks help is illegal cause that can
443 : * trivial deadlock with page faults for example. Make lockdep complain
444 : * about it early on.
445 : */
446 0 : if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
447 : might_sleep();
448 : lockdep_assert_none_held_once();
449 : }
450 :
451 0 : *fence = drm_syncobj_fence_get(syncobj);
452 :
453 0 : if (*fence) {
454 0 : ret = dma_fence_chain_find_seqno(fence, point);
455 0 : if (!ret) {
456 : /* If the requested seqno is already signaled
457 : * drm_syncobj_find_fence may return a NULL
458 : * fence. To make sure the recipient gets
459 : * signalled, use a new fence instead.
460 : */
461 0 : if (!*fence)
462 0 : *fence = dma_fence_get_stub();
463 :
464 : goto out;
465 : }
466 0 : dma_fence_put(*fence);
467 : } else {
468 : ret = -EINVAL;
469 : }
470 :
471 0 : if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
472 : goto out;
473 :
474 0 : memset(&wait, 0, sizeof(wait));
475 0 : wait.task = current;
476 0 : wait.point = point;
477 0 : drm_syncobj_fence_add_wait(syncobj, &wait);
478 :
479 : do {
480 0 : set_current_state(TASK_INTERRUPTIBLE);
481 0 : if (wait.fence) {
482 : ret = 0;
483 : break;
484 : }
485 0 : if (timeout == 0) {
486 : ret = -ETIME;
487 : break;
488 : }
489 :
490 0 : if (signal_pending(current)) {
491 : ret = -ERESTARTSYS;
492 : break;
493 : }
494 :
495 0 : timeout = schedule_timeout(timeout);
496 : } while (1);
497 :
498 0 : __set_current_state(TASK_RUNNING);
499 0 : *fence = wait.fence;
500 :
501 0 : if (wait.node.next)
502 0 : drm_syncobj_remove_wait(syncobj, &wait);
503 :
504 : out:
505 0 : drm_syncobj_put(syncobj);
506 :
507 0 : return ret;
508 : }
509 : EXPORT_SYMBOL(drm_syncobj_find_fence);
510 :
511 : /**
512 : * drm_syncobj_free - free a sync object.
513 : * @kref: kref to free.
514 : *
515 : * Only to be called from kref_put in drm_syncobj_put.
516 : */
517 0 : void drm_syncobj_free(struct kref *kref)
518 : {
519 0 : struct drm_syncobj *syncobj = container_of(kref,
520 : struct drm_syncobj,
521 : refcount);
522 : struct syncobj_eventfd_entry *ev_fd_cur, *ev_fd_tmp;
523 :
524 0 : drm_syncobj_replace_fence(syncobj, NULL);
525 :
526 0 : list_for_each_entry_safe(ev_fd_cur, ev_fd_tmp, &syncobj->ev_fd_list, node)
527 0 : syncobj_eventfd_entry_free(ev_fd_cur);
528 :
529 0 : kfree(syncobj);
530 0 : }
531 : EXPORT_SYMBOL(drm_syncobj_free);
532 :
533 : /**
534 : * drm_syncobj_create - create a new syncobj
535 : * @out_syncobj: returned syncobj
536 : * @flags: DRM_SYNCOBJ_* flags
537 : * @fence: if non-NULL, the syncobj will represent this fence
538 : *
539 : * This is the first function to create a sync object. After creating, drivers
540 : * probably want to make it available to userspace, either through
541 : * drm_syncobj_get_handle() or drm_syncobj_get_fd().
542 : *
543 : * Returns 0 on success or a negative error value on failure.
544 : */
545 0 : int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
546 : struct dma_fence *fence)
547 : {
548 : int ret;
549 : struct drm_syncobj *syncobj;
550 :
551 0 : syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
552 0 : if (!syncobj)
553 : return -ENOMEM;
554 :
555 0 : kref_init(&syncobj->refcount);
556 0 : INIT_LIST_HEAD(&syncobj->cb_list);
557 0 : INIT_LIST_HEAD(&syncobj->ev_fd_list);
558 0 : spin_lock_init(&syncobj->lock);
559 :
560 0 : if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
561 0 : ret = drm_syncobj_assign_null_handle(syncobj);
562 0 : if (ret < 0) {
563 0 : drm_syncobj_put(syncobj);
564 0 : return ret;
565 : }
566 : }
567 :
568 0 : if (fence)
569 0 : drm_syncobj_replace_fence(syncobj, fence);
570 :
571 0 : *out_syncobj = syncobj;
572 0 : return 0;
573 : }
574 : EXPORT_SYMBOL(drm_syncobj_create);
575 :
576 : /**
577 : * drm_syncobj_get_handle - get a handle from a syncobj
578 : * @file_private: drm file private pointer
579 : * @syncobj: Sync object to export
580 : * @handle: out parameter with the new handle
581 : *
582 : * Exports a sync object created with drm_syncobj_create() as a handle on
583 : * @file_private to userspace.
584 : *
585 : * Returns 0 on success or a negative error value on failure.
586 : */
587 0 : int drm_syncobj_get_handle(struct drm_file *file_private,
588 : struct drm_syncobj *syncobj, u32 *handle)
589 : {
590 : int ret;
591 :
592 : /* take a reference to put in the idr */
593 0 : drm_syncobj_get(syncobj);
594 :
595 0 : idr_preload(GFP_KERNEL);
596 0 : spin_lock(&file_private->syncobj_table_lock);
597 0 : ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
598 0 : spin_unlock(&file_private->syncobj_table_lock);
599 :
600 : idr_preload_end();
601 :
602 0 : if (ret < 0) {
603 0 : drm_syncobj_put(syncobj);
604 0 : return ret;
605 : }
606 :
607 0 : *handle = ret;
608 0 : return 0;
609 : }
610 : EXPORT_SYMBOL(drm_syncobj_get_handle);
611 :
612 0 : static int drm_syncobj_create_as_handle(struct drm_file *file_private,
613 : u32 *handle, uint32_t flags)
614 : {
615 : int ret;
616 : struct drm_syncobj *syncobj;
617 :
618 0 : ret = drm_syncobj_create(&syncobj, flags, NULL);
619 0 : if (ret)
620 : return ret;
621 :
622 0 : ret = drm_syncobj_get_handle(file_private, syncobj, handle);
623 0 : drm_syncobj_put(syncobj);
624 0 : return ret;
625 : }
626 :
627 0 : static int drm_syncobj_destroy(struct drm_file *file_private,
628 : u32 handle)
629 : {
630 : struct drm_syncobj *syncobj;
631 :
632 0 : spin_lock(&file_private->syncobj_table_lock);
633 0 : syncobj = idr_remove(&file_private->syncobj_idr, handle);
634 0 : spin_unlock(&file_private->syncobj_table_lock);
635 :
636 0 : if (!syncobj)
637 : return -EINVAL;
638 :
639 0 : drm_syncobj_put(syncobj);
640 0 : return 0;
641 : }
642 :
643 0 : static int drm_syncobj_file_release(struct inode *inode, struct file *file)
644 : {
645 0 : struct drm_syncobj *syncobj = file->private_data;
646 :
647 0 : drm_syncobj_put(syncobj);
648 0 : return 0;
649 : }
650 :
651 : static const struct file_operations drm_syncobj_file_fops = {
652 : .release = drm_syncobj_file_release,
653 : };
654 :
655 : /**
656 : * drm_syncobj_get_fd - get a file descriptor from a syncobj
657 : * @syncobj: Sync object to export
658 : * @p_fd: out parameter with the new file descriptor
659 : *
660 : * Exports a sync object created with drm_syncobj_create() as a file descriptor.
661 : *
662 : * Returns 0 on success or a negative error value on failure.
663 : */
664 0 : int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
665 : {
666 : struct file *file;
667 : int fd;
668 :
669 0 : fd = get_unused_fd_flags(O_CLOEXEC);
670 0 : if (fd < 0)
671 : return fd;
672 :
673 0 : file = anon_inode_getfile("syncobj_file",
674 : &drm_syncobj_file_fops,
675 : syncobj, 0);
676 0 : if (IS_ERR(file)) {
677 0 : put_unused_fd(fd);
678 0 : return PTR_ERR(file);
679 : }
680 :
681 0 : drm_syncobj_get(syncobj);
682 0 : fd_install(fd, file);
683 :
684 0 : *p_fd = fd;
685 0 : return 0;
686 : }
687 : EXPORT_SYMBOL(drm_syncobj_get_fd);
688 :
689 0 : static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
690 : u32 handle, int *p_fd)
691 : {
692 0 : struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
693 : int ret;
694 :
695 0 : if (!syncobj)
696 : return -EINVAL;
697 :
698 0 : ret = drm_syncobj_get_fd(syncobj, p_fd);
699 0 : drm_syncobj_put(syncobj);
700 0 : return ret;
701 : }
702 :
703 0 : static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
704 : int fd, u32 *handle)
705 : {
706 : struct drm_syncobj *syncobj;
707 0 : struct fd f = fdget(fd);
708 : int ret;
709 :
710 0 : if (!f.file)
711 : return -EINVAL;
712 :
713 0 : if (f.file->f_op != &drm_syncobj_file_fops) {
714 0 : fdput(f);
715 : return -EINVAL;
716 : }
717 :
718 : /* take a reference to put in the idr */
719 0 : syncobj = f.file->private_data;
720 0 : drm_syncobj_get(syncobj);
721 :
722 0 : idr_preload(GFP_KERNEL);
723 0 : spin_lock(&file_private->syncobj_table_lock);
724 0 : ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
725 0 : spin_unlock(&file_private->syncobj_table_lock);
726 : idr_preload_end();
727 :
728 0 : if (ret > 0) {
729 0 : *handle = ret;
730 0 : ret = 0;
731 : } else
732 : drm_syncobj_put(syncobj);
733 :
734 0 : fdput(f);
735 : return ret;
736 : }
737 :
738 0 : static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
739 : int fd, int handle)
740 : {
741 0 : struct dma_fence *fence = sync_file_get_fence(fd);
742 : struct drm_syncobj *syncobj;
743 :
744 0 : if (!fence)
745 : return -EINVAL;
746 :
747 0 : syncobj = drm_syncobj_find(file_private, handle);
748 0 : if (!syncobj) {
749 0 : dma_fence_put(fence);
750 0 : return -ENOENT;
751 : }
752 :
753 0 : drm_syncobj_replace_fence(syncobj, fence);
754 0 : dma_fence_put(fence);
755 0 : drm_syncobj_put(syncobj);
756 0 : return 0;
757 : }
758 :
759 0 : static int drm_syncobj_export_sync_file(struct drm_file *file_private,
760 : int handle, int *p_fd)
761 : {
762 : int ret;
763 : struct dma_fence *fence;
764 : struct sync_file *sync_file;
765 0 : int fd = get_unused_fd_flags(O_CLOEXEC);
766 :
767 0 : if (fd < 0)
768 : return fd;
769 :
770 0 : ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
771 0 : if (ret)
772 : goto err_put_fd;
773 :
774 0 : sync_file = sync_file_create(fence);
775 :
776 0 : dma_fence_put(fence);
777 :
778 0 : if (!sync_file) {
779 : ret = -EINVAL;
780 : goto err_put_fd;
781 : }
782 :
783 0 : fd_install(fd, sync_file->file);
784 :
785 0 : *p_fd = fd;
786 0 : return 0;
787 : err_put_fd:
788 0 : put_unused_fd(fd);
789 0 : return ret;
790 : }
791 : /**
792 : * drm_syncobj_open - initializes syncobj file-private structures at devnode open time
793 : * @file_private: drm file-private structure to set up
794 : *
795 : * Called at device open time, sets up the structure for handling refcounting
796 : * of sync objects.
797 : */
798 : void
799 0 : drm_syncobj_open(struct drm_file *file_private)
800 : {
801 0 : idr_init_base(&file_private->syncobj_idr, 1);
802 0 : spin_lock_init(&file_private->syncobj_table_lock);
803 0 : }
804 :
805 : static int
806 0 : drm_syncobj_release_handle(int id, void *ptr, void *data)
807 : {
808 0 : struct drm_syncobj *syncobj = ptr;
809 :
810 0 : drm_syncobj_put(syncobj);
811 0 : return 0;
812 : }
813 :
814 : /**
815 : * drm_syncobj_release - release file-private sync object resources
816 : * @file_private: drm file-private structure to clean up
817 : *
818 : * Called at close time when the filp is going away.
819 : *
820 : * Releases any remaining references on objects by this filp.
821 : */
822 : void
823 0 : drm_syncobj_release(struct drm_file *file_private)
824 : {
825 0 : idr_for_each(&file_private->syncobj_idr,
826 : &drm_syncobj_release_handle, file_private);
827 0 : idr_destroy(&file_private->syncobj_idr);
828 0 : }
829 :
830 : int
831 0 : drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
832 : struct drm_file *file_private)
833 : {
834 0 : struct drm_syncobj_create *args = data;
835 :
836 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
837 : return -EOPNOTSUPP;
838 :
839 : /* no valid flags yet */
840 0 : if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
841 : return -EINVAL;
842 :
843 0 : return drm_syncobj_create_as_handle(file_private,
844 0 : &args->handle, args->flags);
845 : }
846 :
847 : int
848 0 : drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data,
849 : struct drm_file *file_private)
850 : {
851 0 : struct drm_syncobj_destroy *args = data;
852 :
853 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
854 : return -EOPNOTSUPP;
855 :
856 : /* make sure padding is empty */
857 0 : if (args->pad)
858 : return -EINVAL;
859 0 : return drm_syncobj_destroy(file_private, args->handle);
860 : }
861 :
862 : int
863 0 : drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
864 : struct drm_file *file_private)
865 : {
866 0 : struct drm_syncobj_handle *args = data;
867 :
868 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
869 : return -EOPNOTSUPP;
870 :
871 0 : if (args->pad)
872 : return -EINVAL;
873 :
874 0 : if (args->flags != 0 &&
875 : args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
876 : return -EINVAL;
877 :
878 0 : if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
879 0 : return drm_syncobj_export_sync_file(file_private, args->handle,
880 0 : &args->fd);
881 :
882 0 : return drm_syncobj_handle_to_fd(file_private, args->handle,
883 0 : &args->fd);
884 : }
885 :
886 : int
887 0 : drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
888 : struct drm_file *file_private)
889 : {
890 0 : struct drm_syncobj_handle *args = data;
891 :
892 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
893 : return -EOPNOTSUPP;
894 :
895 0 : if (args->pad)
896 : return -EINVAL;
897 :
898 0 : if (args->flags != 0 &&
899 : args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
900 : return -EINVAL;
901 :
902 0 : if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
903 0 : return drm_syncobj_import_sync_file_fence(file_private,
904 : args->fd,
905 0 : args->handle);
906 :
907 0 : return drm_syncobj_fd_to_handle(file_private, args->fd,
908 0 : &args->handle);
909 : }
910 :
911 0 : static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
912 : struct drm_syncobj_transfer *args)
913 : {
914 0 : struct drm_syncobj *timeline_syncobj = NULL;
915 : struct dma_fence *fence, *tmp;
916 : struct dma_fence_chain *chain;
917 : int ret;
918 :
919 0 : timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle);
920 0 : if (!timeline_syncobj) {
921 : return -ENOENT;
922 : }
923 0 : ret = drm_syncobj_find_fence(file_private, args->src_handle,
924 0 : args->src_point, args->flags,
925 : &tmp);
926 0 : if (ret)
927 : goto err_put_timeline;
928 :
929 0 : fence = dma_fence_unwrap_merge(tmp);
930 0 : dma_fence_put(tmp);
931 0 : if (!fence) {
932 : ret = -ENOMEM;
933 : goto err_put_timeline;
934 : }
935 :
936 0 : chain = dma_fence_chain_alloc();
937 0 : if (!chain) {
938 : ret = -ENOMEM;
939 : goto err_free_fence;
940 : }
941 :
942 0 : drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point);
943 : err_free_fence:
944 : dma_fence_put(fence);
945 : err_put_timeline:
946 0 : drm_syncobj_put(timeline_syncobj);
947 :
948 0 : return ret;
949 : }
950 :
951 : static int
952 0 : drm_syncobj_transfer_to_binary(struct drm_file *file_private,
953 : struct drm_syncobj_transfer *args)
954 : {
955 0 : struct drm_syncobj *binary_syncobj = NULL;
956 : struct dma_fence *fence;
957 : int ret;
958 :
959 0 : binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
960 0 : if (!binary_syncobj)
961 : return -ENOENT;
962 0 : ret = drm_syncobj_find_fence(file_private, args->src_handle,
963 0 : args->src_point, args->flags, &fence);
964 0 : if (ret)
965 : goto err;
966 0 : drm_syncobj_replace_fence(binary_syncobj, fence);
967 0 : dma_fence_put(fence);
968 : err:
969 0 : drm_syncobj_put(binary_syncobj);
970 :
971 0 : return ret;
972 : }
973 : int
974 0 : drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
975 : struct drm_file *file_private)
976 : {
977 0 : struct drm_syncobj_transfer *args = data;
978 : int ret;
979 :
980 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
981 : return -EOPNOTSUPP;
982 :
983 0 : if (args->pad)
984 : return -EINVAL;
985 :
986 0 : if (args->dst_point)
987 0 : ret = drm_syncobj_transfer_to_timeline(file_private, args);
988 : else
989 0 : ret = drm_syncobj_transfer_to_binary(file_private, args);
990 :
991 : return ret;
992 : }
993 :
994 0 : static void syncobj_wait_fence_func(struct dma_fence *fence,
995 : struct dma_fence_cb *cb)
996 : {
997 0 : struct syncobj_wait_entry *wait =
998 0 : container_of(cb, struct syncobj_wait_entry, fence_cb);
999 :
1000 0 : wake_up_process(wait->task);
1001 0 : }
1002 :
1003 0 : static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
1004 : struct syncobj_wait_entry *wait)
1005 : {
1006 : struct dma_fence *fence;
1007 :
1008 : /* This happens inside the syncobj lock */
1009 0 : fence = rcu_dereference_protected(syncobj->fence,
1010 : lockdep_is_held(&syncobj->lock));
1011 0 : dma_fence_get(fence);
1012 0 : if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
1013 0 : dma_fence_put(fence);
1014 0 : return;
1015 0 : } else if (!fence) {
1016 0 : wait->fence = dma_fence_get_stub();
1017 : } else {
1018 0 : wait->fence = fence;
1019 : }
1020 :
1021 0 : wake_up_process(wait->task);
1022 0 : list_del_init(&wait->node);
1023 : }
1024 :
1025 0 : static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
1026 : void __user *user_points,
1027 : uint32_t count,
1028 : uint32_t flags,
1029 : signed long timeout,
1030 : uint32_t *idx)
1031 : {
1032 : struct syncobj_wait_entry *entries;
1033 : struct dma_fence *fence;
1034 : uint64_t *points;
1035 : uint32_t signaled_count, i;
1036 :
1037 0 : if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
1038 : lockdep_assert_none_held_once();
1039 :
1040 0 : points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
1041 0 : if (points == NULL)
1042 : return -ENOMEM;
1043 :
1044 0 : if (!user_points) {
1045 0 : memset(points, 0, count * sizeof(uint64_t));
1046 :
1047 0 : } else if (copy_from_user(points, user_points,
1048 : sizeof(uint64_t) * count)) {
1049 : timeout = -EFAULT;
1050 : goto err_free_points;
1051 : }
1052 :
1053 0 : entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
1054 0 : if (!entries) {
1055 : timeout = -ENOMEM;
1056 : goto err_free_points;
1057 : }
1058 : /* Walk the list of sync objects and initialize entries. We do
1059 : * this up-front so that we can properly return -EINVAL if there is
1060 : * a syncobj with a missing fence and then never have the chance of
1061 : * returning -EINVAL again.
1062 : */
1063 : signaled_count = 0;
1064 0 : for (i = 0; i < count; ++i) {
1065 : struct dma_fence *fence;
1066 :
1067 0 : entries[i].task = current;
1068 0 : entries[i].point = points[i];
1069 0 : fence = drm_syncobj_fence_get(syncobjs[i]);
1070 0 : if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) {
1071 0 : dma_fence_put(fence);
1072 0 : if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
1073 0 : continue;
1074 : } else {
1075 0 : timeout = -EINVAL;
1076 0 : goto cleanup_entries;
1077 : }
1078 : }
1079 :
1080 0 : if (fence)
1081 0 : entries[i].fence = fence;
1082 : else
1083 0 : entries[i].fence = dma_fence_get_stub();
1084 :
1085 0 : if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
1086 0 : dma_fence_is_signaled(entries[i].fence)) {
1087 0 : if (signaled_count == 0 && idx)
1088 0 : *idx = i;
1089 0 : signaled_count++;
1090 : }
1091 : }
1092 :
1093 0 : if (signaled_count == count ||
1094 0 : (signaled_count > 0 &&
1095 0 : !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
1096 : goto cleanup_entries;
1097 :
1098 : /* There's a very annoying laxness in the dma_fence API here, in
1099 : * that backends are not required to automatically report when a
1100 : * fence is signaled prior to fence->ops->enable_signaling() being
1101 : * called. So here if we fail to match signaled_count, we need to
1102 : * fallthough and try a 0 timeout wait!
1103 : */
1104 :
1105 0 : if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
1106 0 : for (i = 0; i < count; ++i)
1107 0 : drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
1108 : }
1109 :
1110 : do {
1111 0 : set_current_state(TASK_INTERRUPTIBLE);
1112 :
1113 0 : signaled_count = 0;
1114 0 : for (i = 0; i < count; ++i) {
1115 0 : fence = entries[i].fence;
1116 0 : if (!fence)
1117 0 : continue;
1118 :
1119 0 : if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
1120 0 : dma_fence_is_signaled(fence) ||
1121 0 : (!entries[i].fence_cb.func &&
1122 0 : dma_fence_add_callback(fence,
1123 : &entries[i].fence_cb,
1124 : syncobj_wait_fence_func))) {
1125 : /* The fence has been signaled */
1126 0 : if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) {
1127 0 : signaled_count++;
1128 : } else {
1129 0 : if (idx)
1130 0 : *idx = i;
1131 : goto done_waiting;
1132 : }
1133 : }
1134 : }
1135 :
1136 0 : if (signaled_count == count)
1137 : goto done_waiting;
1138 :
1139 0 : if (timeout == 0) {
1140 : timeout = -ETIME;
1141 : goto done_waiting;
1142 : }
1143 :
1144 0 : if (signal_pending(current)) {
1145 : timeout = -ERESTARTSYS;
1146 : goto done_waiting;
1147 : }
1148 :
1149 0 : timeout = schedule_timeout(timeout);
1150 : } while (1);
1151 :
1152 : done_waiting:
1153 0 : __set_current_state(TASK_RUNNING);
1154 :
1155 : cleanup_entries:
1156 0 : for (i = 0; i < count; ++i) {
1157 0 : drm_syncobj_remove_wait(syncobjs[i], &entries[i]);
1158 0 : if (entries[i].fence_cb.func)
1159 0 : dma_fence_remove_callback(entries[i].fence,
1160 : &entries[i].fence_cb);
1161 0 : dma_fence_put(entries[i].fence);
1162 : }
1163 0 : kfree(entries);
1164 :
1165 : err_free_points:
1166 0 : kfree(points);
1167 :
1168 0 : return timeout;
1169 : }
1170 :
1171 : /**
1172 : * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
1173 : *
1174 : * @timeout_nsec: timeout nsec component in ns, 0 for poll
1175 : *
1176 : * Calculate the timeout in jiffies from an absolute time in sec/nsec.
1177 : */
1178 0 : signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
1179 : {
1180 : ktime_t abs_timeout, now;
1181 : u64 timeout_ns, timeout_jiffies64;
1182 :
1183 : /* make 0 timeout means poll - absolute 0 doesn't seem valid */
1184 0 : if (timeout_nsec == 0)
1185 : return 0;
1186 :
1187 0 : abs_timeout = ns_to_ktime(timeout_nsec);
1188 0 : now = ktime_get();
1189 :
1190 0 : if (!ktime_after(abs_timeout, now))
1191 : return 0;
1192 :
1193 0 : timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
1194 :
1195 0 : timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
1196 : /* clamp timeout to avoid infinite timeout */
1197 0 : if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
1198 : return MAX_SCHEDULE_TIMEOUT - 1;
1199 :
1200 0 : return timeout_jiffies64 + 1;
1201 : }
1202 : EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
1203 :
1204 0 : static int drm_syncobj_array_wait(struct drm_device *dev,
1205 : struct drm_file *file_private,
1206 : struct drm_syncobj_wait *wait,
1207 : struct drm_syncobj_timeline_wait *timeline_wait,
1208 : struct drm_syncobj **syncobjs, bool timeline)
1209 : {
1210 0 : signed long timeout = 0;
1211 0 : uint32_t first = ~0;
1212 :
1213 0 : if (!timeline) {
1214 0 : timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
1215 0 : timeout = drm_syncobj_array_wait_timeout(syncobjs,
1216 : NULL,
1217 : wait->count_handles,
1218 : wait->flags,
1219 : timeout, &first);
1220 0 : if (timeout < 0)
1221 0 : return timeout;
1222 0 : wait->first_signaled = first;
1223 : } else {
1224 0 : timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec);
1225 0 : timeout = drm_syncobj_array_wait_timeout(syncobjs,
1226 0 : u64_to_user_ptr(timeline_wait->points),
1227 : timeline_wait->count_handles,
1228 : timeline_wait->flags,
1229 : timeout, &first);
1230 0 : if (timeout < 0)
1231 0 : return timeout;
1232 0 : timeline_wait->first_signaled = first;
1233 : }
1234 : return 0;
1235 : }
1236 :
1237 0 : static int drm_syncobj_array_find(struct drm_file *file_private,
1238 : void __user *user_handles,
1239 : uint32_t count_handles,
1240 : struct drm_syncobj ***syncobjs_out)
1241 : {
1242 : uint32_t i, *handles;
1243 : struct drm_syncobj **syncobjs;
1244 : int ret;
1245 :
1246 0 : handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
1247 0 : if (handles == NULL)
1248 : return -ENOMEM;
1249 :
1250 0 : if (copy_from_user(handles, user_handles,
1251 : sizeof(uint32_t) * count_handles)) {
1252 : ret = -EFAULT;
1253 : goto err_free_handles;
1254 : }
1255 :
1256 0 : syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
1257 0 : if (syncobjs == NULL) {
1258 : ret = -ENOMEM;
1259 : goto err_free_handles;
1260 : }
1261 :
1262 0 : for (i = 0; i < count_handles; i++) {
1263 0 : syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
1264 0 : if (!syncobjs[i]) {
1265 : ret = -ENOENT;
1266 : goto err_put_syncobjs;
1267 : }
1268 : }
1269 :
1270 0 : kfree(handles);
1271 0 : *syncobjs_out = syncobjs;
1272 0 : return 0;
1273 :
1274 : err_put_syncobjs:
1275 0 : while (i-- > 0)
1276 0 : drm_syncobj_put(syncobjs[i]);
1277 0 : kfree(syncobjs);
1278 : err_free_handles:
1279 0 : kfree(handles);
1280 :
1281 0 : return ret;
1282 : }
1283 :
1284 0 : static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
1285 : uint32_t count)
1286 : {
1287 : uint32_t i;
1288 :
1289 0 : for (i = 0; i < count; i++)
1290 0 : drm_syncobj_put(syncobjs[i]);
1291 0 : kfree(syncobjs);
1292 0 : }
1293 :
1294 : int
1295 0 : drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
1296 : struct drm_file *file_private)
1297 : {
1298 0 : struct drm_syncobj_wait *args = data;
1299 : struct drm_syncobj **syncobjs;
1300 0 : int ret = 0;
1301 :
1302 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1303 : return -EOPNOTSUPP;
1304 :
1305 0 : if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
1306 : DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
1307 : return -EINVAL;
1308 :
1309 0 : if (args->count_handles == 0)
1310 : return -EINVAL;
1311 :
1312 0 : ret = drm_syncobj_array_find(file_private,
1313 0 : u64_to_user_ptr(args->handles),
1314 : args->count_handles,
1315 : &syncobjs);
1316 0 : if (ret < 0)
1317 : return ret;
1318 :
1319 0 : ret = drm_syncobj_array_wait(dev, file_private,
1320 : args, NULL, syncobjs, false);
1321 :
1322 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1323 :
1324 0 : return ret;
1325 : }
1326 :
1327 : int
1328 0 : drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
1329 : struct drm_file *file_private)
1330 : {
1331 0 : struct drm_syncobj_timeline_wait *args = data;
1332 : struct drm_syncobj **syncobjs;
1333 0 : int ret = 0;
1334 :
1335 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1336 : return -EOPNOTSUPP;
1337 :
1338 0 : if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
1339 : DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
1340 : DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
1341 : return -EINVAL;
1342 :
1343 0 : if (args->count_handles == 0)
1344 : return -EINVAL;
1345 :
1346 0 : ret = drm_syncobj_array_find(file_private,
1347 0 : u64_to_user_ptr(args->handles),
1348 : args->count_handles,
1349 : &syncobjs);
1350 0 : if (ret < 0)
1351 : return ret;
1352 :
1353 0 : ret = drm_syncobj_array_wait(dev, file_private,
1354 : NULL, args, syncobjs, true);
1355 :
1356 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1357 :
1358 0 : return ret;
1359 : }
1360 :
1361 0 : static void syncobj_eventfd_entry_fence_func(struct dma_fence *fence,
1362 : struct dma_fence_cb *cb)
1363 : {
1364 0 : struct syncobj_eventfd_entry *entry =
1365 0 : container_of(cb, struct syncobj_eventfd_entry, fence_cb);
1366 :
1367 0 : eventfd_signal(entry->ev_fd_ctx, 1);
1368 0 : syncobj_eventfd_entry_free(entry);
1369 0 : }
1370 :
1371 : static void
1372 0 : syncobj_eventfd_entry_func(struct drm_syncobj *syncobj,
1373 : struct syncobj_eventfd_entry *entry)
1374 : {
1375 : int ret;
1376 : struct dma_fence *fence;
1377 :
1378 : /* This happens inside the syncobj lock */
1379 0 : fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
1380 0 : ret = dma_fence_chain_find_seqno(&fence, entry->point);
1381 0 : if (ret != 0 || !fence) {
1382 0 : dma_fence_put(fence);
1383 0 : return;
1384 : }
1385 :
1386 0 : list_del_init(&entry->node);
1387 0 : entry->fence = fence;
1388 :
1389 0 : if (entry->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) {
1390 0 : eventfd_signal(entry->ev_fd_ctx, 1);
1391 0 : syncobj_eventfd_entry_free(entry);
1392 : } else {
1393 0 : ret = dma_fence_add_callback(fence, &entry->fence_cb,
1394 : syncobj_eventfd_entry_fence_func);
1395 0 : if (ret == -ENOENT) {
1396 0 : eventfd_signal(entry->ev_fd_ctx, 1);
1397 0 : syncobj_eventfd_entry_free(entry);
1398 : }
1399 : }
1400 : }
1401 :
1402 : int
1403 0 : drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data,
1404 : struct drm_file *file_private)
1405 : {
1406 0 : struct drm_syncobj_eventfd *args = data;
1407 : struct drm_syncobj *syncobj;
1408 : struct eventfd_ctx *ev_fd_ctx;
1409 : struct syncobj_eventfd_entry *entry;
1410 :
1411 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1412 : return -EOPNOTSUPP;
1413 :
1414 0 : if (args->flags & ~DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)
1415 : return -EINVAL;
1416 :
1417 0 : if (args->pad)
1418 : return -EINVAL;
1419 :
1420 0 : syncobj = drm_syncobj_find(file_private, args->handle);
1421 0 : if (!syncobj)
1422 : return -ENOENT;
1423 :
1424 0 : ev_fd_ctx = eventfd_ctx_fdget(args->fd);
1425 0 : if (IS_ERR(ev_fd_ctx))
1426 0 : return PTR_ERR(ev_fd_ctx);
1427 :
1428 0 : entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1429 0 : if (!entry) {
1430 0 : eventfd_ctx_put(ev_fd_ctx);
1431 0 : return -ENOMEM;
1432 : }
1433 0 : entry->syncobj = syncobj;
1434 0 : entry->ev_fd_ctx = ev_fd_ctx;
1435 0 : entry->point = args->point;
1436 0 : entry->flags = args->flags;
1437 :
1438 0 : drm_syncobj_add_eventfd(syncobj, entry);
1439 0 : drm_syncobj_put(syncobj);
1440 :
1441 0 : return 0;
1442 : }
1443 :
1444 : int
1445 0 : drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
1446 : struct drm_file *file_private)
1447 : {
1448 0 : struct drm_syncobj_array *args = data;
1449 : struct drm_syncobj **syncobjs;
1450 : uint32_t i;
1451 : int ret;
1452 :
1453 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1454 : return -EOPNOTSUPP;
1455 :
1456 0 : if (args->pad != 0)
1457 : return -EINVAL;
1458 :
1459 0 : if (args->count_handles == 0)
1460 : return -EINVAL;
1461 :
1462 0 : ret = drm_syncobj_array_find(file_private,
1463 0 : u64_to_user_ptr(args->handles),
1464 : args->count_handles,
1465 : &syncobjs);
1466 0 : if (ret < 0)
1467 : return ret;
1468 :
1469 0 : for (i = 0; i < args->count_handles; i++)
1470 0 : drm_syncobj_replace_fence(syncobjs[i], NULL);
1471 :
1472 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1473 :
1474 0 : return 0;
1475 : }
1476 :
1477 : int
1478 0 : drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
1479 : struct drm_file *file_private)
1480 : {
1481 0 : struct drm_syncobj_array *args = data;
1482 : struct drm_syncobj **syncobjs;
1483 : uint32_t i;
1484 : int ret;
1485 :
1486 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1487 : return -EOPNOTSUPP;
1488 :
1489 0 : if (args->pad != 0)
1490 : return -EINVAL;
1491 :
1492 0 : if (args->count_handles == 0)
1493 : return -EINVAL;
1494 :
1495 0 : ret = drm_syncobj_array_find(file_private,
1496 0 : u64_to_user_ptr(args->handles),
1497 : args->count_handles,
1498 : &syncobjs);
1499 0 : if (ret < 0)
1500 : return ret;
1501 :
1502 0 : for (i = 0; i < args->count_handles; i++) {
1503 0 : ret = drm_syncobj_assign_null_handle(syncobjs[i]);
1504 0 : if (ret < 0)
1505 : break;
1506 : }
1507 :
1508 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1509 :
1510 0 : return ret;
1511 : }
1512 :
1513 : int
1514 0 : drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
1515 : struct drm_file *file_private)
1516 : {
1517 0 : struct drm_syncobj_timeline_array *args = data;
1518 : struct drm_syncobj **syncobjs;
1519 : struct dma_fence_chain **chains;
1520 : uint64_t *points;
1521 : uint32_t i, j;
1522 : int ret;
1523 :
1524 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1525 : return -EOPNOTSUPP;
1526 :
1527 0 : if (args->flags != 0)
1528 : return -EINVAL;
1529 :
1530 0 : if (args->count_handles == 0)
1531 : return -EINVAL;
1532 :
1533 0 : ret = drm_syncobj_array_find(file_private,
1534 0 : u64_to_user_ptr(args->handles),
1535 : args->count_handles,
1536 : &syncobjs);
1537 0 : if (ret < 0)
1538 : return ret;
1539 :
1540 0 : points = kmalloc_array(args->count_handles, sizeof(*points),
1541 : GFP_KERNEL);
1542 0 : if (!points) {
1543 : ret = -ENOMEM;
1544 : goto out;
1545 : }
1546 0 : if (!u64_to_user_ptr(args->points)) {
1547 0 : memset(points, 0, args->count_handles * sizeof(uint64_t));
1548 0 : } else if (copy_from_user(points, u64_to_user_ptr(args->points),
1549 0 : sizeof(uint64_t) * args->count_handles)) {
1550 : ret = -EFAULT;
1551 : goto err_points;
1552 : }
1553 :
1554 0 : chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
1555 0 : if (!chains) {
1556 : ret = -ENOMEM;
1557 : goto err_points;
1558 : }
1559 0 : for (i = 0; i < args->count_handles; i++) {
1560 0 : chains[i] = dma_fence_chain_alloc();
1561 0 : if (!chains[i]) {
1562 0 : for (j = 0; j < i; j++)
1563 0 : dma_fence_chain_free(chains[j]);
1564 : ret = -ENOMEM;
1565 : goto err_chains;
1566 : }
1567 : }
1568 :
1569 0 : for (i = 0; i < args->count_handles; i++) {
1570 0 : struct dma_fence *fence = dma_fence_get_stub();
1571 :
1572 0 : drm_syncobj_add_point(syncobjs[i], chains[i],
1573 0 : fence, points[i]);
1574 0 : dma_fence_put(fence);
1575 : }
1576 : err_chains:
1577 0 : kfree(chains);
1578 : err_points:
1579 0 : kfree(points);
1580 : out:
1581 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1582 :
1583 0 : return ret;
1584 : }
1585 :
1586 0 : int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
1587 : struct drm_file *file_private)
1588 : {
1589 0 : struct drm_syncobj_timeline_array *args = data;
1590 : struct drm_syncobj **syncobjs;
1591 0 : uint64_t __user *points = u64_to_user_ptr(args->points);
1592 : uint32_t i;
1593 : int ret;
1594 :
1595 0 : if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1596 : return -EOPNOTSUPP;
1597 :
1598 0 : if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED)
1599 : return -EINVAL;
1600 :
1601 0 : if (args->count_handles == 0)
1602 : return -EINVAL;
1603 :
1604 0 : ret = drm_syncobj_array_find(file_private,
1605 0 : u64_to_user_ptr(args->handles),
1606 : args->count_handles,
1607 : &syncobjs);
1608 0 : if (ret < 0)
1609 : return ret;
1610 :
1611 0 : for (i = 0; i < args->count_handles; i++) {
1612 : struct dma_fence_chain *chain;
1613 : struct dma_fence *fence;
1614 : uint64_t point;
1615 :
1616 0 : fence = drm_syncobj_fence_get(syncobjs[i]);
1617 0 : chain = to_dma_fence_chain(fence);
1618 0 : if (chain) {
1619 0 : struct dma_fence *iter, *last_signaled =
1620 : dma_fence_get(fence);
1621 :
1622 0 : if (args->flags &
1623 : DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) {
1624 0 : point = fence->seqno;
1625 : } else {
1626 0 : dma_fence_chain_for_each(iter, fence) {
1627 0 : if (iter->context != fence->context) {
1628 : dma_fence_put(iter);
1629 : /* It is most likely that timeline has
1630 : * unorder points. */
1631 : break;
1632 : }
1633 0 : dma_fence_put(last_signaled);
1634 0 : last_signaled = dma_fence_get(iter);
1635 : }
1636 0 : point = dma_fence_is_signaled(last_signaled) ?
1637 0 : last_signaled->seqno :
1638 0 : to_dma_fence_chain(last_signaled)->prev_seqno;
1639 : }
1640 : dma_fence_put(last_signaled);
1641 : } else {
1642 0 : point = 0;
1643 : }
1644 0 : dma_fence_put(fence);
1645 0 : ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
1646 0 : ret = ret ? -EFAULT : 0;
1647 0 : if (ret)
1648 : break;
1649 : }
1650 0 : drm_syncobj_array_free(syncobjs, args->count_handles);
1651 :
1652 0 : return ret;
1653 : }
|