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