1*3f2dd94aSFrançois Tigeot /*
2*3f2dd94aSFrançois Tigeot * Copyright 2017 Red Hat
3*3f2dd94aSFrançois Tigeot * Parts ported from amdgpu (fence wait code).
4*3f2dd94aSFrançois Tigeot * Copyright 2016 Advanced Micro Devices, Inc.
5*3f2dd94aSFrançois Tigeot *
6*3f2dd94aSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
7*3f2dd94aSFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
8*3f2dd94aSFrançois Tigeot * to deal in the Software without restriction, including without limitation
9*3f2dd94aSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*3f2dd94aSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
11*3f2dd94aSFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
12*3f2dd94aSFrançois Tigeot *
13*3f2dd94aSFrançois Tigeot * The above copyright notice and this permission notice (including the next
14*3f2dd94aSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the
15*3f2dd94aSFrançois Tigeot * Software.
16*3f2dd94aSFrançois Tigeot *
17*3f2dd94aSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*3f2dd94aSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*3f2dd94aSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20*3f2dd94aSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21*3f2dd94aSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22*3f2dd94aSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23*3f2dd94aSFrançois Tigeot * IN THE SOFTWARE.
24*3f2dd94aSFrançois Tigeot *
25*3f2dd94aSFrançois Tigeot * Authors:
26*3f2dd94aSFrançois Tigeot *
27*3f2dd94aSFrançois Tigeot */
28*3f2dd94aSFrançois Tigeot
29*3f2dd94aSFrançois Tigeot /**
30*3f2dd94aSFrançois Tigeot * DOC: Overview
31*3f2dd94aSFrançois Tigeot *
32*3f2dd94aSFrançois Tigeot * DRM synchronisation objects (syncobj) are a persistent objects,
33*3f2dd94aSFrançois Tigeot * that contain an optional fence. The fence can be updated with a new
34*3f2dd94aSFrançois Tigeot * fence, or be NULL.
35*3f2dd94aSFrançois Tigeot *
36*3f2dd94aSFrançois Tigeot * syncobj's can be waited upon, where it will wait for the underlying
37*3f2dd94aSFrançois Tigeot * fence.
38*3f2dd94aSFrançois Tigeot *
39*3f2dd94aSFrançois Tigeot * syncobj's can be export to fd's and back, these fd's are opaque and
40*3f2dd94aSFrançois Tigeot * have no other use case, except passing the syncobj between processes.
41*3f2dd94aSFrançois Tigeot *
42*3f2dd94aSFrançois Tigeot * Their primary use-case is to implement Vulkan fences and semaphores.
43*3f2dd94aSFrançois Tigeot *
44*3f2dd94aSFrançois Tigeot * syncobj have a kref reference count, but also have an optional file.
45*3f2dd94aSFrançois Tigeot * The file is only created once the syncobj is exported.
46*3f2dd94aSFrançois Tigeot * The file takes a reference on the kref.
47*3f2dd94aSFrançois Tigeot */
48*3f2dd94aSFrançois Tigeot
49*3f2dd94aSFrançois Tigeot #include <drm/drmP.h>
50*3f2dd94aSFrançois Tigeot #include <linux/file.h>
51*3f2dd94aSFrançois Tigeot #include <linux/fs.h>
52*3f2dd94aSFrançois Tigeot #include <linux/anon_inodes.h>
53*3f2dd94aSFrançois Tigeot #include <linux/sync_file.h>
54*3f2dd94aSFrançois Tigeot #include <linux/sched/signal.h>
55*3f2dd94aSFrançois Tigeot
56*3f2dd94aSFrançois Tigeot #include "drm_internal.h"
57*3f2dd94aSFrançois Tigeot #include <drm/drm_syncobj.h>
58*3f2dd94aSFrançois Tigeot
59*3f2dd94aSFrançois Tigeot /**
60*3f2dd94aSFrançois Tigeot * drm_syncobj_find - lookup and reference a sync object.
61*3f2dd94aSFrançois Tigeot * @file_private: drm file private pointer
62*3f2dd94aSFrançois Tigeot * @handle: sync object handle to lookup.
63*3f2dd94aSFrançois Tigeot *
64*3f2dd94aSFrançois Tigeot * Returns a reference to the syncobj pointed to by handle or NULL.
65*3f2dd94aSFrançois Tigeot */
drm_syncobj_find(struct drm_file * file_private,u32 handle)66*3f2dd94aSFrançois Tigeot struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
67*3f2dd94aSFrançois Tigeot u32 handle)
68*3f2dd94aSFrançois Tigeot {
69*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
70*3f2dd94aSFrançois Tigeot
71*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_EXCLUSIVE);
72*3f2dd94aSFrançois Tigeot
73*3f2dd94aSFrançois Tigeot /* Check if we currently have a reference on the object */
74*3f2dd94aSFrançois Tigeot syncobj = idr_find(&file_private->syncobj_idr, handle);
75*3f2dd94aSFrançois Tigeot if (syncobj)
76*3f2dd94aSFrançois Tigeot drm_syncobj_get(syncobj);
77*3f2dd94aSFrançois Tigeot
78*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_RELEASE);
79*3f2dd94aSFrançois Tigeot
80*3f2dd94aSFrançois Tigeot return syncobj;
81*3f2dd94aSFrançois Tigeot }
82*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_find);
83*3f2dd94aSFrançois Tigeot
drm_syncobj_add_callback_locked(struct drm_syncobj * syncobj,struct drm_syncobj_cb * cb,drm_syncobj_func_t func)84*3f2dd94aSFrançois Tigeot static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
85*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cb,
86*3f2dd94aSFrançois Tigeot drm_syncobj_func_t func)
87*3f2dd94aSFrançois Tigeot {
88*3f2dd94aSFrançois Tigeot cb->func = func;
89*3f2dd94aSFrançois Tigeot list_add_tail(&cb->node, &syncobj->cb_list);
90*3f2dd94aSFrançois Tigeot }
91*3f2dd94aSFrançois Tigeot
92*3f2dd94aSFrançois Tigeot #if 0
93*3f2dd94aSFrançois Tigeot static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
94*3f2dd94aSFrançois Tigeot struct dma_fence **fence,
95*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cb,
96*3f2dd94aSFrançois Tigeot drm_syncobj_func_t func)
97*3f2dd94aSFrançois Tigeot {
98*3f2dd94aSFrançois Tigeot int ret;
99*3f2dd94aSFrançois Tigeot
100*3f2dd94aSFrançois Tigeot *fence = drm_syncobj_fence_get(syncobj);
101*3f2dd94aSFrançois Tigeot if (*fence)
102*3f2dd94aSFrançois Tigeot return 1;
103*3f2dd94aSFrançois Tigeot
104*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_EXCLUSIVE);
105*3f2dd94aSFrançois Tigeot /* We've already tried once to get a fence and failed. Now that we
106*3f2dd94aSFrançois Tigeot * have the lock, try one more time just to be sure we don't add a
107*3f2dd94aSFrançois Tigeot * callback when a fence has already been set.
108*3f2dd94aSFrançois Tigeot */
109*3f2dd94aSFrançois Tigeot if (syncobj->fence) {
110*3f2dd94aSFrançois Tigeot *fence = dma_fence_get(syncobj->fence);
111*3f2dd94aSFrançois Tigeot ret = 1;
112*3f2dd94aSFrançois Tigeot } else {
113*3f2dd94aSFrançois Tigeot *fence = NULL;
114*3f2dd94aSFrançois Tigeot drm_syncobj_add_callback_locked(syncobj, cb, func);
115*3f2dd94aSFrançois Tigeot ret = 0;
116*3f2dd94aSFrançois Tigeot }
117*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_RELEASE);
118*3f2dd94aSFrançois Tigeot
119*3f2dd94aSFrançois Tigeot return ret;
120*3f2dd94aSFrançois Tigeot }
121*3f2dd94aSFrançois Tigeot #endif
122*3f2dd94aSFrançois Tigeot
123*3f2dd94aSFrançois Tigeot /**
124*3f2dd94aSFrançois Tigeot * drm_syncobj_add_callback - adds a callback to syncobj::cb_list
125*3f2dd94aSFrançois Tigeot * @syncobj: Sync object to which to add the callback
126*3f2dd94aSFrançois Tigeot * @cb: Callback to add
127*3f2dd94aSFrançois Tigeot * @func: Func to use when initializing the drm_syncobj_cb struct
128*3f2dd94aSFrançois Tigeot *
129*3f2dd94aSFrançois Tigeot * This adds a callback to be called next time the fence is replaced
130*3f2dd94aSFrançois Tigeot */
drm_syncobj_add_callback(struct drm_syncobj * syncobj,struct drm_syncobj_cb * cb,drm_syncobj_func_t func)131*3f2dd94aSFrançois Tigeot void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
132*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cb,
133*3f2dd94aSFrançois Tigeot drm_syncobj_func_t func)
134*3f2dd94aSFrançois Tigeot {
135*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_EXCLUSIVE);
136*3f2dd94aSFrançois Tigeot drm_syncobj_add_callback_locked(syncobj, cb, func);
137*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_RELEASE);
138*3f2dd94aSFrançois Tigeot }
139*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_add_callback);
140*3f2dd94aSFrançois Tigeot
141*3f2dd94aSFrançois Tigeot /**
142*3f2dd94aSFrançois Tigeot * drm_syncobj_add_callback - removes a callback to syncobj::cb_list
143*3f2dd94aSFrançois Tigeot * @syncobj: Sync object from which to remove the callback
144*3f2dd94aSFrançois Tigeot * @cb: Callback to remove
145*3f2dd94aSFrançois Tigeot */
drm_syncobj_remove_callback(struct drm_syncobj * syncobj,struct drm_syncobj_cb * cb)146*3f2dd94aSFrançois Tigeot void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
147*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cb)
148*3f2dd94aSFrançois Tigeot {
149*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_EXCLUSIVE);
150*3f2dd94aSFrançois Tigeot list_del_init(&cb->node);
151*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_RELEASE);
152*3f2dd94aSFrançois Tigeot }
153*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_remove_callback);
154*3f2dd94aSFrançois Tigeot
155*3f2dd94aSFrançois Tigeot /**
156*3f2dd94aSFrançois Tigeot * drm_syncobj_replace_fence - replace fence in a sync object.
157*3f2dd94aSFrançois Tigeot * @syncobj: Sync object to replace fence in
158*3f2dd94aSFrançois Tigeot * @fence: fence to install in sync file.
159*3f2dd94aSFrançois Tigeot *
160*3f2dd94aSFrançois Tigeot * This replaces the fence on a sync object.
161*3f2dd94aSFrançois Tigeot */
drm_syncobj_replace_fence(struct drm_syncobj * syncobj,struct dma_fence * fence)162*3f2dd94aSFrançois Tigeot void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
163*3f2dd94aSFrançois Tigeot struct dma_fence *fence)
164*3f2dd94aSFrançois Tigeot {
165*3f2dd94aSFrançois Tigeot struct dma_fence *old_fence;
166*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cur, *tmp;
167*3f2dd94aSFrançois Tigeot
168*3f2dd94aSFrançois Tigeot if (fence)
169*3f2dd94aSFrançois Tigeot dma_fence_get(fence);
170*3f2dd94aSFrançois Tigeot
171*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_EXCLUSIVE);
172*3f2dd94aSFrançois Tigeot
173*3f2dd94aSFrançois Tigeot old_fence = syncobj->fence;
174*3f2dd94aSFrançois Tigeot syncobj->fence = fence;
175*3f2dd94aSFrançois Tigeot
176*3f2dd94aSFrançois Tigeot if (fence != old_fence) {
177*3f2dd94aSFrançois Tigeot list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
178*3f2dd94aSFrançois Tigeot list_del_init(&cur->node);
179*3f2dd94aSFrançois Tigeot cur->func(syncobj, cur);
180*3f2dd94aSFrançois Tigeot }
181*3f2dd94aSFrançois Tigeot }
182*3f2dd94aSFrançois Tigeot
183*3f2dd94aSFrançois Tigeot lockmgr(&syncobj->lock, LK_RELEASE);
184*3f2dd94aSFrançois Tigeot
185*3f2dd94aSFrançois Tigeot dma_fence_put(old_fence);
186*3f2dd94aSFrançois Tigeot }
187*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_replace_fence);
188*3f2dd94aSFrançois Tigeot
189*3f2dd94aSFrançois Tigeot struct drm_syncobj_null_fence {
190*3f2dd94aSFrançois Tigeot struct dma_fence base;
191*3f2dd94aSFrançois Tigeot spinlock_t lock;
192*3f2dd94aSFrançois Tigeot };
193*3f2dd94aSFrançois Tigeot
drm_syncobj_null_fence_get_name(struct dma_fence * fence)194*3f2dd94aSFrançois Tigeot static const char *drm_syncobj_null_fence_get_name(struct dma_fence *fence)
195*3f2dd94aSFrançois Tigeot {
196*3f2dd94aSFrançois Tigeot return "syncobjnull";
197*3f2dd94aSFrançois Tigeot }
198*3f2dd94aSFrançois Tigeot
drm_syncobj_null_fence_enable_signaling(struct dma_fence * fence)199*3f2dd94aSFrançois Tigeot static bool drm_syncobj_null_fence_enable_signaling(struct dma_fence *fence)
200*3f2dd94aSFrançois Tigeot {
201*3f2dd94aSFrançois Tigeot dma_fence_enable_sw_signaling(fence);
202*3f2dd94aSFrançois Tigeot return !dma_fence_is_signaled(fence);
203*3f2dd94aSFrançois Tigeot }
204*3f2dd94aSFrançois Tigeot
205*3f2dd94aSFrançois Tigeot static const struct dma_fence_ops drm_syncobj_null_fence_ops = {
206*3f2dd94aSFrançois Tigeot .get_driver_name = drm_syncobj_null_fence_get_name,
207*3f2dd94aSFrançois Tigeot .get_timeline_name = drm_syncobj_null_fence_get_name,
208*3f2dd94aSFrançois Tigeot .enable_signaling = drm_syncobj_null_fence_enable_signaling,
209*3f2dd94aSFrançois Tigeot .wait = dma_fence_default_wait,
210*3f2dd94aSFrançois Tigeot .release = NULL,
211*3f2dd94aSFrançois Tigeot };
212*3f2dd94aSFrançois Tigeot
drm_syncobj_assign_null_handle(struct drm_syncobj * syncobj)213*3f2dd94aSFrançois Tigeot static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
214*3f2dd94aSFrançois Tigeot {
215*3f2dd94aSFrançois Tigeot struct drm_syncobj_null_fence *fence;
216*3f2dd94aSFrançois Tigeot fence = kzalloc(sizeof(*fence), GFP_KERNEL);
217*3f2dd94aSFrançois Tigeot if (fence == NULL)
218*3f2dd94aSFrançois Tigeot return -ENOMEM;
219*3f2dd94aSFrançois Tigeot
220*3f2dd94aSFrançois Tigeot lockinit(&fence->lock, "dsofl", 0, 0);
221*3f2dd94aSFrançois Tigeot dma_fence_init(&fence->base, &drm_syncobj_null_fence_ops,
222*3f2dd94aSFrançois Tigeot &fence->lock, 0, 0);
223*3f2dd94aSFrançois Tigeot dma_fence_signal(&fence->base);
224*3f2dd94aSFrançois Tigeot
225*3f2dd94aSFrançois Tigeot drm_syncobj_replace_fence(syncobj, &fence->base);
226*3f2dd94aSFrançois Tigeot
227*3f2dd94aSFrançois Tigeot dma_fence_put(&fence->base);
228*3f2dd94aSFrançois Tigeot
229*3f2dd94aSFrançois Tigeot return 0;
230*3f2dd94aSFrançois Tigeot }
231*3f2dd94aSFrançois Tigeot
drm_syncobj_find_fence(struct drm_file * file_private,u32 handle,struct dma_fence ** fence)232*3f2dd94aSFrançois Tigeot int drm_syncobj_find_fence(struct drm_file *file_private,
233*3f2dd94aSFrançois Tigeot u32 handle,
234*3f2dd94aSFrançois Tigeot struct dma_fence **fence)
235*3f2dd94aSFrançois Tigeot {
236*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
237*3f2dd94aSFrançois Tigeot int ret = 0;
238*3f2dd94aSFrançois Tigeot
239*3f2dd94aSFrançois Tigeot if (!syncobj)
240*3f2dd94aSFrançois Tigeot return -ENOENT;
241*3f2dd94aSFrançois Tigeot
242*3f2dd94aSFrançois Tigeot *fence = drm_syncobj_fence_get(syncobj);
243*3f2dd94aSFrançois Tigeot if (!*fence) {
244*3f2dd94aSFrançois Tigeot ret = -EINVAL;
245*3f2dd94aSFrançois Tigeot }
246*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
247*3f2dd94aSFrançois Tigeot return ret;
248*3f2dd94aSFrançois Tigeot }
249*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_find_fence);
250*3f2dd94aSFrançois Tigeot
251*3f2dd94aSFrançois Tigeot /**
252*3f2dd94aSFrançois Tigeot * drm_syncobj_free - free a sync object.
253*3f2dd94aSFrançois Tigeot * @kref: kref to free.
254*3f2dd94aSFrançois Tigeot *
255*3f2dd94aSFrançois Tigeot * Only to be called from kref_put in drm_syncobj_put.
256*3f2dd94aSFrançois Tigeot */
drm_syncobj_free(struct kref * kref)257*3f2dd94aSFrançois Tigeot void drm_syncobj_free(struct kref *kref)
258*3f2dd94aSFrançois Tigeot {
259*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj = container_of(kref,
260*3f2dd94aSFrançois Tigeot struct drm_syncobj,
261*3f2dd94aSFrançois Tigeot refcount);
262*3f2dd94aSFrançois Tigeot drm_syncobj_replace_fence(syncobj, NULL);
263*3f2dd94aSFrançois Tigeot kfree(syncobj);
264*3f2dd94aSFrançois Tigeot }
265*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_free);
266*3f2dd94aSFrançois Tigeot
267*3f2dd94aSFrançois Tigeot /**
268*3f2dd94aSFrançois Tigeot * drm_syncobj_create - create a new syncobj
269*3f2dd94aSFrançois Tigeot * @out_syncobj: returned syncobj
270*3f2dd94aSFrançois Tigeot * @flags: DRM_SYNCOBJ_* flags
271*3f2dd94aSFrançois Tigeot * @fence: if non-NULL, the syncobj will represent this fence
272*3f2dd94aSFrançois Tigeot */
drm_syncobj_create(struct drm_syncobj ** out_syncobj,uint32_t flags,struct dma_fence * fence)273*3f2dd94aSFrançois Tigeot int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
274*3f2dd94aSFrançois Tigeot struct dma_fence *fence)
275*3f2dd94aSFrançois Tigeot {
276*3f2dd94aSFrançois Tigeot int ret;
277*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
278*3f2dd94aSFrançois Tigeot
279*3f2dd94aSFrançois Tigeot syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
280*3f2dd94aSFrançois Tigeot if (!syncobj)
281*3f2dd94aSFrançois Tigeot return -ENOMEM;
282*3f2dd94aSFrançois Tigeot
283*3f2dd94aSFrançois Tigeot kref_init(&syncobj->refcount);
284*3f2dd94aSFrançois Tigeot INIT_LIST_HEAD(&syncobj->cb_list);
285*3f2dd94aSFrançois Tigeot lockinit(&syncobj->lock, "dsol", 0, 0);
286*3f2dd94aSFrançois Tigeot
287*3f2dd94aSFrançois Tigeot if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
288*3f2dd94aSFrançois Tigeot ret = drm_syncobj_assign_null_handle(syncobj);
289*3f2dd94aSFrançois Tigeot if (ret < 0) {
290*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
291*3f2dd94aSFrançois Tigeot return ret;
292*3f2dd94aSFrançois Tigeot }
293*3f2dd94aSFrançois Tigeot }
294*3f2dd94aSFrançois Tigeot
295*3f2dd94aSFrançois Tigeot if (fence)
296*3f2dd94aSFrançois Tigeot drm_syncobj_replace_fence(syncobj, fence);
297*3f2dd94aSFrançois Tigeot
298*3f2dd94aSFrançois Tigeot *out_syncobj = syncobj;
299*3f2dd94aSFrançois Tigeot return 0;
300*3f2dd94aSFrançois Tigeot }
301*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_create);
302*3f2dd94aSFrançois Tigeot
303*3f2dd94aSFrançois Tigeot /**
304*3f2dd94aSFrançois Tigeot * drm_syncobj_get_handle - get a handle from a syncobj
305*3f2dd94aSFrançois Tigeot */
drm_syncobj_get_handle(struct drm_file * file_private,struct drm_syncobj * syncobj,u32 * handle)306*3f2dd94aSFrançois Tigeot int drm_syncobj_get_handle(struct drm_file *file_private,
307*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj, u32 *handle)
308*3f2dd94aSFrançois Tigeot {
309*3f2dd94aSFrançois Tigeot int ret;
310*3f2dd94aSFrançois Tigeot
311*3f2dd94aSFrançois Tigeot /* take a reference to put in the idr */
312*3f2dd94aSFrançois Tigeot drm_syncobj_get(syncobj);
313*3f2dd94aSFrançois Tigeot
314*3f2dd94aSFrançois Tigeot idr_preload(GFP_KERNEL);
315*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_EXCLUSIVE);
316*3f2dd94aSFrançois Tigeot ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
317*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_RELEASE);
318*3f2dd94aSFrançois Tigeot
319*3f2dd94aSFrançois Tigeot idr_preload_end();
320*3f2dd94aSFrançois Tigeot
321*3f2dd94aSFrançois Tigeot if (ret < 0) {
322*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
323*3f2dd94aSFrançois Tigeot return ret;
324*3f2dd94aSFrançois Tigeot }
325*3f2dd94aSFrançois Tigeot
326*3f2dd94aSFrançois Tigeot *handle = ret;
327*3f2dd94aSFrançois Tigeot return 0;
328*3f2dd94aSFrançois Tigeot }
329*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_get_handle);
330*3f2dd94aSFrançois Tigeot
drm_syncobj_create_as_handle(struct drm_file * file_private,u32 * handle,uint32_t flags)331*3f2dd94aSFrançois Tigeot static int drm_syncobj_create_as_handle(struct drm_file *file_private,
332*3f2dd94aSFrançois Tigeot u32 *handle, uint32_t flags)
333*3f2dd94aSFrançois Tigeot {
334*3f2dd94aSFrançois Tigeot int ret;
335*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
336*3f2dd94aSFrançois Tigeot
337*3f2dd94aSFrançois Tigeot ret = drm_syncobj_create(&syncobj, flags, NULL);
338*3f2dd94aSFrançois Tigeot if (ret)
339*3f2dd94aSFrançois Tigeot return ret;
340*3f2dd94aSFrançois Tigeot
341*3f2dd94aSFrançois Tigeot ret = drm_syncobj_get_handle(file_private, syncobj, handle);
342*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
343*3f2dd94aSFrançois Tigeot return ret;
344*3f2dd94aSFrançois Tigeot }
345*3f2dd94aSFrançois Tigeot
drm_syncobj_destroy(struct drm_file * file_private,u32 handle)346*3f2dd94aSFrançois Tigeot static int drm_syncobj_destroy(struct drm_file *file_private,
347*3f2dd94aSFrançois Tigeot u32 handle)
348*3f2dd94aSFrançois Tigeot {
349*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
350*3f2dd94aSFrançois Tigeot
351*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_EXCLUSIVE);
352*3f2dd94aSFrançois Tigeot syncobj = idr_remove(&file_private->syncobj_idr, handle);
353*3f2dd94aSFrançois Tigeot lockmgr(&file_private->syncobj_table_lock, LK_RELEASE);
354*3f2dd94aSFrançois Tigeot
355*3f2dd94aSFrançois Tigeot if (!syncobj)
356*3f2dd94aSFrançois Tigeot return -EINVAL;
357*3f2dd94aSFrançois Tigeot
358*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
359*3f2dd94aSFrançois Tigeot return 0;
360*3f2dd94aSFrançois Tigeot }
361*3f2dd94aSFrançois Tigeot
362*3f2dd94aSFrançois Tigeot #if 0
363*3f2dd94aSFrançois Tigeot static int drm_syncobj_file_release(struct inode *inode, struct file *file)
364*3f2dd94aSFrançois Tigeot {
365*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj = file->private_data;
366*3f2dd94aSFrançois Tigeot
367*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
368*3f2dd94aSFrançois Tigeot return 0;
369*3f2dd94aSFrançois Tigeot }
370*3f2dd94aSFrançois Tigeot
371*3f2dd94aSFrançois Tigeot static const struct file_operations drm_syncobj_file_fops = {
372*3f2dd94aSFrançois Tigeot .release = drm_syncobj_file_release,
373*3f2dd94aSFrançois Tigeot };
374*3f2dd94aSFrançois Tigeot #endif
375*3f2dd94aSFrançois Tigeot
drm_syncobj_get_fd(struct drm_syncobj * syncobj,int * p_fd)376*3f2dd94aSFrançois Tigeot int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
377*3f2dd94aSFrançois Tigeot {
378*3f2dd94aSFrançois Tigeot struct file *file;
379*3f2dd94aSFrançois Tigeot int fd;
380*3f2dd94aSFrançois Tigeot
381*3f2dd94aSFrançois Tigeot fd = get_unused_fd_flags(O_CLOEXEC);
382*3f2dd94aSFrançois Tigeot if (fd < 0)
383*3f2dd94aSFrançois Tigeot return fd;
384*3f2dd94aSFrançois Tigeot
385*3f2dd94aSFrançois Tigeot #if 0
386*3f2dd94aSFrançois Tigeot file = anon_inode_getfile("syncobj_file",
387*3f2dd94aSFrançois Tigeot &drm_syncobj_file_fops,
388*3f2dd94aSFrançois Tigeot syncobj, 0);
389*3f2dd94aSFrançois Tigeot if (IS_ERR(file)) {
390*3f2dd94aSFrançois Tigeot put_unused_fd(fd);
391*3f2dd94aSFrançois Tigeot return PTR_ERR(file);
392*3f2dd94aSFrançois Tigeot }
393*3f2dd94aSFrançois Tigeot #else
394*3f2dd94aSFrançois Tigeot return -EINVAL;
395*3f2dd94aSFrançois Tigeot #endif
396*3f2dd94aSFrançois Tigeot
397*3f2dd94aSFrançois Tigeot drm_syncobj_get(syncobj);
398*3f2dd94aSFrançois Tigeot fd_install(fd, file);
399*3f2dd94aSFrançois Tigeot
400*3f2dd94aSFrançois Tigeot *p_fd = fd;
401*3f2dd94aSFrançois Tigeot return 0;
402*3f2dd94aSFrançois Tigeot }
403*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_syncobj_get_fd);
404*3f2dd94aSFrançois Tigeot
drm_syncobj_handle_to_fd(struct drm_file * file_private,u32 handle,int * p_fd)405*3f2dd94aSFrançois Tigeot static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
406*3f2dd94aSFrançois Tigeot u32 handle, int *p_fd)
407*3f2dd94aSFrançois Tigeot {
408*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
409*3f2dd94aSFrançois Tigeot int ret;
410*3f2dd94aSFrançois Tigeot
411*3f2dd94aSFrançois Tigeot if (!syncobj)
412*3f2dd94aSFrançois Tigeot return -EINVAL;
413*3f2dd94aSFrançois Tigeot
414*3f2dd94aSFrançois Tigeot ret = drm_syncobj_get_fd(syncobj, p_fd);
415*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
416*3f2dd94aSFrançois Tigeot return ret;
417*3f2dd94aSFrançois Tigeot }
418*3f2dd94aSFrançois Tigeot
419*3f2dd94aSFrançois Tigeot #if 0
420*3f2dd94aSFrançois Tigeot static struct drm_syncobj *drm_syncobj_fdget(int fd)
421*3f2dd94aSFrançois Tigeot {
422*3f2dd94aSFrançois Tigeot struct file *file = fget(fd);
423*3f2dd94aSFrançois Tigeot
424*3f2dd94aSFrançois Tigeot if (!file)
425*3f2dd94aSFrançois Tigeot return NULL;
426*3f2dd94aSFrançois Tigeot if (file->f_op != &drm_syncobj_file_fops)
427*3f2dd94aSFrançois Tigeot goto err;
428*3f2dd94aSFrançois Tigeot
429*3f2dd94aSFrançois Tigeot return file->private_data;
430*3f2dd94aSFrançois Tigeot err:
431*3f2dd94aSFrançois Tigeot fput(file);
432*3f2dd94aSFrançois Tigeot return NULL;
433*3f2dd94aSFrançois Tigeot };
434*3f2dd94aSFrançois Tigeot #endif
435*3f2dd94aSFrançois Tigeot
drm_syncobj_fd_to_handle(struct drm_file * file_private,int fd,u32 * handle)436*3f2dd94aSFrançois Tigeot static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
437*3f2dd94aSFrançois Tigeot int fd, u32 *handle)
438*3f2dd94aSFrançois Tigeot {
439*3f2dd94aSFrançois Tigeot #if 0
440*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
441*3f2dd94aSFrançois Tigeot struct file *file;
442*3f2dd94aSFrançois Tigeot int ret;
443*3f2dd94aSFrançois Tigeot
444*3f2dd94aSFrançois Tigeot file = fget(fd);
445*3f2dd94aSFrançois Tigeot if (!file)
446*3f2dd94aSFrançois Tigeot return -EINVAL;
447*3f2dd94aSFrançois Tigeot
448*3f2dd94aSFrançois Tigeot if (file->f_op != &drm_syncobj_file_fops) {
449*3f2dd94aSFrançois Tigeot fput(file);
450*3f2dd94aSFrançois Tigeot return -EINVAL;
451*3f2dd94aSFrançois Tigeot }
452*3f2dd94aSFrançois Tigeot
453*3f2dd94aSFrançois Tigeot /* take a reference to put in the idr */
454*3f2dd94aSFrançois Tigeot syncobj = file->private_data;
455*3f2dd94aSFrançois Tigeot drm_syncobj_get(syncobj);
456*3f2dd94aSFrançois Tigeot
457*3f2dd94aSFrançois Tigeot idr_preload(GFP_KERNEL);
458*3f2dd94aSFrançois Tigeot spin_lock(&file_private->syncobj_table_lock);
459*3f2dd94aSFrançois Tigeot ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);
460*3f2dd94aSFrançois Tigeot spin_unlock(&file_private->syncobj_table_lock);
461*3f2dd94aSFrançois Tigeot idr_preload_end();
462*3f2dd94aSFrançois Tigeot
463*3f2dd94aSFrançois Tigeot if (ret > 0) {
464*3f2dd94aSFrançois Tigeot *handle = ret;
465*3f2dd94aSFrançois Tigeot ret = 0;
466*3f2dd94aSFrançois Tigeot } else
467*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
468*3f2dd94aSFrançois Tigeot
469*3f2dd94aSFrançois Tigeot fput(file);
470*3f2dd94aSFrançois Tigeot return ret;
471*3f2dd94aSFrançois Tigeot #endif
472*3f2dd94aSFrançois Tigeot return -EINVAL;
473*3f2dd94aSFrançois Tigeot }
474*3f2dd94aSFrançois Tigeot
drm_syncobj_import_sync_file_fence(struct drm_file * file_private,int fd,int handle)475*3f2dd94aSFrançois Tigeot static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
476*3f2dd94aSFrançois Tigeot int fd, int handle)
477*3f2dd94aSFrançois Tigeot {
478*3f2dd94aSFrançois Tigeot struct dma_fence *fence = sync_file_get_fence(fd);
479*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj;
480*3f2dd94aSFrançois Tigeot
481*3f2dd94aSFrançois Tigeot if (!fence)
482*3f2dd94aSFrançois Tigeot return -EINVAL;
483*3f2dd94aSFrançois Tigeot
484*3f2dd94aSFrançois Tigeot syncobj = drm_syncobj_find(file_private, handle);
485*3f2dd94aSFrançois Tigeot if (!syncobj) {
486*3f2dd94aSFrançois Tigeot dma_fence_put(fence);
487*3f2dd94aSFrançois Tigeot return -ENOENT;
488*3f2dd94aSFrançois Tigeot }
489*3f2dd94aSFrançois Tigeot
490*3f2dd94aSFrançois Tigeot drm_syncobj_replace_fence(syncobj, fence);
491*3f2dd94aSFrançois Tigeot dma_fence_put(fence);
492*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
493*3f2dd94aSFrançois Tigeot return 0;
494*3f2dd94aSFrançois Tigeot }
495*3f2dd94aSFrançois Tigeot
drm_syncobj_export_sync_file(struct drm_file * file_private,int handle,int * p_fd)496*3f2dd94aSFrançois Tigeot static int drm_syncobj_export_sync_file(struct drm_file *file_private,
497*3f2dd94aSFrançois Tigeot int handle, int *p_fd)
498*3f2dd94aSFrançois Tigeot {
499*3f2dd94aSFrançois Tigeot int ret;
500*3f2dd94aSFrançois Tigeot struct dma_fence *fence;
501*3f2dd94aSFrançois Tigeot struct sync_file *sync_file;
502*3f2dd94aSFrançois Tigeot int fd = get_unused_fd_flags(O_CLOEXEC);
503*3f2dd94aSFrançois Tigeot
504*3f2dd94aSFrançois Tigeot if (fd < 0)
505*3f2dd94aSFrançois Tigeot return fd;
506*3f2dd94aSFrançois Tigeot
507*3f2dd94aSFrançois Tigeot ret = drm_syncobj_find_fence(file_private, handle, &fence);
508*3f2dd94aSFrançois Tigeot if (ret)
509*3f2dd94aSFrançois Tigeot goto err_put_fd;
510*3f2dd94aSFrançois Tigeot
511*3f2dd94aSFrançois Tigeot sync_file = sync_file_create(fence);
512*3f2dd94aSFrançois Tigeot
513*3f2dd94aSFrançois Tigeot dma_fence_put(fence);
514*3f2dd94aSFrançois Tigeot
515*3f2dd94aSFrançois Tigeot if (!sync_file) {
516*3f2dd94aSFrançois Tigeot ret = -EINVAL;
517*3f2dd94aSFrançois Tigeot goto err_put_fd;
518*3f2dd94aSFrançois Tigeot }
519*3f2dd94aSFrançois Tigeot
520*3f2dd94aSFrançois Tigeot fd_install(fd, sync_file->file);
521*3f2dd94aSFrançois Tigeot
522*3f2dd94aSFrançois Tigeot *p_fd = fd;
523*3f2dd94aSFrançois Tigeot return 0;
524*3f2dd94aSFrançois Tigeot err_put_fd:
525*3f2dd94aSFrançois Tigeot put_unused_fd(fd);
526*3f2dd94aSFrançois Tigeot return ret;
527*3f2dd94aSFrançois Tigeot }
528*3f2dd94aSFrançois Tigeot /**
529*3f2dd94aSFrançois Tigeot * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time
530*3f2dd94aSFrançois Tigeot * @file_private: drm file-private structure to set up
531*3f2dd94aSFrançois Tigeot *
532*3f2dd94aSFrançois Tigeot * Called at device open time, sets up the structure for handling refcounting
533*3f2dd94aSFrançois Tigeot * of sync objects.
534*3f2dd94aSFrançois Tigeot */
535*3f2dd94aSFrançois Tigeot void
drm_syncobj_open(struct drm_file * file_private)536*3f2dd94aSFrançois Tigeot drm_syncobj_open(struct drm_file *file_private)
537*3f2dd94aSFrançois Tigeot {
538*3f2dd94aSFrançois Tigeot idr_init(&file_private->syncobj_idr);
539*3f2dd94aSFrançois Tigeot lockinit(&file_private->syncobj_table_lock, "dsotl", 0, 0);
540*3f2dd94aSFrançois Tigeot }
541*3f2dd94aSFrançois Tigeot
542*3f2dd94aSFrançois Tigeot static int
drm_syncobj_release_handle(int id,void * ptr,void * data)543*3f2dd94aSFrançois Tigeot drm_syncobj_release_handle(int id, void *ptr, void *data)
544*3f2dd94aSFrançois Tigeot {
545*3f2dd94aSFrançois Tigeot struct drm_syncobj *syncobj = ptr;
546*3f2dd94aSFrançois Tigeot
547*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobj);
548*3f2dd94aSFrançois Tigeot return 0;
549*3f2dd94aSFrançois Tigeot }
550*3f2dd94aSFrançois Tigeot
551*3f2dd94aSFrançois Tigeot /**
552*3f2dd94aSFrançois Tigeot * drm_syncobj_release - release file-private sync object resources
553*3f2dd94aSFrançois Tigeot * @file_private: drm file-private structure to clean up
554*3f2dd94aSFrançois Tigeot *
555*3f2dd94aSFrançois Tigeot * Called at close time when the filp is going away.
556*3f2dd94aSFrançois Tigeot *
557*3f2dd94aSFrançois Tigeot * Releases any remaining references on objects by this filp.
558*3f2dd94aSFrançois Tigeot */
559*3f2dd94aSFrançois Tigeot void
drm_syncobj_release(struct drm_file * file_private)560*3f2dd94aSFrançois Tigeot drm_syncobj_release(struct drm_file *file_private)
561*3f2dd94aSFrançois Tigeot {
562*3f2dd94aSFrançois Tigeot idr_for_each(&file_private->syncobj_idr,
563*3f2dd94aSFrançois Tigeot &drm_syncobj_release_handle, file_private);
564*3f2dd94aSFrançois Tigeot idr_destroy(&file_private->syncobj_idr);
565*3f2dd94aSFrançois Tigeot }
566*3f2dd94aSFrançois Tigeot
567*3f2dd94aSFrançois Tigeot int
drm_syncobj_create_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)568*3f2dd94aSFrançois Tigeot drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
569*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
570*3f2dd94aSFrançois Tigeot {
571*3f2dd94aSFrançois Tigeot struct drm_syncobj_create *args = data;
572*3f2dd94aSFrançois Tigeot
573*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
574*3f2dd94aSFrançois Tigeot return -ENODEV;
575*3f2dd94aSFrançois Tigeot
576*3f2dd94aSFrançois Tigeot /* no valid flags yet */
577*3f2dd94aSFrançois Tigeot if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
578*3f2dd94aSFrançois Tigeot return -EINVAL;
579*3f2dd94aSFrançois Tigeot
580*3f2dd94aSFrançois Tigeot return drm_syncobj_create_as_handle(file_private,
581*3f2dd94aSFrançois Tigeot &args->handle, args->flags);
582*3f2dd94aSFrançois Tigeot }
583*3f2dd94aSFrançois Tigeot
584*3f2dd94aSFrançois Tigeot int
drm_syncobj_destroy_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)585*3f2dd94aSFrançois Tigeot drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data,
586*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
587*3f2dd94aSFrançois Tigeot {
588*3f2dd94aSFrançois Tigeot struct drm_syncobj_destroy *args = data;
589*3f2dd94aSFrançois Tigeot
590*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
591*3f2dd94aSFrançois Tigeot return -ENODEV;
592*3f2dd94aSFrançois Tigeot
593*3f2dd94aSFrançois Tigeot /* make sure padding is empty */
594*3f2dd94aSFrançois Tigeot if (args->pad)
595*3f2dd94aSFrançois Tigeot return -EINVAL;
596*3f2dd94aSFrançois Tigeot return drm_syncobj_destroy(file_private, args->handle);
597*3f2dd94aSFrançois Tigeot }
598*3f2dd94aSFrançois Tigeot
599*3f2dd94aSFrançois Tigeot int
drm_syncobj_handle_to_fd_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)600*3f2dd94aSFrançois Tigeot drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
601*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
602*3f2dd94aSFrançois Tigeot {
603*3f2dd94aSFrançois Tigeot struct drm_syncobj_handle *args = data;
604*3f2dd94aSFrançois Tigeot
605*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
606*3f2dd94aSFrançois Tigeot return -ENODEV;
607*3f2dd94aSFrançois Tigeot
608*3f2dd94aSFrançois Tigeot if (args->pad)
609*3f2dd94aSFrançois Tigeot return -EINVAL;
610*3f2dd94aSFrançois Tigeot
611*3f2dd94aSFrançois Tigeot if (args->flags != 0 &&
612*3f2dd94aSFrançois Tigeot args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
613*3f2dd94aSFrançois Tigeot return -EINVAL;
614*3f2dd94aSFrançois Tigeot
615*3f2dd94aSFrançois Tigeot if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
616*3f2dd94aSFrançois Tigeot return drm_syncobj_export_sync_file(file_private, args->handle,
617*3f2dd94aSFrançois Tigeot &args->fd);
618*3f2dd94aSFrançois Tigeot
619*3f2dd94aSFrançois Tigeot return drm_syncobj_handle_to_fd(file_private, args->handle,
620*3f2dd94aSFrançois Tigeot &args->fd);
621*3f2dd94aSFrançois Tigeot }
622*3f2dd94aSFrançois Tigeot
623*3f2dd94aSFrançois Tigeot int
drm_syncobj_fd_to_handle_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)624*3f2dd94aSFrançois Tigeot drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
625*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
626*3f2dd94aSFrançois Tigeot {
627*3f2dd94aSFrançois Tigeot struct drm_syncobj_handle *args = data;
628*3f2dd94aSFrançois Tigeot
629*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
630*3f2dd94aSFrançois Tigeot return -ENODEV;
631*3f2dd94aSFrançois Tigeot
632*3f2dd94aSFrançois Tigeot if (args->pad)
633*3f2dd94aSFrançois Tigeot return -EINVAL;
634*3f2dd94aSFrançois Tigeot
635*3f2dd94aSFrançois Tigeot if (args->flags != 0 &&
636*3f2dd94aSFrançois Tigeot args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
637*3f2dd94aSFrançois Tigeot return -EINVAL;
638*3f2dd94aSFrançois Tigeot
639*3f2dd94aSFrançois Tigeot if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE)
640*3f2dd94aSFrançois Tigeot return drm_syncobj_import_sync_file_fence(file_private,
641*3f2dd94aSFrançois Tigeot args->fd,
642*3f2dd94aSFrançois Tigeot args->handle);
643*3f2dd94aSFrançois Tigeot
644*3f2dd94aSFrançois Tigeot return drm_syncobj_fd_to_handle(file_private, args->fd,
645*3f2dd94aSFrançois Tigeot &args->handle);
646*3f2dd94aSFrançois Tigeot }
647*3f2dd94aSFrançois Tigeot
648*3f2dd94aSFrançois Tigeot #if 0
649*3f2dd94aSFrançois Tigeot struct syncobj_wait_entry {
650*3f2dd94aSFrançois Tigeot struct task_struct *task;
651*3f2dd94aSFrançois Tigeot struct dma_fence *fence;
652*3f2dd94aSFrançois Tigeot struct dma_fence_cb fence_cb;
653*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb syncobj_cb;
654*3f2dd94aSFrançois Tigeot };
655*3f2dd94aSFrançois Tigeot
656*3f2dd94aSFrançois Tigeot static void syncobj_wait_fence_func(struct dma_fence *fence,
657*3f2dd94aSFrançois Tigeot struct dma_fence_cb *cb)
658*3f2dd94aSFrançois Tigeot {
659*3f2dd94aSFrançois Tigeot struct syncobj_wait_entry *wait =
660*3f2dd94aSFrançois Tigeot container_of(cb, struct syncobj_wait_entry, fence_cb);
661*3f2dd94aSFrançois Tigeot
662*3f2dd94aSFrançois Tigeot wake_up_process(wait->task);
663*3f2dd94aSFrançois Tigeot }
664*3f2dd94aSFrançois Tigeot
665*3f2dd94aSFrançois Tigeot static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
666*3f2dd94aSFrançois Tigeot struct drm_syncobj_cb *cb)
667*3f2dd94aSFrançois Tigeot {
668*3f2dd94aSFrançois Tigeot struct syncobj_wait_entry *wait =
669*3f2dd94aSFrançois Tigeot container_of(cb, struct syncobj_wait_entry, syncobj_cb);
670*3f2dd94aSFrançois Tigeot
671*3f2dd94aSFrançois Tigeot /* This happens inside the syncobj lock */
672*3f2dd94aSFrançois Tigeot wait->fence = dma_fence_get(syncobj->fence);
673*3f2dd94aSFrançois Tigeot wake_up_process(wait->task);
674*3f2dd94aSFrançois Tigeot }
675*3f2dd94aSFrançois Tigeot
676*3f2dd94aSFrançois Tigeot static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
677*3f2dd94aSFrançois Tigeot uint32_t count,
678*3f2dd94aSFrançois Tigeot uint32_t flags,
679*3f2dd94aSFrançois Tigeot signed long timeout,
680*3f2dd94aSFrançois Tigeot uint32_t *idx)
681*3f2dd94aSFrançois Tigeot {
682*3f2dd94aSFrançois Tigeot struct syncobj_wait_entry *entries;
683*3f2dd94aSFrançois Tigeot struct dma_fence *fence;
684*3f2dd94aSFrançois Tigeot signed long ret;
685*3f2dd94aSFrançois Tigeot uint32_t signaled_count, i;
686*3f2dd94aSFrançois Tigeot
687*3f2dd94aSFrançois Tigeot entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
688*3f2dd94aSFrançois Tigeot if (!entries)
689*3f2dd94aSFrançois Tigeot return -ENOMEM;
690*3f2dd94aSFrançois Tigeot
691*3f2dd94aSFrançois Tigeot /* Walk the list of sync objects and initialize entries. We do
692*3f2dd94aSFrançois Tigeot * this up-front so that we can properly return -EINVAL if there is
693*3f2dd94aSFrançois Tigeot * a syncobj with a missing fence and then never have the chance of
694*3f2dd94aSFrançois Tigeot * returning -EINVAL again.
695*3f2dd94aSFrançois Tigeot */
696*3f2dd94aSFrançois Tigeot signaled_count = 0;
697*3f2dd94aSFrançois Tigeot for (i = 0; i < count; ++i) {
698*3f2dd94aSFrançois Tigeot entries[i].task = current;
699*3f2dd94aSFrançois Tigeot entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
700*3f2dd94aSFrançois Tigeot if (!entries[i].fence) {
701*3f2dd94aSFrançois Tigeot if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
702*3f2dd94aSFrançois Tigeot continue;
703*3f2dd94aSFrançois Tigeot } else {
704*3f2dd94aSFrançois Tigeot ret = -EINVAL;
705*3f2dd94aSFrançois Tigeot goto cleanup_entries;
706*3f2dd94aSFrançois Tigeot }
707*3f2dd94aSFrançois Tigeot }
708*3f2dd94aSFrançois Tigeot
709*3f2dd94aSFrançois Tigeot if (dma_fence_is_signaled(entries[i].fence)) {
710*3f2dd94aSFrançois Tigeot if (signaled_count == 0 && idx)
711*3f2dd94aSFrançois Tigeot *idx = i;
712*3f2dd94aSFrançois Tigeot signaled_count++;
713*3f2dd94aSFrançois Tigeot }
714*3f2dd94aSFrançois Tigeot }
715*3f2dd94aSFrançois Tigeot
716*3f2dd94aSFrançois Tigeot /* Initialize ret to the max of timeout and 1. That way, the
717*3f2dd94aSFrançois Tigeot * default return value indicates a successful wait and not a
718*3f2dd94aSFrançois Tigeot * timeout.
719*3f2dd94aSFrançois Tigeot */
720*3f2dd94aSFrançois Tigeot ret = max_t(signed long, timeout, 1);
721*3f2dd94aSFrançois Tigeot
722*3f2dd94aSFrançois Tigeot if (signaled_count == count ||
723*3f2dd94aSFrançois Tigeot (signaled_count > 0 &&
724*3f2dd94aSFrançois Tigeot !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
725*3f2dd94aSFrançois Tigeot goto cleanup_entries;
726*3f2dd94aSFrançois Tigeot
727*3f2dd94aSFrançois Tigeot /* There's a very annoying laxness in the dma_fence API here, in
728*3f2dd94aSFrançois Tigeot * that backends are not required to automatically report when a
729*3f2dd94aSFrançois Tigeot * fence is signaled prior to fence->ops->enable_signaling() being
730*3f2dd94aSFrançois Tigeot * called. So here if we fail to match signaled_count, we need to
731*3f2dd94aSFrançois Tigeot * fallthough and try a 0 timeout wait!
732*3f2dd94aSFrançois Tigeot */
733*3f2dd94aSFrançois Tigeot
734*3f2dd94aSFrançois Tigeot if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
735*3f2dd94aSFrançois Tigeot for (i = 0; i < count; ++i) {
736*3f2dd94aSFrançois Tigeot drm_syncobj_fence_get_or_add_callback(syncobjs[i],
737*3f2dd94aSFrançois Tigeot &entries[i].fence,
738*3f2dd94aSFrançois Tigeot &entries[i].syncobj_cb,
739*3f2dd94aSFrançois Tigeot syncobj_wait_syncobj_func);
740*3f2dd94aSFrançois Tigeot }
741*3f2dd94aSFrançois Tigeot }
742*3f2dd94aSFrançois Tigeot
743*3f2dd94aSFrançois Tigeot do {
744*3f2dd94aSFrançois Tigeot set_current_state(TASK_INTERRUPTIBLE);
745*3f2dd94aSFrançois Tigeot
746*3f2dd94aSFrançois Tigeot signaled_count = 0;
747*3f2dd94aSFrançois Tigeot for (i = 0; i < count; ++i) {
748*3f2dd94aSFrançois Tigeot fence = entries[i].fence;
749*3f2dd94aSFrançois Tigeot if (!fence)
750*3f2dd94aSFrançois Tigeot continue;
751*3f2dd94aSFrançois Tigeot
752*3f2dd94aSFrançois Tigeot if (dma_fence_is_signaled(fence) ||
753*3f2dd94aSFrançois Tigeot (!entries[i].fence_cb.func &&
754*3f2dd94aSFrançois Tigeot dma_fence_add_callback(fence,
755*3f2dd94aSFrançois Tigeot &entries[i].fence_cb,
756*3f2dd94aSFrançois Tigeot syncobj_wait_fence_func))) {
757*3f2dd94aSFrançois Tigeot /* The fence has been signaled */
758*3f2dd94aSFrançois Tigeot if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) {
759*3f2dd94aSFrançois Tigeot signaled_count++;
760*3f2dd94aSFrançois Tigeot } else {
761*3f2dd94aSFrançois Tigeot if (idx)
762*3f2dd94aSFrançois Tigeot *idx = i;
763*3f2dd94aSFrançois Tigeot goto done_waiting;
764*3f2dd94aSFrançois Tigeot }
765*3f2dd94aSFrançois Tigeot }
766*3f2dd94aSFrançois Tigeot }
767*3f2dd94aSFrançois Tigeot
768*3f2dd94aSFrançois Tigeot if (signaled_count == count)
769*3f2dd94aSFrançois Tigeot goto done_waiting;
770*3f2dd94aSFrançois Tigeot
771*3f2dd94aSFrançois Tigeot if (timeout == 0) {
772*3f2dd94aSFrançois Tigeot /* If we are doing a 0 timeout wait and we got
773*3f2dd94aSFrançois Tigeot * here, then we just timed out.
774*3f2dd94aSFrançois Tigeot */
775*3f2dd94aSFrançois Tigeot ret = 0;
776*3f2dd94aSFrançois Tigeot goto done_waiting;
777*3f2dd94aSFrançois Tigeot }
778*3f2dd94aSFrançois Tigeot
779*3f2dd94aSFrançois Tigeot ret = schedule_timeout(ret);
780*3f2dd94aSFrançois Tigeot
781*3f2dd94aSFrançois Tigeot if (ret > 0 && signal_pending(current))
782*3f2dd94aSFrançois Tigeot ret = -ERESTARTSYS;
783*3f2dd94aSFrançois Tigeot } while (ret > 0);
784*3f2dd94aSFrançois Tigeot
785*3f2dd94aSFrançois Tigeot done_waiting:
786*3f2dd94aSFrançois Tigeot __set_current_state(TASK_RUNNING);
787*3f2dd94aSFrançois Tigeot
788*3f2dd94aSFrançois Tigeot cleanup_entries:
789*3f2dd94aSFrançois Tigeot for (i = 0; i < count; ++i) {
790*3f2dd94aSFrançois Tigeot if (entries[i].syncobj_cb.func)
791*3f2dd94aSFrançois Tigeot drm_syncobj_remove_callback(syncobjs[i],
792*3f2dd94aSFrançois Tigeot &entries[i].syncobj_cb);
793*3f2dd94aSFrançois Tigeot if (entries[i].fence_cb.func)
794*3f2dd94aSFrançois Tigeot dma_fence_remove_callback(entries[i].fence,
795*3f2dd94aSFrançois Tigeot &entries[i].fence_cb);
796*3f2dd94aSFrançois Tigeot dma_fence_put(entries[i].fence);
797*3f2dd94aSFrançois Tigeot }
798*3f2dd94aSFrançois Tigeot kfree(entries);
799*3f2dd94aSFrançois Tigeot
800*3f2dd94aSFrançois Tigeot return ret;
801*3f2dd94aSFrançois Tigeot }
802*3f2dd94aSFrançois Tigeot
803*3f2dd94aSFrançois Tigeot /**
804*3f2dd94aSFrançois Tigeot * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
805*3f2dd94aSFrançois Tigeot *
806*3f2dd94aSFrançois Tigeot * @timeout_nsec: timeout nsec component in ns, 0 for poll
807*3f2dd94aSFrançois Tigeot *
808*3f2dd94aSFrançois Tigeot * Calculate the timeout in jiffies from an absolute time in sec/nsec.
809*3f2dd94aSFrançois Tigeot */
810*3f2dd94aSFrançois Tigeot static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
811*3f2dd94aSFrançois Tigeot {
812*3f2dd94aSFrançois Tigeot ktime_t abs_timeout, now;
813*3f2dd94aSFrançois Tigeot u64 timeout_ns, timeout_jiffies64;
814*3f2dd94aSFrançois Tigeot
815*3f2dd94aSFrançois Tigeot /* make 0 timeout means poll - absolute 0 doesn't seem valid */
816*3f2dd94aSFrançois Tigeot if (timeout_nsec == 0)
817*3f2dd94aSFrançois Tigeot return 0;
818*3f2dd94aSFrançois Tigeot
819*3f2dd94aSFrançois Tigeot abs_timeout = ns_to_ktime(timeout_nsec);
820*3f2dd94aSFrançois Tigeot now = ktime_get();
821*3f2dd94aSFrançois Tigeot
822*3f2dd94aSFrançois Tigeot if (!ktime_after(abs_timeout, now))
823*3f2dd94aSFrançois Tigeot return 0;
824*3f2dd94aSFrançois Tigeot
825*3f2dd94aSFrançois Tigeot timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
826*3f2dd94aSFrançois Tigeot
827*3f2dd94aSFrançois Tigeot timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
828*3f2dd94aSFrançois Tigeot /* clamp timeout to avoid infinite timeout */
829*3f2dd94aSFrançois Tigeot if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
830*3f2dd94aSFrançois Tigeot return MAX_SCHEDULE_TIMEOUT - 1;
831*3f2dd94aSFrançois Tigeot
832*3f2dd94aSFrançois Tigeot return timeout_jiffies64 + 1;
833*3f2dd94aSFrançois Tigeot }
834*3f2dd94aSFrançois Tigeot
835*3f2dd94aSFrançois Tigeot static int drm_syncobj_array_wait(struct drm_device *dev,
836*3f2dd94aSFrançois Tigeot struct drm_file *file_private,
837*3f2dd94aSFrançois Tigeot struct drm_syncobj_wait *wait,
838*3f2dd94aSFrançois Tigeot struct drm_syncobj **syncobjs)
839*3f2dd94aSFrançois Tigeot {
840*3f2dd94aSFrançois Tigeot signed long timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
841*3f2dd94aSFrançois Tigeot signed long ret = 0;
842*3f2dd94aSFrançois Tigeot uint32_t first = ~0;
843*3f2dd94aSFrançois Tigeot
844*3f2dd94aSFrançois Tigeot ret = drm_syncobj_array_wait_timeout(syncobjs,
845*3f2dd94aSFrançois Tigeot wait->count_handles,
846*3f2dd94aSFrançois Tigeot wait->flags,
847*3f2dd94aSFrançois Tigeot timeout, &first);
848*3f2dd94aSFrançois Tigeot if (ret < 0)
849*3f2dd94aSFrançois Tigeot return ret;
850*3f2dd94aSFrançois Tigeot
851*3f2dd94aSFrançois Tigeot wait->first_signaled = first;
852*3f2dd94aSFrançois Tigeot if (ret == 0)
853*3f2dd94aSFrançois Tigeot return -ETIME;
854*3f2dd94aSFrançois Tigeot return 0;
855*3f2dd94aSFrançois Tigeot }
856*3f2dd94aSFrançois Tigeot #endif
857*3f2dd94aSFrançois Tigeot
drm_syncobj_array_find(struct drm_file * file_private,void __user * user_handles,uint32_t count_handles,struct drm_syncobj *** syncobjs_out)858*3f2dd94aSFrançois Tigeot static int drm_syncobj_array_find(struct drm_file *file_private,
859*3f2dd94aSFrançois Tigeot void __user *user_handles,
860*3f2dd94aSFrançois Tigeot uint32_t count_handles,
861*3f2dd94aSFrançois Tigeot struct drm_syncobj ***syncobjs_out)
862*3f2dd94aSFrançois Tigeot {
863*3f2dd94aSFrançois Tigeot uint32_t i, *handles;
864*3f2dd94aSFrançois Tigeot struct drm_syncobj **syncobjs;
865*3f2dd94aSFrançois Tigeot int ret;
866*3f2dd94aSFrançois Tigeot
867*3f2dd94aSFrançois Tigeot handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL);
868*3f2dd94aSFrançois Tigeot if (handles == NULL)
869*3f2dd94aSFrançois Tigeot return -ENOMEM;
870*3f2dd94aSFrançois Tigeot
871*3f2dd94aSFrançois Tigeot if (copy_from_user(handles, user_handles,
872*3f2dd94aSFrançois Tigeot sizeof(uint32_t) * count_handles)) {
873*3f2dd94aSFrançois Tigeot ret = -EFAULT;
874*3f2dd94aSFrançois Tigeot goto err_free_handles;
875*3f2dd94aSFrançois Tigeot }
876*3f2dd94aSFrançois Tigeot
877*3f2dd94aSFrançois Tigeot syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL);
878*3f2dd94aSFrançois Tigeot if (syncobjs == NULL) {
879*3f2dd94aSFrançois Tigeot ret = -ENOMEM;
880*3f2dd94aSFrançois Tigeot goto err_free_handles;
881*3f2dd94aSFrançois Tigeot }
882*3f2dd94aSFrançois Tigeot
883*3f2dd94aSFrançois Tigeot for (i = 0; i < count_handles; i++) {
884*3f2dd94aSFrançois Tigeot syncobjs[i] = drm_syncobj_find(file_private, handles[i]);
885*3f2dd94aSFrançois Tigeot if (!syncobjs[i]) {
886*3f2dd94aSFrançois Tigeot ret = -ENOENT;
887*3f2dd94aSFrançois Tigeot goto err_put_syncobjs;
888*3f2dd94aSFrançois Tigeot }
889*3f2dd94aSFrançois Tigeot }
890*3f2dd94aSFrançois Tigeot
891*3f2dd94aSFrançois Tigeot kfree(handles);
892*3f2dd94aSFrançois Tigeot *syncobjs_out = syncobjs;
893*3f2dd94aSFrançois Tigeot return 0;
894*3f2dd94aSFrançois Tigeot
895*3f2dd94aSFrançois Tigeot err_put_syncobjs:
896*3f2dd94aSFrançois Tigeot while (i-- > 0)
897*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobjs[i]);
898*3f2dd94aSFrançois Tigeot kfree(syncobjs);
899*3f2dd94aSFrançois Tigeot err_free_handles:
900*3f2dd94aSFrançois Tigeot kfree(handles);
901*3f2dd94aSFrançois Tigeot
902*3f2dd94aSFrançois Tigeot return ret;
903*3f2dd94aSFrançois Tigeot }
904*3f2dd94aSFrançois Tigeot
drm_syncobj_array_free(struct drm_syncobj ** syncobjs,uint32_t count)905*3f2dd94aSFrançois Tigeot static void drm_syncobj_array_free(struct drm_syncobj **syncobjs,
906*3f2dd94aSFrançois Tigeot uint32_t count)
907*3f2dd94aSFrançois Tigeot {
908*3f2dd94aSFrançois Tigeot uint32_t i;
909*3f2dd94aSFrançois Tigeot for (i = 0; i < count; i++)
910*3f2dd94aSFrançois Tigeot drm_syncobj_put(syncobjs[i]);
911*3f2dd94aSFrançois Tigeot kfree(syncobjs);
912*3f2dd94aSFrançois Tigeot }
913*3f2dd94aSFrançois Tigeot
914*3f2dd94aSFrançois Tigeot int
drm_syncobj_wait_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)915*3f2dd94aSFrançois Tigeot drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
916*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
917*3f2dd94aSFrançois Tigeot {
918*3f2dd94aSFrançois Tigeot #if 0
919*3f2dd94aSFrançois Tigeot struct drm_syncobj_wait *args = data;
920*3f2dd94aSFrançois Tigeot struct drm_syncobj **syncobjs;
921*3f2dd94aSFrançois Tigeot int ret = 0;
922*3f2dd94aSFrançois Tigeot
923*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
924*3f2dd94aSFrançois Tigeot return -ENODEV;
925*3f2dd94aSFrançois Tigeot
926*3f2dd94aSFrançois Tigeot if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
927*3f2dd94aSFrançois Tigeot DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
928*3f2dd94aSFrançois Tigeot return -EINVAL;
929*3f2dd94aSFrançois Tigeot
930*3f2dd94aSFrançois Tigeot if (args->count_handles == 0)
931*3f2dd94aSFrançois Tigeot return -EINVAL;
932*3f2dd94aSFrançois Tigeot
933*3f2dd94aSFrançois Tigeot ret = drm_syncobj_array_find(file_private,
934*3f2dd94aSFrançois Tigeot u64_to_user_ptr(args->handles),
935*3f2dd94aSFrançois Tigeot args->count_handles,
936*3f2dd94aSFrançois Tigeot &syncobjs);
937*3f2dd94aSFrançois Tigeot if (ret < 0)
938*3f2dd94aSFrançois Tigeot return ret;
939*3f2dd94aSFrançois Tigeot
940*3f2dd94aSFrançois Tigeot ret = drm_syncobj_array_wait(dev, file_private,
941*3f2dd94aSFrançois Tigeot args, syncobjs);
942*3f2dd94aSFrançois Tigeot
943*3f2dd94aSFrançois Tigeot drm_syncobj_array_free(syncobjs, args->count_handles);
944*3f2dd94aSFrançois Tigeot
945*3f2dd94aSFrançois Tigeot return ret;
946*3f2dd94aSFrançois Tigeot #endif
947*3f2dd94aSFrançois Tigeot return -EINVAL;
948*3f2dd94aSFrançois Tigeot }
949*3f2dd94aSFrançois Tigeot
950*3f2dd94aSFrançois Tigeot int
drm_syncobj_reset_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)951*3f2dd94aSFrançois Tigeot drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
952*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
953*3f2dd94aSFrançois Tigeot {
954*3f2dd94aSFrançois Tigeot struct drm_syncobj_array *args = data;
955*3f2dd94aSFrançois Tigeot struct drm_syncobj **syncobjs;
956*3f2dd94aSFrançois Tigeot uint32_t i;
957*3f2dd94aSFrançois Tigeot int ret;
958*3f2dd94aSFrançois Tigeot
959*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
960*3f2dd94aSFrançois Tigeot return -ENODEV;
961*3f2dd94aSFrançois Tigeot
962*3f2dd94aSFrançois Tigeot if (args->pad != 0)
963*3f2dd94aSFrançois Tigeot return -EINVAL;
964*3f2dd94aSFrançois Tigeot
965*3f2dd94aSFrançois Tigeot if (args->count_handles == 0)
966*3f2dd94aSFrançois Tigeot return -EINVAL;
967*3f2dd94aSFrançois Tigeot
968*3f2dd94aSFrançois Tigeot ret = drm_syncobj_array_find(file_private,
969*3f2dd94aSFrançois Tigeot u64_to_user_ptr(args->handles),
970*3f2dd94aSFrançois Tigeot args->count_handles,
971*3f2dd94aSFrançois Tigeot &syncobjs);
972*3f2dd94aSFrançois Tigeot if (ret < 0)
973*3f2dd94aSFrançois Tigeot return ret;
974*3f2dd94aSFrançois Tigeot
975*3f2dd94aSFrançois Tigeot for (i = 0; i < args->count_handles; i++)
976*3f2dd94aSFrançois Tigeot drm_syncobj_replace_fence(syncobjs[i], NULL);
977*3f2dd94aSFrançois Tigeot
978*3f2dd94aSFrançois Tigeot drm_syncobj_array_free(syncobjs, args->count_handles);
979*3f2dd94aSFrançois Tigeot
980*3f2dd94aSFrançois Tigeot return 0;
981*3f2dd94aSFrançois Tigeot }
982*3f2dd94aSFrançois Tigeot
983*3f2dd94aSFrançois Tigeot int
drm_syncobj_signal_ioctl(struct drm_device * dev,void * data,struct drm_file * file_private)984*3f2dd94aSFrançois Tigeot drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
985*3f2dd94aSFrançois Tigeot struct drm_file *file_private)
986*3f2dd94aSFrançois Tigeot {
987*3f2dd94aSFrançois Tigeot struct drm_syncobj_array *args = data;
988*3f2dd94aSFrançois Tigeot struct drm_syncobj **syncobjs;
989*3f2dd94aSFrançois Tigeot uint32_t i;
990*3f2dd94aSFrançois Tigeot int ret;
991*3f2dd94aSFrançois Tigeot
992*3f2dd94aSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
993*3f2dd94aSFrançois Tigeot return -ENODEV;
994*3f2dd94aSFrançois Tigeot
995*3f2dd94aSFrançois Tigeot if (args->pad != 0)
996*3f2dd94aSFrançois Tigeot return -EINVAL;
997*3f2dd94aSFrançois Tigeot
998*3f2dd94aSFrançois Tigeot if (args->count_handles == 0)
999*3f2dd94aSFrançois Tigeot return -EINVAL;
1000*3f2dd94aSFrançois Tigeot
1001*3f2dd94aSFrançois Tigeot ret = drm_syncobj_array_find(file_private,
1002*3f2dd94aSFrançois Tigeot u64_to_user_ptr(args->handles),
1003*3f2dd94aSFrançois Tigeot args->count_handles,
1004*3f2dd94aSFrançois Tigeot &syncobjs);
1005*3f2dd94aSFrançois Tigeot if (ret < 0)
1006*3f2dd94aSFrançois Tigeot return ret;
1007*3f2dd94aSFrançois Tigeot
1008*3f2dd94aSFrançois Tigeot for (i = 0; i < args->count_handles; i++) {
1009*3f2dd94aSFrançois Tigeot ret = drm_syncobj_assign_null_handle(syncobjs[i]);
1010*3f2dd94aSFrançois Tigeot if (ret < 0)
1011*3f2dd94aSFrançois Tigeot break;
1012*3f2dd94aSFrançois Tigeot }
1013*3f2dd94aSFrançois Tigeot
1014*3f2dd94aSFrançois Tigeot drm_syncobj_array_free(syncobjs, args->count_handles);
1015*3f2dd94aSFrançois Tigeot
1016*3f2dd94aSFrançois Tigeot return ret;
1017*3f2dd94aSFrançois Tigeot }
1018