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