drm_syncobj.c revision 1.6 1 1.6 riastrad /* $NetBSD: drm_syncobj.c,v 1.6 2021/12/19 12:35:28 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.6 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_syncobj.c,v 1.6 2021/12/19 12:35:28 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.4 riastrad /*
151 1.4 riastrad * Lock order:
152 1.4 riastrad * syncobj->lock ???? fence lock
153 1.4 riastrad * syncobj->lock then wait->lock
154 1.4 riastrad * fence lock then wait->lock
155 1.4 riastrad *
156 1.4 riastrad * syncobj->lock serializes wait->node and wait->fence.
157 1.4 riastrad * wait->lock serializes wait->signalledp, and, by
158 1.4 riastrad * interlocking with syncobj->lock, coordinates wakeups on
159 1.4 riastrad * wait->cv for wait->fence.
160 1.4 riastrad */
161 1.3 riastrad kmutex_t *lock;
162 1.3 riastrad kcondvar_t *cv;
163 1.4 riastrad bool *signalledp;
164 1.3 riastrad #else
165 1.1 riastrad struct task_struct *task;
166 1.3 riastrad #endif
167 1.1 riastrad struct dma_fence *fence;
168 1.1 riastrad struct dma_fence_cb fence_cb;
169 1.1 riastrad u64 point;
170 1.1 riastrad };
171 1.1 riastrad
172 1.4 riastrad #ifdef __NetBSD__
173 1.4 riastrad static int
174 1.4 riastrad cv_wait_timeout_sig(kcondvar_t *cv, kmutex_t *lock, long *timeoutp)
175 1.4 riastrad {
176 1.4 riastrad unsigned long ticks = *timeoutp;
177 1.4 riastrad unsigned starttime, endtime;
178 1.4 riastrad int error;
179 1.4 riastrad
180 1.4 riastrad starttime = hardclock_ticks;
181 1.4 riastrad error = cv_timedwait_sig(cv, lock, MIN(ticks, INT_MAX));
182 1.4 riastrad endtime = hardclock_ticks;
183 1.4 riastrad
184 1.4 riastrad if (error == EINTR || error == ERESTART) {
185 1.4 riastrad return ERESTARTSYS;
186 1.4 riastrad } else {
187 1.4 riastrad KASSERTMSG(error == 0 || error == EWOULDBLOCK,
188 1.4 riastrad "error=%d", error);
189 1.4 riastrad if (endtime - starttime < ticks)
190 1.4 riastrad *timeoutp = ticks - (endtime - starttime);
191 1.4 riastrad else
192 1.4 riastrad *timeoutp = 0;
193 1.4 riastrad return 0;
194 1.4 riastrad }
195 1.4 riastrad }
196 1.4 riastrad #endif
197 1.4 riastrad
198 1.1 riastrad static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
199 1.1 riastrad struct syncobj_wait_entry *wait);
200 1.1 riastrad
201 1.1 riastrad /**
202 1.1 riastrad * drm_syncobj_find - lookup and reference a sync object.
203 1.1 riastrad * @file_private: drm file private pointer
204 1.1 riastrad * @handle: sync object handle to lookup.
205 1.1 riastrad *
206 1.1 riastrad * Returns a reference to the syncobj pointed to by handle or NULL. The
207 1.1 riastrad * reference must be released by calling drm_syncobj_put().
208 1.1 riastrad */
209 1.1 riastrad struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
210 1.1 riastrad u32 handle)
211 1.1 riastrad {
212 1.1 riastrad struct drm_syncobj *syncobj;
213 1.1 riastrad
214 1.1 riastrad spin_lock(&file_private->syncobj_table_lock);
215 1.1 riastrad
216 1.1 riastrad /* Check if we currently have a reference on the object */
217 1.1 riastrad syncobj = idr_find(&file_private->syncobj_idr, handle);
218 1.1 riastrad if (syncobj)
219 1.1 riastrad drm_syncobj_get(syncobj);
220 1.1 riastrad
221 1.1 riastrad spin_unlock(&file_private->syncobj_table_lock);
222 1.1 riastrad
223 1.1 riastrad return syncobj;
224 1.1 riastrad }
225 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_find);
226 1.1 riastrad
227 1.1 riastrad static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
228 1.1 riastrad struct syncobj_wait_entry *wait)
229 1.1 riastrad {
230 1.1 riastrad struct dma_fence *fence;
231 1.1 riastrad
232 1.1 riastrad if (wait->fence)
233 1.1 riastrad return;
234 1.1 riastrad
235 1.1 riastrad spin_lock(&syncobj->lock);
236 1.1 riastrad /* We've already tried once to get a fence and failed. Now that we
237 1.1 riastrad * have the lock, try one more time just to be sure we don't add a
238 1.1 riastrad * callback when a fence has already been set.
239 1.1 riastrad */
240 1.1 riastrad fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
241 1.1 riastrad if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
242 1.1 riastrad dma_fence_put(fence);
243 1.1 riastrad list_add_tail(&wait->node, &syncobj->cb_list);
244 1.1 riastrad } else if (!fence) {
245 1.1 riastrad wait->fence = dma_fence_get_stub();
246 1.1 riastrad } else {
247 1.1 riastrad wait->fence = fence;
248 1.1 riastrad }
249 1.1 riastrad spin_unlock(&syncobj->lock);
250 1.1 riastrad }
251 1.1 riastrad
252 1.1 riastrad static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
253 1.1 riastrad struct syncobj_wait_entry *wait)
254 1.1 riastrad {
255 1.1 riastrad if (!wait->node.next)
256 1.1 riastrad return;
257 1.1 riastrad
258 1.1 riastrad spin_lock(&syncobj->lock);
259 1.1 riastrad list_del_init(&wait->node);
260 1.1 riastrad spin_unlock(&syncobj->lock);
261 1.1 riastrad }
262 1.1 riastrad
263 1.1 riastrad /**
264 1.1 riastrad * drm_syncobj_add_point - add new timeline point to the syncobj
265 1.1 riastrad * @syncobj: sync object to add timeline point do
266 1.1 riastrad * @chain: chain node to use to add the point
267 1.1 riastrad * @fence: fence to encapsulate in the chain node
268 1.1 riastrad * @point: sequence number to use for the point
269 1.1 riastrad *
270 1.1 riastrad * Add the chain node as new timeline point to the syncobj.
271 1.1 riastrad */
272 1.1 riastrad void drm_syncobj_add_point(struct drm_syncobj *syncobj,
273 1.1 riastrad struct dma_fence_chain *chain,
274 1.1 riastrad struct dma_fence *fence,
275 1.1 riastrad uint64_t point)
276 1.1 riastrad {
277 1.1 riastrad struct syncobj_wait_entry *cur, *tmp;
278 1.1 riastrad struct dma_fence *prev;
279 1.1 riastrad
280 1.1 riastrad dma_fence_get(fence);
281 1.1 riastrad
282 1.1 riastrad spin_lock(&syncobj->lock);
283 1.1 riastrad
284 1.1 riastrad prev = drm_syncobj_fence_get(syncobj);
285 1.1 riastrad /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
286 1.1 riastrad if (prev && prev->seqno >= point)
287 1.1 riastrad DRM_ERROR("You are adding an unorder point to timeline!\n");
288 1.1 riastrad dma_fence_chain_init(chain, prev, fence, point);
289 1.1 riastrad rcu_assign_pointer(syncobj->fence, &chain->base);
290 1.1 riastrad
291 1.1 riastrad list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
292 1.1 riastrad syncobj_wait_syncobj_func(syncobj, cur);
293 1.1 riastrad spin_unlock(&syncobj->lock);
294 1.1 riastrad
295 1.1 riastrad /* Walk the chain once to trigger garbage collection */
296 1.1 riastrad dma_fence_chain_for_each(fence, prev);
297 1.1 riastrad dma_fence_put(prev);
298 1.1 riastrad }
299 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_add_point);
300 1.1 riastrad
301 1.1 riastrad /**
302 1.1 riastrad * drm_syncobj_replace_fence - replace fence in a sync object.
303 1.1 riastrad * @syncobj: Sync object to replace fence in
304 1.1 riastrad * @fence: fence to install in sync file.
305 1.1 riastrad *
306 1.1 riastrad * This replaces the fence on a sync object.
307 1.1 riastrad */
308 1.1 riastrad void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
309 1.1 riastrad struct dma_fence *fence)
310 1.1 riastrad {
311 1.1 riastrad struct dma_fence *old_fence;
312 1.1 riastrad struct syncobj_wait_entry *cur, *tmp;
313 1.1 riastrad
314 1.1 riastrad if (fence)
315 1.1 riastrad dma_fence_get(fence);
316 1.1 riastrad
317 1.1 riastrad spin_lock(&syncobj->lock);
318 1.1 riastrad
319 1.1 riastrad old_fence = rcu_dereference_protected(syncobj->fence,
320 1.1 riastrad lockdep_is_held(&syncobj->lock));
321 1.1 riastrad rcu_assign_pointer(syncobj->fence, fence);
322 1.1 riastrad
323 1.1 riastrad if (fence != old_fence) {
324 1.1 riastrad list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
325 1.1 riastrad syncobj_wait_syncobj_func(syncobj, cur);
326 1.1 riastrad }
327 1.1 riastrad
328 1.1 riastrad spin_unlock(&syncobj->lock);
329 1.1 riastrad
330 1.1 riastrad dma_fence_put(old_fence);
331 1.1 riastrad }
332 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_replace_fence);
333 1.1 riastrad
334 1.1 riastrad /**
335 1.1 riastrad * drm_syncobj_assign_null_handle - assign a stub fence to the sync object
336 1.1 riastrad * @syncobj: sync object to assign the fence on
337 1.1 riastrad *
338 1.1 riastrad * Assign a already signaled stub fence to the sync object.
339 1.1 riastrad */
340 1.1 riastrad static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
341 1.1 riastrad {
342 1.1 riastrad struct dma_fence *fence = dma_fence_get_stub();
343 1.1 riastrad
344 1.1 riastrad drm_syncobj_replace_fence(syncobj, fence);
345 1.1 riastrad dma_fence_put(fence);
346 1.1 riastrad }
347 1.1 riastrad
348 1.1 riastrad /* 5s default for wait submission */
349 1.1 riastrad #define DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT 5000000000ULL
350 1.1 riastrad /**
351 1.1 riastrad * drm_syncobj_find_fence - lookup and reference the fence in a sync object
352 1.1 riastrad * @file_private: drm file private pointer
353 1.1 riastrad * @handle: sync object handle to lookup.
354 1.1 riastrad * @point: timeline point
355 1.1 riastrad * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
356 1.1 riastrad * @fence: out parameter for the fence
357 1.1 riastrad *
358 1.1 riastrad * This is just a convenience function that combines drm_syncobj_find() and
359 1.1 riastrad * drm_syncobj_fence_get().
360 1.1 riastrad *
361 1.1 riastrad * Returns 0 on success or a negative error value on failure. On success @fence
362 1.1 riastrad * contains a reference to the fence, which must be released by calling
363 1.1 riastrad * dma_fence_put().
364 1.1 riastrad */
365 1.1 riastrad int drm_syncobj_find_fence(struct drm_file *file_private,
366 1.1 riastrad u32 handle, u64 point, u64 flags,
367 1.1 riastrad struct dma_fence **fence)
368 1.1 riastrad {
369 1.1 riastrad struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
370 1.1 riastrad struct syncobj_wait_entry wait;
371 1.1 riastrad u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
372 1.1 riastrad int ret;
373 1.1 riastrad
374 1.1 riastrad if (!syncobj)
375 1.1 riastrad return -ENOENT;
376 1.1 riastrad
377 1.1 riastrad *fence = drm_syncobj_fence_get(syncobj);
378 1.1 riastrad drm_syncobj_put(syncobj);
379 1.1 riastrad
380 1.1 riastrad if (*fence) {
381 1.1 riastrad ret = dma_fence_chain_find_seqno(fence, point);
382 1.1 riastrad if (!ret)
383 1.1 riastrad return 0;
384 1.1 riastrad dma_fence_put(*fence);
385 1.1 riastrad } else {
386 1.1 riastrad ret = -EINVAL;
387 1.1 riastrad }
388 1.1 riastrad
389 1.1 riastrad if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
390 1.1 riastrad return ret;
391 1.1 riastrad
392 1.1 riastrad memset(&wait, 0, sizeof(wait));
393 1.4 riastrad #ifdef __NetBSD__
394 1.4 riastrad kmutex_t lock;
395 1.4 riastrad kcondvar_t cv;
396 1.4 riastrad mutex_init(&lock, MUTEX_DEFAULT, IPL_VM);
397 1.4 riastrad cv_init(&cv, "drmfnfnc");
398 1.4 riastrad wait.cv = &cv;
399 1.4 riastrad #else
400 1.1 riastrad wait.task = current;
401 1.6 riastrad #endif
402 1.1 riastrad wait.point = point;
403 1.1 riastrad drm_syncobj_fence_add_wait(syncobj, &wait);
404 1.1 riastrad
405 1.4 riastrad #ifdef __NetBSD__
406 1.4 riastrad spin_lock(&syncobj->lock);
407 1.4 riastrad #endif
408 1.1 riastrad do {
409 1.4 riastrad #ifndef __NetBSD__
410 1.1 riastrad set_current_state(TASK_INTERRUPTIBLE);
411 1.4 riastrad #endif
412 1.1 riastrad if (wait.fence) {
413 1.1 riastrad ret = 0;
414 1.1 riastrad break;
415 1.1 riastrad }
416 1.1 riastrad if (timeout == 0) {
417 1.1 riastrad ret = -ETIME;
418 1.1 riastrad break;
419 1.1 riastrad }
420 1.1 riastrad
421 1.4 riastrad #ifdef __NetBSD__
422 1.4 riastrad mutex_enter(&lock);
423 1.4 riastrad spin_unlock(&syncobj->lock);
424 1.4 riastrad /* XXX errno NetBSD->Linux */
425 1.4 riastrad ret = -cv_wait_timeout_sig(&cv, &lock, &timeout);
426 1.4 riastrad mutex_exit(&lock);
427 1.4 riastrad spin_lock(&syncobj->lock);
428 1.4 riastrad if (ret)
429 1.4 riastrad break;
430 1.4 riastrad #else
431 1.1 riastrad if (signal_pending(current)) {
432 1.1 riastrad ret = -ERESTARTSYS;
433 1.1 riastrad break;
434 1.1 riastrad }
435 1.1 riastrad
436 1.1 riastrad timeout = schedule_timeout(timeout);
437 1.4 riastrad #endif
438 1.1 riastrad } while (1);
439 1.1 riastrad
440 1.4 riastrad #ifdef __NetBSD__
441 1.4 riastrad spin_unlock(&syncobj->lock);
442 1.4 riastrad cv_destroy(&cv);
443 1.4 riastrad mutex_destroy(&lock);
444 1.4 riastrad #else
445 1.1 riastrad __set_current_state(TASK_RUNNING);
446 1.4 riastrad #endif
447 1.1 riastrad *fence = wait.fence;
448 1.1 riastrad
449 1.1 riastrad if (wait.node.next)
450 1.1 riastrad drm_syncobj_remove_wait(syncobj, &wait);
451 1.1 riastrad
452 1.1 riastrad return ret;
453 1.1 riastrad }
454 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_find_fence);
455 1.1 riastrad
456 1.1 riastrad /**
457 1.1 riastrad * drm_syncobj_free - free a sync object.
458 1.1 riastrad * @kref: kref to free.
459 1.1 riastrad *
460 1.1 riastrad * Only to be called from kref_put in drm_syncobj_put.
461 1.1 riastrad */
462 1.1 riastrad void drm_syncobj_free(struct kref *kref)
463 1.1 riastrad {
464 1.1 riastrad struct drm_syncobj *syncobj = container_of(kref,
465 1.1 riastrad struct drm_syncobj,
466 1.1 riastrad refcount);
467 1.1 riastrad drm_syncobj_replace_fence(syncobj, NULL);
468 1.5 riastrad spin_lock_destroy(&syncobj->lock);
469 1.1 riastrad kfree(syncobj);
470 1.1 riastrad }
471 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_free);
472 1.1 riastrad
473 1.1 riastrad /**
474 1.1 riastrad * drm_syncobj_create - create a new syncobj
475 1.1 riastrad * @out_syncobj: returned syncobj
476 1.1 riastrad * @flags: DRM_SYNCOBJ_* flags
477 1.1 riastrad * @fence: if non-NULL, the syncobj will represent this fence
478 1.1 riastrad *
479 1.1 riastrad * This is the first function to create a sync object. After creating, drivers
480 1.1 riastrad * probably want to make it available to userspace, either through
481 1.1 riastrad * drm_syncobj_get_handle() or drm_syncobj_get_fd().
482 1.1 riastrad *
483 1.1 riastrad * Returns 0 on success or a negative error value on failure.
484 1.1 riastrad */
485 1.1 riastrad int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
486 1.1 riastrad struct dma_fence *fence)
487 1.1 riastrad {
488 1.1 riastrad struct drm_syncobj *syncobj;
489 1.1 riastrad
490 1.1 riastrad syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
491 1.1 riastrad if (!syncobj)
492 1.1 riastrad return -ENOMEM;
493 1.1 riastrad
494 1.1 riastrad kref_init(&syncobj->refcount);
495 1.1 riastrad INIT_LIST_HEAD(&syncobj->cb_list);
496 1.1 riastrad spin_lock_init(&syncobj->lock);
497 1.1 riastrad
498 1.1 riastrad if (flags & DRM_SYNCOBJ_CREATE_SIGNALED)
499 1.1 riastrad drm_syncobj_assign_null_handle(syncobj);
500 1.1 riastrad
501 1.1 riastrad if (fence)
502 1.1 riastrad drm_syncobj_replace_fence(syncobj, fence);
503 1.1 riastrad
504 1.1 riastrad *out_syncobj = syncobj;
505 1.1 riastrad return 0;
506 1.1 riastrad }
507 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_create);
508 1.1 riastrad
509 1.1 riastrad /**
510 1.1 riastrad * drm_syncobj_get_handle - get a handle from a syncobj
511 1.1 riastrad * @file_private: drm file private pointer
512 1.1 riastrad * @syncobj: Sync object to export
513 1.1 riastrad * @handle: out parameter with the new handle
514 1.1 riastrad *
515 1.1 riastrad * Exports a sync object created with drm_syncobj_create() as a handle on
516 1.1 riastrad * @file_private to userspace.
517 1.1 riastrad *
518 1.1 riastrad * Returns 0 on success or a negative error value on failure.
519 1.1 riastrad */
520 1.1 riastrad int drm_syncobj_get_handle(struct drm_file *file_private,
521 1.1 riastrad struct drm_syncobj *syncobj, u32 *handle)
522 1.1 riastrad {
523 1.1 riastrad int ret;
524 1.1 riastrad
525 1.1 riastrad /* take a reference to put in the idr */
526 1.1 riastrad drm_syncobj_get(syncobj);
527 1.1 riastrad
528 1.1 riastrad idr_preload(GFP_KERNEL);
529 1.1 riastrad spin_lock(&file_private->syncobj_table_lock);
530 1.1 riastrad ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
531 1.1 riastrad spin_unlock(&file_private->syncobj_table_lock);
532 1.1 riastrad
533 1.1 riastrad idr_preload_end();
534 1.1 riastrad
535 1.1 riastrad if (ret < 0) {
536 1.1 riastrad drm_syncobj_put(syncobj);
537 1.1 riastrad return ret;
538 1.1 riastrad }
539 1.1 riastrad
540 1.1 riastrad *handle = ret;
541 1.1 riastrad return 0;
542 1.1 riastrad }
543 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_get_handle);
544 1.1 riastrad
545 1.1 riastrad static int drm_syncobj_create_as_handle(struct drm_file *file_private,
546 1.1 riastrad u32 *handle, uint32_t flags)
547 1.1 riastrad {
548 1.1 riastrad int ret;
549 1.1 riastrad struct drm_syncobj *syncobj;
550 1.1 riastrad
551 1.1 riastrad ret = drm_syncobj_create(&syncobj, flags, NULL);
552 1.1 riastrad if (ret)
553 1.1 riastrad return ret;
554 1.1 riastrad
555 1.1 riastrad ret = drm_syncobj_get_handle(file_private, syncobj, handle);
556 1.1 riastrad drm_syncobj_put(syncobj);
557 1.1 riastrad return ret;
558 1.1 riastrad }
559 1.1 riastrad
560 1.1 riastrad static int drm_syncobj_destroy(struct drm_file *file_private,
561 1.1 riastrad u32 handle)
562 1.1 riastrad {
563 1.1 riastrad struct drm_syncobj *syncobj;
564 1.1 riastrad
565 1.1 riastrad spin_lock(&file_private->syncobj_table_lock);
566 1.1 riastrad syncobj = idr_remove(&file_private->syncobj_idr, handle);
567 1.1 riastrad spin_unlock(&file_private->syncobj_table_lock);
568 1.1 riastrad
569 1.1 riastrad if (!syncobj)
570 1.1 riastrad return -EINVAL;
571 1.1 riastrad
572 1.1 riastrad drm_syncobj_put(syncobj);
573 1.1 riastrad return 0;
574 1.1 riastrad }
575 1.1 riastrad
576 1.3 riastrad #ifdef __NetBSD__
577 1.3 riastrad static int drm_syncobj_fop_close(struct file *file)
578 1.3 riastrad #else
579 1.1 riastrad static int drm_syncobj_file_release(struct inode *inode, struct file *file)
580 1.3 riastrad #endif
581 1.1 riastrad {
582 1.3 riastrad #ifdef __NetBSD__
583 1.3 riastrad struct drm_syncobj *syncobj = file->f_data;
584 1.3 riastrad #else
585 1.1 riastrad struct drm_syncobj *syncobj = file->private_data;
586 1.3 riastrad #endif
587 1.1 riastrad
588 1.1 riastrad drm_syncobj_put(syncobj);
589 1.1 riastrad return 0;
590 1.1 riastrad }
591 1.1 riastrad
592 1.3 riastrad #ifdef __NetBSD__
593 1.3 riastrad static const struct fileops drm_syncobj_file_ops = {
594 1.3 riastrad .fo_name = "drm_syncobj",
595 1.3 riastrad .fo_read = fbadop_read,
596 1.3 riastrad .fo_write = fbadop_write,
597 1.3 riastrad .fo_ioctl = fbadop_ioctl,
598 1.3 riastrad .fo_fcntl = fnullop_fcntl,
599 1.3 riastrad .fo_poll = fnullop_poll,
600 1.3 riastrad .fo_stat = fbadop_stat,
601 1.3 riastrad .fo_close = drm_syncobj_fop_close,
602 1.3 riastrad .fo_kqfilter = fnullop_kqfilter,
603 1.3 riastrad .fo_restart = fnullop_restart,
604 1.3 riastrad };
605 1.3 riastrad #else
606 1.1 riastrad static const struct file_operations drm_syncobj_file_fops = {
607 1.1 riastrad .release = drm_syncobj_file_release,
608 1.1 riastrad };
609 1.3 riastrad #endif
610 1.1 riastrad
611 1.1 riastrad /**
612 1.1 riastrad * drm_syncobj_get_fd - get a file descriptor from a syncobj
613 1.1 riastrad * @syncobj: Sync object to export
614 1.1 riastrad * @p_fd: out parameter with the new file descriptor
615 1.1 riastrad *
616 1.1 riastrad * Exports a sync object created with drm_syncobj_create() as a file descriptor.
617 1.1 riastrad *
618 1.1 riastrad * Returns 0 on success or a negative error value on failure.
619 1.1 riastrad */
620 1.1 riastrad int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
621 1.1 riastrad {
622 1.1 riastrad struct file *file;
623 1.1 riastrad int fd;
624 1.3 riastrad #ifdef __NetBSD__
625 1.3 riastrad int ret;
626 1.3 riastrad #endif
627 1.1 riastrad
628 1.3 riastrad #ifdef __NetBSD__
629 1.3 riastrad fd = -1;
630 1.3 riastrad /* XXX errno NetBSD->Linux */
631 1.3 riastrad ret = -fd_allocfile(&file, &fd);
632 1.3 riastrad if (ret)
633 1.3 riastrad return ret;
634 1.3 riastrad file->f_data = syncobj;
635 1.3 riastrad file->f_ops = &drm_syncobj_file_ops;
636 1.3 riastrad #else
637 1.1 riastrad fd = get_unused_fd_flags(O_CLOEXEC);
638 1.1 riastrad if (fd < 0)
639 1.1 riastrad return fd;
640 1.1 riastrad
641 1.1 riastrad file = anon_inode_getfile("syncobj_file",
642 1.1 riastrad &drm_syncobj_file_fops,
643 1.1 riastrad syncobj, 0);
644 1.1 riastrad if (IS_ERR(file)) {
645 1.1 riastrad put_unused_fd(fd);
646 1.1 riastrad return PTR_ERR(file);
647 1.1 riastrad }
648 1.3 riastrad #endif
649 1.1 riastrad
650 1.1 riastrad drm_syncobj_get(syncobj);
651 1.1 riastrad fd_install(fd, file);
652 1.1 riastrad
653 1.1 riastrad *p_fd = fd;
654 1.1 riastrad return 0;
655 1.1 riastrad }
656 1.1 riastrad EXPORT_SYMBOL(drm_syncobj_get_fd);
657 1.1 riastrad
658 1.1 riastrad static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
659 1.1 riastrad u32 handle, int *p_fd)
660 1.1 riastrad {
661 1.1 riastrad struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
662 1.1 riastrad int ret;
663 1.1 riastrad
664 1.1 riastrad if (!syncobj)
665 1.1 riastrad return -EINVAL;
666 1.1 riastrad
667 1.1 riastrad ret = drm_syncobj_get_fd(syncobj, p_fd);
668 1.1 riastrad drm_syncobj_put(syncobj);
669 1.1 riastrad return ret;
670 1.1 riastrad }
671 1.1 riastrad
672 1.1 riastrad static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
673 1.1 riastrad int fd, u32 *handle)
674 1.1 riastrad {
675 1.1 riastrad struct drm_syncobj *syncobj;
676 1.1 riastrad struct fd f = fdget(fd);
677 1.1 riastrad int ret;
678 1.1 riastrad
679 1.1 riastrad if (!f.file)
680 1.1 riastrad return -EINVAL;
681 1.1 riastrad
682 1.3 riastrad #ifdef __NetBSD__
683 1.4 riastrad if (f.file->f_ops != &drm_syncobj_file_ops)
684 1.3 riastrad #else
685 1.4 riastrad if (f.file->f_op != &drm_syncobj_file_fops)
686 1.4 riastrad #endif
687 1.4 riastrad {
688 1.1 riastrad fdput(f);
689 1.1 riastrad return -EINVAL;
690 1.1 riastrad }
691 1.1 riastrad
692 1.1 riastrad /* take a reference to put in the idr */
693 1.3 riastrad #ifdef __NetBSD__
694 1.3 riastrad syncobj = f.file->f_data;
695 1.3 riastrad #else
696 1.1 riastrad syncobj = f.file->private_data;
697 1.3 riastrad #endif
698 1.1 riastrad drm_syncobj_get(syncobj);
699 1.1 riastrad
700 1.1 riastrad idr_preload(GFP_KERNEL);
701 1.1 riastrad spin_lock(&file_private->syncobj_table_lock);
702 1.1 riastrad ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
703 1.1 riastrad spin_unlock(&file_private->syncobj_table_lock);
704 1.1 riastrad idr_preload_end();
705 1.1 riastrad
706 1.1 riastrad if (ret > 0) {
707 1.1 riastrad *handle = ret;
708 1.1 riastrad ret = 0;
709 1.1 riastrad } else
710 1.1 riastrad drm_syncobj_put(syncobj);
711 1.1 riastrad
712 1.1 riastrad fdput(f);
713 1.1 riastrad return ret;
714 1.1 riastrad }
715 1.1 riastrad
716 1.1 riastrad static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
717 1.1 riastrad int fd, int handle)
718 1.1 riastrad {
719 1.1 riastrad struct dma_fence *fence = sync_file_get_fence(fd);
720 1.1 riastrad struct drm_syncobj *syncobj;
721 1.1 riastrad
722 1.1 riastrad if (!fence)
723 1.1 riastrad return -EINVAL;
724 1.1 riastrad
725 1.1 riastrad syncobj = drm_syncobj_find(file_private, handle);
726 1.1 riastrad if (!syncobj) {
727 1.1 riastrad dma_fence_put(fence);
728 1.1 riastrad return -ENOENT;
729 1.1 riastrad }
730 1.1 riastrad
731 1.1 riastrad drm_syncobj_replace_fence(syncobj, fence);
732 1.1 riastrad dma_fence_put(fence);
733 1.1 riastrad drm_syncobj_put(syncobj);
734 1.1 riastrad return 0;
735 1.1 riastrad }
736 1.1 riastrad
737 1.1 riastrad static int drm_syncobj_export_sync_file(struct drm_file *file_private,
738 1.1 riastrad int handle, int *p_fd)
739 1.1 riastrad {
740 1.3 riastrad #ifdef __NetBSD__
741 1.3 riastrad struct dma_fence *fence;
742 1.3 riastrad struct sync_file *sync_file;
743 1.3 riastrad struct file *fp = NULL;
744 1.3 riastrad int fd = -1;
745 1.3 riastrad int ret;
746 1.3 riastrad
747 1.3 riastrad /* Allocate a file and descriptor. */
748 1.3 riastrad /* XXX errno NetBSD->Linux */
749 1.3 riastrad ret = -fd_allocfile(&fp, &fd);
750 1.3 riastrad if (ret)
751 1.3 riastrad goto out;
752 1.3 riastrad
753 1.3 riastrad /* Find the fence. */
754 1.4 riastrad ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
755 1.3 riastrad if (ret)
756 1.3 riastrad goto out;
757 1.3 riastrad
758 1.3 riastrad /* Create the sync file. */
759 1.3 riastrad sync_file = sync_file_create(fence, fp);
760 1.3 riastrad
761 1.3 riastrad /* Release the fence. */
762 1.3 riastrad dma_fence_put(fence);
763 1.3 riastrad
764 1.3 riastrad /* If the sync file creation failed, bail. */
765 1.3 riastrad if (sync_file == NULL)
766 1.3 riastrad goto out;
767 1.3 riastrad
768 1.3 riastrad /* Success! */
769 1.3 riastrad fd_affix(curproc, fp, fd);
770 1.3 riastrad fp = NULL; /* sync_file consumes */
771 1.3 riastrad ret = 0;
772 1.3 riastrad
773 1.3 riastrad out:
774 1.3 riastrad /* If anything went wrong and we still have an unused file, abort. */
775 1.3 riastrad if (fp != NULL) {
776 1.3 riastrad fd_abort(curproc, fp, fd);
777 1.3 riastrad fd = -1;
778 1.3 riastrad }
779 1.3 riastrad
780 1.3 riastrad /* Return the descriptor or -1. */
781 1.3 riastrad *p_fd = fd;
782 1.3 riastrad return ret;
783 1.3 riastrad #else
784 1.1 riastrad int ret;
785 1.1 riastrad struct dma_fence *fence;
786 1.1 riastrad struct sync_file *sync_file;
787 1.1 riastrad int fd = get_unused_fd_flags(O_CLOEXEC);
788 1.1 riastrad
789 1.1 riastrad if (fd < 0)
790 1.1 riastrad return fd;
791 1.1 riastrad
792 1.1 riastrad ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
793 1.1 riastrad if (ret)
794 1.1 riastrad goto err_put_fd;
795 1.1 riastrad
796 1.1 riastrad sync_file = sync_file_create(fence);
797 1.1 riastrad
798 1.1 riastrad dma_fence_put(fence);
799 1.1 riastrad
800 1.1 riastrad if (!sync_file) {
801 1.1 riastrad ret = -EINVAL;
802 1.1 riastrad goto err_put_fd;
803 1.1 riastrad }
804 1.1 riastrad
805 1.1 riastrad fd_install(fd, sync_file->file);
806 1.1 riastrad
807 1.1 riastrad *p_fd = fd;
808 1.1 riastrad return 0;
809 1.1 riastrad err_put_fd:
810 1.1 riastrad put_unused_fd(fd);
811 1.1 riastrad return ret;
812 1.3 riastrad #endif
813 1.1 riastrad }
814 1.1 riastrad /**
815 1.1 riastrad * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time
816 1.1 riastrad * @file_private: drm file-private structure to set up
817 1.1 riastrad *
818 1.1 riastrad * Called at device open time, sets up the structure for handling refcounting
819 1.1 riastrad * of sync objects.
820 1.1 riastrad */
821 1.1 riastrad void
822 1.1 riastrad drm_syncobj_open(struct drm_file *file_private)
823 1.1 riastrad {
824 1.1 riastrad idr_init_base(&file_private->syncobj_idr, 1);
825 1.1 riastrad spin_lock_init(&file_private->syncobj_table_lock);
826 1.1 riastrad }
827 1.1 riastrad
828 1.1 riastrad static int
829 1.1 riastrad drm_syncobj_release_handle(int id, void *ptr, void *data)
830 1.1 riastrad {
831 1.1 riastrad struct drm_syncobj *syncobj = ptr;
832 1.1 riastrad
833 1.1 riastrad drm_syncobj_put(syncobj);
834 1.1 riastrad return 0;
835 1.1 riastrad }
836 1.1 riastrad
837 1.1 riastrad /**
838 1.1 riastrad * drm_syncobj_release - release file-private sync object resources
839 1.1 riastrad * @file_private: drm file-private structure to clean up
840 1.1 riastrad *
841 1.1 riastrad * Called at close time when the filp is going away.
842 1.1 riastrad *
843 1.1 riastrad * Releases any remaining references on objects by this filp.
844 1.1 riastrad */
845 1.1 riastrad void
846 1.1 riastrad drm_syncobj_release(struct drm_file *file_private)
847 1.1 riastrad {
848 1.1 riastrad idr_for_each(&file_private->syncobj_idr,
849 1.1 riastrad &drm_syncobj_release_handle, file_private);
850 1.3 riastrad spin_lock_destroy(&file_private->syncobj_table_lock);
851 1.1 riastrad idr_destroy(&file_private->syncobj_idr);
852 1.1 riastrad }
853 1.1 riastrad
854 1.1 riastrad int
855 1.1 riastrad drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
856 1.1 riastrad struct drm_file *file_private)
857 1.1 riastrad {
858 1.1 riastrad struct drm_syncobj_create *args = data;
859 1.1 riastrad
860 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
861 1.1 riastrad return -EOPNOTSUPP;
862 1.1 riastrad
863 1.1 riastrad /* no valid flags yet */
864 1.1 riastrad if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
865 1.1 riastrad return -EINVAL;
866 1.1 riastrad
867 1.1 riastrad return drm_syncobj_create_as_handle(file_private,
868 1.1 riastrad &args->handle, args->flags);
869 1.1 riastrad }
870 1.1 riastrad
871 1.1 riastrad int
872 1.1 riastrad drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data,
873 1.1 riastrad struct drm_file *file_private)
874 1.1 riastrad {
875 1.1 riastrad struct drm_syncobj_destroy *args = data;
876 1.1 riastrad
877 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
878 1.1 riastrad return -EOPNOTSUPP;
879 1.1 riastrad
880 1.1 riastrad /* make sure padding is empty */
881 1.1 riastrad if (args->pad)
882 1.1 riastrad return -EINVAL;
883 1.1 riastrad return drm_syncobj_destroy(file_private, args->handle);
884 1.1 riastrad }
885 1.1 riastrad
886 1.1 riastrad int
887 1.1 riastrad drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
888 1.1 riastrad struct drm_file *file_private)
889 1.1 riastrad {
890 1.1 riastrad struct drm_syncobj_handle *args = data;
891 1.1 riastrad
892 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
893 1.1 riastrad return -EOPNOTSUPP;
894 1.1 riastrad
895 1.1 riastrad if (args->pad)
896 1.1 riastrad return -EINVAL;
897 1.1 riastrad
898 1.1 riastrad if (args->flags != 0 &&
899 1.1 riastrad args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
900 1.1 riastrad return -EINVAL;
901 1.1 riastrad
902 1.1 riastrad if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
903 1.1 riastrad return drm_syncobj_export_sync_file(file_private, args->handle,
904 1.1 riastrad &args->fd);
905 1.1 riastrad
906 1.1 riastrad return drm_syncobj_handle_to_fd(file_private, args->handle,
907 1.1 riastrad &args->fd);
908 1.1 riastrad }
909 1.1 riastrad
910 1.1 riastrad int
911 1.1 riastrad drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
912 1.1 riastrad struct drm_file *file_private)
913 1.1 riastrad {
914 1.1 riastrad struct drm_syncobj_handle *args = data;
915 1.1 riastrad
916 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
917 1.1 riastrad return -EOPNOTSUPP;
918 1.1 riastrad
919 1.1 riastrad if (args->pad)
920 1.1 riastrad return -EINVAL;
921 1.1 riastrad
922 1.1 riastrad if (args->flags != 0 &&
923 1.1 riastrad args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
924 1.1 riastrad return -EINVAL;
925 1.1 riastrad
926 1.1 riastrad if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
927 1.1 riastrad return drm_syncobj_import_sync_file_fence(file_private,
928 1.1 riastrad args->fd,
929 1.1 riastrad args->handle);
930 1.1 riastrad
931 1.1 riastrad return drm_syncobj_fd_to_handle(file_private, args->fd,
932 1.1 riastrad &args->handle);
933 1.1 riastrad }
934 1.1 riastrad
935 1.1 riastrad static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
936 1.1 riastrad struct drm_syncobj_transfer *args)
937 1.1 riastrad {
938 1.1 riastrad struct drm_syncobj *timeline_syncobj = NULL;
939 1.1 riastrad struct dma_fence *fence;
940 1.1 riastrad struct dma_fence_chain *chain;
941 1.1 riastrad int ret;
942 1.1 riastrad
943 1.1 riastrad timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle);
944 1.1 riastrad if (!timeline_syncobj) {
945 1.1 riastrad return -ENOENT;
946 1.1 riastrad }
947 1.1 riastrad ret = drm_syncobj_find_fence(file_private, args->src_handle,
948 1.1 riastrad args->src_point, args->flags,
949 1.1 riastrad &fence);
950 1.1 riastrad if (ret)
951 1.1 riastrad goto err;
952 1.1 riastrad chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
953 1.1 riastrad if (!chain) {
954 1.1 riastrad ret = -ENOMEM;
955 1.1 riastrad goto err1;
956 1.1 riastrad }
957 1.1 riastrad drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point);
958 1.1 riastrad err1:
959 1.1 riastrad dma_fence_put(fence);
960 1.1 riastrad err:
961 1.1 riastrad drm_syncobj_put(timeline_syncobj);
962 1.1 riastrad
963 1.1 riastrad return ret;
964 1.1 riastrad }
965 1.1 riastrad
966 1.1 riastrad static int
967 1.1 riastrad drm_syncobj_transfer_to_binary(struct drm_file *file_private,
968 1.1 riastrad struct drm_syncobj_transfer *args)
969 1.1 riastrad {
970 1.1 riastrad struct drm_syncobj *binary_syncobj = NULL;
971 1.1 riastrad struct dma_fence *fence;
972 1.1 riastrad int ret;
973 1.1 riastrad
974 1.1 riastrad binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
975 1.1 riastrad if (!binary_syncobj)
976 1.1 riastrad return -ENOENT;
977 1.1 riastrad ret = drm_syncobj_find_fence(file_private, args->src_handle,
978 1.1 riastrad args->src_point, args->flags, &fence);
979 1.1 riastrad if (ret)
980 1.1 riastrad goto err;
981 1.1 riastrad drm_syncobj_replace_fence(binary_syncobj, fence);
982 1.1 riastrad dma_fence_put(fence);
983 1.1 riastrad err:
984 1.1 riastrad drm_syncobj_put(binary_syncobj);
985 1.1 riastrad
986 1.1 riastrad return ret;
987 1.1 riastrad }
988 1.1 riastrad int
989 1.1 riastrad drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
990 1.1 riastrad struct drm_file *file_private)
991 1.1 riastrad {
992 1.1 riastrad struct drm_syncobj_transfer *args = data;
993 1.1 riastrad int ret;
994 1.1 riastrad
995 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
996 1.1 riastrad return -EOPNOTSUPP;
997 1.1 riastrad
998 1.1 riastrad if (args->pad)
999 1.1 riastrad return -EINVAL;
1000 1.1 riastrad
1001 1.1 riastrad if (args->dst_point)
1002 1.1 riastrad ret = drm_syncobj_transfer_to_timeline(file_private, args);
1003 1.1 riastrad else
1004 1.1 riastrad ret = drm_syncobj_transfer_to_binary(file_private, args);
1005 1.1 riastrad
1006 1.1 riastrad return ret;
1007 1.1 riastrad }
1008 1.1 riastrad
1009 1.1 riastrad static void syncobj_wait_fence_func(struct dma_fence *fence,
1010 1.1 riastrad struct dma_fence_cb *cb)
1011 1.1 riastrad {
1012 1.1 riastrad struct syncobj_wait_entry *wait =
1013 1.1 riastrad container_of(cb, struct syncobj_wait_entry, fence_cb);
1014 1.1 riastrad
1015 1.3 riastrad #ifdef __NetBSD__
1016 1.3 riastrad mutex_enter(wait->lock);
1017 1.4 riastrad *wait->signalledp = true;
1018 1.3 riastrad cv_broadcast(wait->cv);
1019 1.3 riastrad mutex_exit(wait->lock);
1020 1.3 riastrad #else
1021 1.1 riastrad wake_up_process(wait->task);
1022 1.3 riastrad #endif
1023 1.1 riastrad }
1024 1.1 riastrad
1025 1.1 riastrad static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
1026 1.1 riastrad struct syncobj_wait_entry *wait)
1027 1.1 riastrad {
1028 1.1 riastrad struct dma_fence *fence;
1029 1.1 riastrad
1030 1.1 riastrad /* This happens inside the syncobj lock */
1031 1.1 riastrad fence = rcu_dereference_protected(syncobj->fence,
1032 1.1 riastrad lockdep_is_held(&syncobj->lock));
1033 1.1 riastrad dma_fence_get(fence);
1034 1.1 riastrad if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
1035 1.1 riastrad dma_fence_put(fence);
1036 1.1 riastrad return;
1037 1.4 riastrad }
1038 1.4 riastrad
1039 1.4 riastrad if (!fence) {
1040 1.1 riastrad wait->fence = dma_fence_get_stub();
1041 1.1 riastrad } else {
1042 1.1 riastrad wait->fence = fence;
1043 1.1 riastrad }
1044 1.1 riastrad
1045 1.3 riastrad #ifdef __NetBSD__
1046 1.3 riastrad KASSERT(spin_is_locked(&syncobj->lock));
1047 1.3 riastrad mutex_enter(wait->lock);
1048 1.3 riastrad cv_broadcast(wait->cv);
1049 1.3 riastrad mutex_exit(wait->lock);
1050 1.3 riastrad #else
1051 1.1 riastrad wake_up_process(wait->task);
1052 1.3 riastrad #endif
1053 1.1 riastrad list_del_init(&wait->node);
1054 1.1 riastrad }
1055 1.1 riastrad
1056 1.1 riastrad static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
1057 1.1 riastrad void __user *user_points,
1058 1.1 riastrad uint32_t count,
1059 1.1 riastrad uint32_t flags,
1060 1.1 riastrad signed long timeout,
1061 1.1 riastrad uint32_t *idx)
1062 1.1 riastrad {
1063 1.1 riastrad struct syncobj_wait_entry *entries;
1064 1.1 riastrad struct dma_fence *fence;
1065 1.1 riastrad uint64_t *points;
1066 1.1 riastrad uint32_t signaled_count, i;
1067 1.3 riastrad #ifdef __NetBSD__
1068 1.3 riastrad kmutex_t lock;
1069 1.3 riastrad kcondvar_t cv;
1070 1.4 riastrad bool signalled = false;
1071 1.4 riastrad int ret;
1072 1.3 riastrad mutex_init(&lock, MUTEX_DEFAULT, IPL_VM);
1073 1.3 riastrad cv_init(&cv, "drmsynco");
1074 1.3 riastrad #endif
1075 1.1 riastrad
1076 1.1 riastrad points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
1077 1.1 riastrad if (points == NULL)
1078 1.1 riastrad return -ENOMEM;
1079 1.1 riastrad
1080 1.1 riastrad if (!user_points) {
1081 1.1 riastrad memset(points, 0, count * sizeof(uint64_t));
1082 1.1 riastrad
1083 1.1 riastrad } else if (copy_from_user(points, user_points,
1084 1.1 riastrad sizeof(uint64_t) * count)) {
1085 1.1 riastrad timeout = -EFAULT;
1086 1.1 riastrad goto err_free_points;
1087 1.1 riastrad }
1088 1.1 riastrad
1089 1.1 riastrad entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
1090 1.1 riastrad if (!entries) {
1091 1.1 riastrad timeout = -ENOMEM;
1092 1.1 riastrad goto err_free_points;
1093 1.1 riastrad }
1094 1.1 riastrad /* Walk the list of sync objects and initialize entries. We do
1095 1.1 riastrad * this up-front so that we can properly return -EINVAL if there is
1096 1.1 riastrad * a syncobj with a missing fence and then never have the chance of
1097 1.1 riastrad * returning -EINVAL again.
1098 1.1 riastrad */
1099 1.1 riastrad signaled_count = 0;
1100 1.1 riastrad for (i = 0; i < count; ++i) {
1101 1.3 riastrad #ifdef __NetBSD__
1102 1.3 riastrad entries[i].lock = &lock;
1103 1.3 riastrad entries[i].cv = &cv;
1104 1.4 riastrad entries[i].signalledp = &signalled;
1105 1.3 riastrad #else
1106 1.1 riastrad entries[i].task = current;
1107 1.3 riastrad #endif
1108 1.1 riastrad entries[i].point = points[i];
1109 1.1 riastrad fence = drm_syncobj_fence_get(syncobjs[i]);
1110 1.1 riastrad if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) {
1111 1.1 riastrad dma_fence_put(fence);
1112 1.1 riastrad if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
1113 1.1 riastrad continue;
1114 1.1 riastrad } else {
1115 1.1 riastrad timeout = -EINVAL;
1116 1.1 riastrad goto cleanup_entries;
1117 1.1 riastrad }
1118 1.1 riastrad }
1119 1.1 riastrad
1120 1.1 riastrad if (fence)
1121 1.1 riastrad entries[i].fence = fence;
1122 1.1 riastrad else
1123 1.1 riastrad entries[i].fence = dma_fence_get_stub();
1124 1.1 riastrad
1125 1.1 riastrad if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
1126 1.1 riastrad dma_fence_is_signaled(entries[i].fence)) {
1127 1.1 riastrad if (signaled_count == 0 && idx)
1128 1.1 riastrad *idx = i;
1129 1.1 riastrad signaled_count++;
1130 1.1 riastrad }
1131 1.1 riastrad }
1132 1.1 riastrad
1133 1.1 riastrad if (signaled_count == count ||
1134 1.1 riastrad (signaled_count > 0 &&
1135 1.1 riastrad !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
1136 1.1 riastrad goto cleanup_entries;
1137 1.1 riastrad
1138 1.1 riastrad /* There's a very annoying laxness in the dma_fence API here, in
1139 1.1 riastrad * that backends are not required to automatically report when a
1140 1.1 riastrad * fence is signaled prior to fence->ops->enable_signaling() being
1141 1.1 riastrad * called. So here if we fail to match signaled_count, we need to
1142 1.1 riastrad * fallthough and try a 0 timeout wait!
1143 1.1 riastrad */
1144 1.1 riastrad
1145 1.1 riastrad if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
1146 1.1 riastrad for (i = 0; i < count; ++i)
1147 1.1 riastrad drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
1148 1.1 riastrad }
1149 1.1 riastrad
1150 1.1 riastrad do {
1151 1.3 riastrad #ifndef __NetBSD__
1152 1.1 riastrad set_current_state(TASK_INTERRUPTIBLE);
1153 1.3 riastrad #endif
1154 1.1 riastrad
1155 1.1 riastrad signaled_count = 0;
1156 1.1 riastrad for (i = 0; i < count; ++i) {
1157 1.1 riastrad fence = entries[i].fence;
1158 1.1 riastrad if (!fence)
1159 1.1 riastrad continue;
1160 1.1 riastrad
1161 1.1 riastrad if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
1162 1.1 riastrad dma_fence_is_signaled(fence) ||
1163 1.1 riastrad (!entries[i].fence_cb.func &&
1164 1.1 riastrad dma_fence_add_callback(fence,
1165 1.1 riastrad &entries[i].fence_cb,
1166 1.1 riastrad syncobj_wait_fence_func))) {
1167 1.1 riastrad /* The fence has been signaled */
1168 1.1 riastrad if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) {
1169 1.1 riastrad signaled_count++;
1170 1.1 riastrad } else {
1171 1.1 riastrad if (idx)
1172 1.1 riastrad *idx = i;
1173 1.1 riastrad goto done_waiting;
1174 1.1 riastrad }
1175 1.1 riastrad }
1176 1.1 riastrad }
1177 1.1 riastrad
1178 1.1 riastrad if (signaled_count == count)
1179 1.1 riastrad goto done_waiting;
1180 1.1 riastrad
1181 1.1 riastrad if (timeout == 0) {
1182 1.1 riastrad timeout = -ETIME;
1183 1.1 riastrad goto done_waiting;
1184 1.1 riastrad }
1185 1.1 riastrad
1186 1.3 riastrad #ifdef __NetBSD__
1187 1.3 riastrad mutex_enter(&lock);
1188 1.4 riastrad if (signalled)
1189 1.4 riastrad ret = 0;
1190 1.4 riastrad else
1191 1.4 riastrad ret = -cv_wait_timeout_sig(&cv, &lock, &timeout);
1192 1.3 riastrad mutex_exit(&lock);
1193 1.4 riastrad if (ret) {
1194 1.4 riastrad timeout = -ERESTARTSYS;
1195 1.4 riastrad goto done_waiting;
1196 1.3 riastrad }
1197 1.3 riastrad #else
1198 1.1 riastrad if (signal_pending(current)) {
1199 1.1 riastrad timeout = -ERESTARTSYS;
1200 1.1 riastrad goto done_waiting;
1201 1.1 riastrad }
1202 1.1 riastrad
1203 1.1 riastrad timeout = schedule_timeout(timeout);
1204 1.3 riastrad #endif
1205 1.1 riastrad } while (1);
1206 1.1 riastrad
1207 1.1 riastrad done_waiting:
1208 1.3 riastrad #ifndef __NetBSD__
1209 1.1 riastrad __set_current_state(TASK_RUNNING);
1210 1.3 riastrad #endif
1211 1.1 riastrad
1212 1.1 riastrad cleanup_entries:
1213 1.1 riastrad for (i = 0; i < count; ++i) {
1214 1.1 riastrad drm_syncobj_remove_wait(syncobjs[i], &entries[i]);
1215 1.1 riastrad if (entries[i].fence_cb.func)
1216 1.1 riastrad dma_fence_remove_callback(entries[i].fence,
1217 1.1 riastrad &entries[i].fence_cb);
1218 1.1 riastrad dma_fence_put(entries[i].fence);
1219 1.1 riastrad }
1220 1.1 riastrad kfree(entries);
1221 1.1 riastrad
1222 1.1 riastrad err_free_points:
1223 1.1 riastrad kfree(points);
1224 1.4 riastrad #ifdef __NetBSD__
1225 1.3 riastrad cv_destroy(&cv);
1226 1.3 riastrad mutex_destroy(&lock);
1227 1.4 riastrad #endif
1228 1.1 riastrad
1229 1.1 riastrad return timeout;
1230 1.1 riastrad }
1231 1.1 riastrad
1232 1.1 riastrad /**
1233 1.1 riastrad * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
1234 1.1 riastrad *
1235 1.1 riastrad * @timeout_nsec: timeout nsec component in ns, 0 for poll
1236 1.1 riastrad *
1237 1.1 riastrad * Calculate the timeout in jiffies from an absolute time in sec/nsec.
1238 1.1 riastrad */
1239 1.1 riastrad signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
1240 1.1 riastrad {
1241 1.1 riastrad ktime_t abs_timeout, now;
1242 1.1 riastrad u64 timeout_ns, timeout_jiffies64;
1243 1.1 riastrad
1244 1.1 riastrad /* make 0 timeout means poll - absolute 0 doesn't seem valid */
1245 1.1 riastrad if (timeout_nsec == 0)
1246 1.1 riastrad return 0;
1247 1.1 riastrad
1248 1.1 riastrad abs_timeout = ns_to_ktime(timeout_nsec);
1249 1.1 riastrad now = ktime_get();
1250 1.1 riastrad
1251 1.1 riastrad if (!ktime_after(abs_timeout, now))
1252 1.1 riastrad return 0;
1253 1.1 riastrad
1254 1.1 riastrad timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
1255 1.1 riastrad
1256 1.1 riastrad timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
1257 1.1 riastrad /* clamp timeout to avoid infinite timeout */
1258 1.1 riastrad if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
1259 1.1 riastrad return MAX_SCHEDULE_TIMEOUT - 1;
1260 1.1 riastrad
1261 1.1 riastrad return timeout_jiffies64 + 1;
1262 1.1 riastrad }
1263 1.1 riastrad EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
1264 1.1 riastrad
1265 1.1 riastrad static int drm_syncobj_array_wait(struct drm_device *dev,
1266 1.1 riastrad struct drm_file *file_private,
1267 1.1 riastrad struct drm_syncobj_wait *wait,
1268 1.1 riastrad struct drm_syncobj_timeline_wait *timeline_wait,
1269 1.1 riastrad struct drm_syncobj **syncobjs, bool timeline)
1270 1.1 riastrad {
1271 1.1 riastrad signed long timeout = 0;
1272 1.1 riastrad uint32_t first = ~0;
1273 1.1 riastrad
1274 1.1 riastrad if (!timeline) {
1275 1.1 riastrad timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
1276 1.1 riastrad timeout = drm_syncobj_array_wait_timeout(syncobjs,
1277 1.1 riastrad NULL,
1278 1.1 riastrad wait->count_handles,
1279 1.1 riastrad wait->flags,
1280 1.1 riastrad timeout, &first);
1281 1.1 riastrad if (timeout < 0)
1282 1.1 riastrad return timeout;
1283 1.1 riastrad wait->first_signaled = first;
1284 1.1 riastrad } else {
1285 1.1 riastrad timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec);
1286 1.1 riastrad timeout = drm_syncobj_array_wait_timeout(syncobjs,
1287 1.1 riastrad u64_to_user_ptr(timeline_wait->points),
1288 1.1 riastrad timeline_wait->count_handles,
1289 1.1 riastrad timeline_wait->flags,
1290 1.1 riastrad timeout, &first);
1291 1.1 riastrad if (timeout < 0)
1292 1.1 riastrad return timeout;
1293 1.1 riastrad timeline_wait->first_signaled = first;
1294 1.1 riastrad }
1295 1.1 riastrad return 0;
1296 1.1 riastrad }
1297 1.1 riastrad
1298 1.1 riastrad static int drm_syncobj_array_find(struct drm_file *file_private,
1299 1.1 riastrad void __user *user_handles,
1300 1.1 riastrad uint32_t count_handles,
1301 1.1 riastrad struct drm_syncobj ***syncobjs_out)
1302 1.1 riastrad {
1303 1.1 riastrad uint32_t i, *handles;
1304 1.1 riastrad struct drm_syncobj **syncobjs;
1305 1.1 riastrad int ret;
1306 1.1 riastrad
1307 1.1 riastrad handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
1308 1.1 riastrad if (handles == NULL)
1309 1.1 riastrad return -ENOMEM;
1310 1.1 riastrad
1311 1.1 riastrad if (copy_from_user(handles, user_handles,
1312 1.1 riastrad sizeof(uint32_t) * count_handles)) {
1313 1.1 riastrad ret = -EFAULT;
1314 1.1 riastrad goto err_free_handles;
1315 1.1 riastrad }
1316 1.1 riastrad
1317 1.1 riastrad syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
1318 1.1 riastrad if (syncobjs == NULL) {
1319 1.1 riastrad ret = -ENOMEM;
1320 1.1 riastrad goto err_free_handles;
1321 1.1 riastrad }
1322 1.1 riastrad
1323 1.1 riastrad for (i = 0; i < count_handles; i++) {
1324 1.1 riastrad syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
1325 1.1 riastrad if (!syncobjs[i]) {
1326 1.1 riastrad ret = -ENOENT;
1327 1.1 riastrad goto err_put_syncobjs;
1328 1.1 riastrad }
1329 1.1 riastrad }
1330 1.1 riastrad
1331 1.1 riastrad kfree(handles);
1332 1.1 riastrad *syncobjs_out = syncobjs;
1333 1.1 riastrad return 0;
1334 1.1 riastrad
1335 1.1 riastrad err_put_syncobjs:
1336 1.1 riastrad while (i-- > 0)
1337 1.1 riastrad drm_syncobj_put(syncobjs[i]);
1338 1.1 riastrad kfree(syncobjs);
1339 1.1 riastrad err_free_handles:
1340 1.1 riastrad kfree(handles);
1341 1.1 riastrad
1342 1.1 riastrad return ret;
1343 1.1 riastrad }
1344 1.1 riastrad
1345 1.1 riastrad static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
1346 1.1 riastrad uint32_t count)
1347 1.1 riastrad {
1348 1.1 riastrad uint32_t i;
1349 1.1 riastrad for (i = 0; i < count; i++)
1350 1.1 riastrad drm_syncobj_put(syncobjs[i]);
1351 1.1 riastrad kfree(syncobjs);
1352 1.1 riastrad }
1353 1.1 riastrad
1354 1.1 riastrad int
1355 1.1 riastrad drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
1356 1.1 riastrad struct drm_file *file_private)
1357 1.1 riastrad {
1358 1.1 riastrad struct drm_syncobj_wait *args = data;
1359 1.1 riastrad struct drm_syncobj **syncobjs;
1360 1.1 riastrad int ret = 0;
1361 1.1 riastrad
1362 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1363 1.1 riastrad return -EOPNOTSUPP;
1364 1.1 riastrad
1365 1.1 riastrad if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
1366 1.1 riastrad DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
1367 1.1 riastrad return -EINVAL;
1368 1.1 riastrad
1369 1.1 riastrad if (args->count_handles == 0)
1370 1.1 riastrad return -EINVAL;
1371 1.1 riastrad
1372 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1373 1.1 riastrad u64_to_user_ptr(args->handles),
1374 1.1 riastrad args->count_handles,
1375 1.1 riastrad &syncobjs);
1376 1.1 riastrad if (ret < 0)
1377 1.1 riastrad return ret;
1378 1.1 riastrad
1379 1.1 riastrad ret = drm_syncobj_array_wait(dev, file_private,
1380 1.1 riastrad args, NULL, syncobjs, false);
1381 1.1 riastrad
1382 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1383 1.1 riastrad
1384 1.1 riastrad return ret;
1385 1.1 riastrad }
1386 1.1 riastrad
1387 1.1 riastrad int
1388 1.1 riastrad drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
1389 1.1 riastrad struct drm_file *file_private)
1390 1.1 riastrad {
1391 1.1 riastrad struct drm_syncobj_timeline_wait *args = data;
1392 1.1 riastrad struct drm_syncobj **syncobjs;
1393 1.1 riastrad int ret = 0;
1394 1.1 riastrad
1395 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1396 1.1 riastrad return -EOPNOTSUPP;
1397 1.1 riastrad
1398 1.1 riastrad if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
1399 1.1 riastrad DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
1400 1.1 riastrad DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
1401 1.1 riastrad return -EINVAL;
1402 1.1 riastrad
1403 1.1 riastrad if (args->count_handles == 0)
1404 1.1 riastrad return -EINVAL;
1405 1.1 riastrad
1406 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1407 1.1 riastrad u64_to_user_ptr(args->handles),
1408 1.1 riastrad args->count_handles,
1409 1.1 riastrad &syncobjs);
1410 1.1 riastrad if (ret < 0)
1411 1.1 riastrad return ret;
1412 1.1 riastrad
1413 1.1 riastrad ret = drm_syncobj_array_wait(dev, file_private,
1414 1.1 riastrad NULL, args, syncobjs, true);
1415 1.1 riastrad
1416 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1417 1.1 riastrad
1418 1.1 riastrad return ret;
1419 1.1 riastrad }
1420 1.1 riastrad
1421 1.1 riastrad
1422 1.1 riastrad int
1423 1.1 riastrad drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
1424 1.1 riastrad struct drm_file *file_private)
1425 1.1 riastrad {
1426 1.1 riastrad struct drm_syncobj_array *args = data;
1427 1.1 riastrad struct drm_syncobj **syncobjs;
1428 1.1 riastrad uint32_t i;
1429 1.1 riastrad int ret;
1430 1.1 riastrad
1431 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1432 1.1 riastrad return -EOPNOTSUPP;
1433 1.1 riastrad
1434 1.1 riastrad if (args->pad != 0)
1435 1.1 riastrad return -EINVAL;
1436 1.1 riastrad
1437 1.1 riastrad if (args->count_handles == 0)
1438 1.1 riastrad return -EINVAL;
1439 1.1 riastrad
1440 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1441 1.1 riastrad u64_to_user_ptr(args->handles),
1442 1.1 riastrad args->count_handles,
1443 1.1 riastrad &syncobjs);
1444 1.1 riastrad if (ret < 0)
1445 1.1 riastrad return ret;
1446 1.1 riastrad
1447 1.1 riastrad for (i = 0; i < args->count_handles; i++)
1448 1.1 riastrad drm_syncobj_replace_fence(syncobjs[i], NULL);
1449 1.1 riastrad
1450 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1451 1.1 riastrad
1452 1.1 riastrad return 0;
1453 1.1 riastrad }
1454 1.1 riastrad
1455 1.1 riastrad int
1456 1.1 riastrad drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
1457 1.1 riastrad struct drm_file *file_private)
1458 1.1 riastrad {
1459 1.1 riastrad struct drm_syncobj_array *args = data;
1460 1.1 riastrad struct drm_syncobj **syncobjs;
1461 1.1 riastrad uint32_t i;
1462 1.1 riastrad int ret;
1463 1.1 riastrad
1464 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
1465 1.1 riastrad return -EOPNOTSUPP;
1466 1.1 riastrad
1467 1.1 riastrad if (args->pad != 0)
1468 1.1 riastrad return -EINVAL;
1469 1.1 riastrad
1470 1.1 riastrad if (args->count_handles == 0)
1471 1.1 riastrad return -EINVAL;
1472 1.1 riastrad
1473 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1474 1.1 riastrad u64_to_user_ptr(args->handles),
1475 1.1 riastrad args->count_handles,
1476 1.1 riastrad &syncobjs);
1477 1.1 riastrad if (ret < 0)
1478 1.1 riastrad return ret;
1479 1.1 riastrad
1480 1.1 riastrad for (i = 0; i < args->count_handles; i++)
1481 1.1 riastrad drm_syncobj_assign_null_handle(syncobjs[i]);
1482 1.1 riastrad
1483 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1484 1.1 riastrad
1485 1.1 riastrad return ret;
1486 1.1 riastrad }
1487 1.1 riastrad
1488 1.1 riastrad int
1489 1.1 riastrad drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
1490 1.1 riastrad struct drm_file *file_private)
1491 1.1 riastrad {
1492 1.1 riastrad struct drm_syncobj_timeline_array *args = data;
1493 1.1 riastrad struct drm_syncobj **syncobjs;
1494 1.1 riastrad struct dma_fence_chain **chains;
1495 1.1 riastrad uint64_t *points;
1496 1.1 riastrad uint32_t i, j;
1497 1.1 riastrad int ret;
1498 1.1 riastrad
1499 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1500 1.1 riastrad return -EOPNOTSUPP;
1501 1.1 riastrad
1502 1.1 riastrad if (args->flags != 0)
1503 1.1 riastrad return -EINVAL;
1504 1.1 riastrad
1505 1.1 riastrad if (args->count_handles == 0)
1506 1.1 riastrad return -EINVAL;
1507 1.1 riastrad
1508 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1509 1.1 riastrad u64_to_user_ptr(args->handles),
1510 1.1 riastrad args->count_handles,
1511 1.1 riastrad &syncobjs);
1512 1.1 riastrad if (ret < 0)
1513 1.1 riastrad return ret;
1514 1.1 riastrad
1515 1.1 riastrad points = kmalloc_array(args->count_handles, sizeof(*points),
1516 1.1 riastrad GFP_KERNEL);
1517 1.1 riastrad if (!points) {
1518 1.1 riastrad ret = -ENOMEM;
1519 1.1 riastrad goto out;
1520 1.1 riastrad }
1521 1.1 riastrad if (!u64_to_user_ptr(args->points)) {
1522 1.1 riastrad memset(points, 0, args->count_handles * sizeof(uint64_t));
1523 1.1 riastrad } else if (copy_from_user(points, u64_to_user_ptr(args->points),
1524 1.1 riastrad sizeof(uint64_t) * args->count_handles)) {
1525 1.1 riastrad ret = -EFAULT;
1526 1.1 riastrad goto err_points;
1527 1.1 riastrad }
1528 1.1 riastrad
1529 1.1 riastrad chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
1530 1.1 riastrad if (!chains) {
1531 1.1 riastrad ret = -ENOMEM;
1532 1.1 riastrad goto err_points;
1533 1.1 riastrad }
1534 1.1 riastrad for (i = 0; i < args->count_handles; i++) {
1535 1.1 riastrad chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
1536 1.1 riastrad if (!chains[i]) {
1537 1.1 riastrad for (j = 0; j < i; j++)
1538 1.1 riastrad kfree(chains[j]);
1539 1.1 riastrad ret = -ENOMEM;
1540 1.1 riastrad goto err_chains;
1541 1.1 riastrad }
1542 1.1 riastrad }
1543 1.1 riastrad
1544 1.1 riastrad for (i = 0; i < args->count_handles; i++) {
1545 1.1 riastrad struct dma_fence *fence = dma_fence_get_stub();
1546 1.1 riastrad
1547 1.1 riastrad drm_syncobj_add_point(syncobjs[i], chains[i],
1548 1.1 riastrad fence, points[i]);
1549 1.1 riastrad dma_fence_put(fence);
1550 1.1 riastrad }
1551 1.1 riastrad err_chains:
1552 1.1 riastrad kfree(chains);
1553 1.1 riastrad err_points:
1554 1.1 riastrad kfree(points);
1555 1.1 riastrad out:
1556 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1557 1.1 riastrad
1558 1.1 riastrad return ret;
1559 1.1 riastrad }
1560 1.1 riastrad
1561 1.1 riastrad int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
1562 1.1 riastrad struct drm_file *file_private)
1563 1.1 riastrad {
1564 1.1 riastrad struct drm_syncobj_timeline_array *args = data;
1565 1.1 riastrad struct drm_syncobj **syncobjs;
1566 1.1 riastrad uint64_t __user *points = u64_to_user_ptr(args->points);
1567 1.1 riastrad uint32_t i;
1568 1.1 riastrad int ret;
1569 1.1 riastrad
1570 1.1 riastrad if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
1571 1.1 riastrad return -EOPNOTSUPP;
1572 1.1 riastrad
1573 1.1 riastrad if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED)
1574 1.1 riastrad return -EINVAL;
1575 1.1 riastrad
1576 1.1 riastrad if (args->count_handles == 0)
1577 1.1 riastrad return -EINVAL;
1578 1.1 riastrad
1579 1.1 riastrad ret = drm_syncobj_array_find(file_private,
1580 1.1 riastrad u64_to_user_ptr(args->handles),
1581 1.1 riastrad args->count_handles,
1582 1.1 riastrad &syncobjs);
1583 1.1 riastrad if (ret < 0)
1584 1.1 riastrad return ret;
1585 1.1 riastrad
1586 1.1 riastrad for (i = 0; i < args->count_handles; i++) {
1587 1.1 riastrad struct dma_fence_chain *chain;
1588 1.1 riastrad struct dma_fence *fence;
1589 1.1 riastrad uint64_t point;
1590 1.1 riastrad
1591 1.1 riastrad fence = drm_syncobj_fence_get(syncobjs[i]);
1592 1.1 riastrad chain = to_dma_fence_chain(fence);
1593 1.1 riastrad if (chain) {
1594 1.1 riastrad struct dma_fence *iter, *last_signaled =
1595 1.1 riastrad dma_fence_get(fence);
1596 1.1 riastrad
1597 1.1 riastrad if (args->flags &
1598 1.1 riastrad DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) {
1599 1.1 riastrad point = fence->seqno;
1600 1.1 riastrad } else {
1601 1.1 riastrad dma_fence_chain_for_each(iter, fence) {
1602 1.1 riastrad if (iter->context != fence->context) {
1603 1.1 riastrad dma_fence_put(iter);
1604 1.1 riastrad /* It is most likely that timeline has
1605 1.1 riastrad * unorder points. */
1606 1.1 riastrad break;
1607 1.1 riastrad }
1608 1.1 riastrad dma_fence_put(last_signaled);
1609 1.1 riastrad last_signaled = dma_fence_get(iter);
1610 1.1 riastrad }
1611 1.1 riastrad point = dma_fence_is_signaled(last_signaled) ?
1612 1.1 riastrad last_signaled->seqno :
1613 1.1 riastrad to_dma_fence_chain(last_signaled)->prev_seqno;
1614 1.1 riastrad }
1615 1.1 riastrad dma_fence_put(last_signaled);
1616 1.1 riastrad } else {
1617 1.1 riastrad point = 0;
1618 1.1 riastrad }
1619 1.1 riastrad dma_fence_put(fence);
1620 1.1 riastrad ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
1621 1.1 riastrad ret = ret ? -EFAULT : 0;
1622 1.1 riastrad if (ret)
1623 1.1 riastrad break;
1624 1.1 riastrad }
1625 1.1 riastrad drm_syncobj_array_free(syncobjs, args->count_handles);
1626 1.1 riastrad
1627 1.1 riastrad return ret;
1628 1.1 riastrad }
1629