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