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