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