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