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, see struct &drm_syncobj) are 33 * persistent objects that contain an optional fence. The fence can be updated 34 * with a new 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 struct syncobj_wait_entry { 60 struct list_head node; 61 struct task_struct *task; 62 struct dma_fence *fence; 63 struct dma_fence_cb fence_cb; 64 u64 point; 65 }; 66 67 static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj, 68 struct syncobj_wait_entry *wait); 69 70 /** 71 * drm_syncobj_find - lookup and reference a sync object. 72 * @file_private: drm file private pointer 73 * @handle: sync object handle to lookup. 74 * 75 * Returns a reference to the syncobj pointed to by handle or NULL. The 76 * reference must be released by calling drm_syncobj_put(). 77 */ 78 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, 79 u32 handle) 80 { 81 struct drm_syncobj *syncobj; 82 83 spin_lock(&file_private->syncobj_table_lock); 84 85 /* Check if we currently have a reference on the object */ 86 syncobj = idr_find(&file_private->syncobj_idr, handle); 87 if (syncobj) 88 drm_syncobj_get(syncobj); 89 90 spin_unlock(&file_private->syncobj_table_lock); 91 92 return syncobj; 93 } 94 EXPORT_SYMBOL(drm_syncobj_find); 95 96 static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj, 97 struct syncobj_wait_entry *wait) 98 { 99 struct dma_fence *fence; 100 101 if (wait->fence) 102 return; 103 104 spin_lock(&syncobj->lock); 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 fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1)); 110 if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) { 111 dma_fence_put(fence); 112 list_add_tail(&wait->node, &syncobj->cb_list); 113 } else if (!fence) { 114 wait->fence = dma_fence_get_stub(); 115 } else { 116 wait->fence = fence; 117 } 118 spin_unlock(&syncobj->lock); 119 } 120 121 static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj, 122 struct syncobj_wait_entry *wait) 123 { 124 if (!wait->node.next) 125 return; 126 127 spin_lock(&syncobj->lock); 128 list_del_init(&wait->node); 129 spin_unlock(&syncobj->lock); 130 } 131 132 /** 133 * drm_syncobj_add_point - add new timeline point to the syncobj 134 * @syncobj: sync object to add timeline point do 135 * @chain: chain node to use to add the point 136 * @fence: fence to encapsulate in the chain node 137 * @point: sequence number to use for the point 138 * 139 * Add the chain node as new timeline point to the syncobj. 140 */ 141 void drm_syncobj_add_point(struct drm_syncobj *syncobj, 142 struct dma_fence_chain *chain, 143 struct dma_fence *fence, 144 uint64_t point) 145 { 146 struct syncobj_wait_entry *cur, *tmp; 147 struct dma_fence *prev; 148 149 dma_fence_get(fence); 150 151 spin_lock(&syncobj->lock); 152 153 prev = drm_syncobj_fence_get(syncobj); 154 /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */ 155 if (prev && prev->seqno >= point) 156 DRM_ERROR("You are adding an unorder point to timeline!\n"); 157 dma_fence_chain_init(chain, prev, fence, point); 158 rcu_assign_pointer(syncobj->fence, &chain->base); 159 160 list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) 161 syncobj_wait_syncobj_func(syncobj, cur); 162 spin_unlock(&syncobj->lock); 163 164 /* Walk the chain once to trigger garbage collection */ 165 dma_fence_chain_for_each(fence, prev); 166 dma_fence_put(prev); 167 } 168 EXPORT_SYMBOL(drm_syncobj_add_point); 169 170 /** 171 * drm_syncobj_replace_fence - replace fence in a sync object. 172 * @syncobj: Sync object to replace fence in 173 * @fence: fence to install in sync file. 174 * 175 * This replaces the fence on a sync object. 176 */ 177 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, 178 struct dma_fence *fence) 179 { 180 struct dma_fence *old_fence; 181 struct syncobj_wait_entry *cur, *tmp; 182 183 if (fence) 184 dma_fence_get(fence); 185 186 spin_lock(&syncobj->lock); 187 188 old_fence = rcu_dereference_protected(syncobj->fence, 189 lockdep_is_held(&syncobj->lock)); 190 rcu_assign_pointer(syncobj->fence, fence); 191 192 if (fence != old_fence) { 193 list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) 194 syncobj_wait_syncobj_func(syncobj, cur); 195 } 196 197 spin_unlock(&syncobj->lock); 198 199 dma_fence_put(old_fence); 200 } 201 EXPORT_SYMBOL(drm_syncobj_replace_fence); 202 203 /** 204 * drm_syncobj_assign_null_handle - assign a stub fence to the sync object 205 * @syncobj: sync object to assign the fence on 206 * 207 * Assign a already signaled stub fence to the sync object. 208 */ 209 static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) 210 { 211 struct dma_fence *fence = dma_fence_get_stub(); 212 213 drm_syncobj_replace_fence(syncobj, fence); 214 dma_fence_put(fence); 215 } 216 217 /* 5s default for wait submission */ 218 #define DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT 5000000000ULL 219 /** 220 * drm_syncobj_find_fence - lookup and reference the fence in a sync object 221 * @file_private: drm file private pointer 222 * @handle: sync object handle to lookup. 223 * @point: timeline point 224 * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not 225 * @fence: out parameter for the fence 226 * 227 * This is just a convenience function that combines drm_syncobj_find() and 228 * drm_syncobj_fence_get(). 229 * 230 * Returns 0 on success or a negative error value on failure. On success @fence 231 * contains a reference to the fence, which must be released by calling 232 * dma_fence_put(). 233 */ 234 int drm_syncobj_find_fence(struct drm_file *file_private, 235 u32 handle, u64 point, u64 flags, 236 struct dma_fence **fence) 237 { 238 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); 239 struct syncobj_wait_entry wait; 240 u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT); 241 int ret; 242 243 if (!syncobj) 244 return -ENOENT; 245 246 *fence = drm_syncobj_fence_get(syncobj); 247 drm_syncobj_put(syncobj); 248 249 if (*fence) { 250 ret = dma_fence_chain_find_seqno(fence, point); 251 if (!ret) 252 return 0; 253 dma_fence_put(*fence); 254 } else { 255 ret = -EINVAL; 256 } 257 258 if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)) 259 return ret; 260 261 memset(&wait, 0, sizeof(wait)); 262 wait.task = current; 263 wait.point = point; 264 drm_syncobj_fence_add_wait(syncobj, &wait); 265 266 do { 267 set_current_state(TASK_INTERRUPTIBLE); 268 if (wait.fence) { 269 ret = 0; 270 break; 271 } 272 if (timeout == 0) { 273 ret = -ETIME; 274 break; 275 } 276 277 if (signal_pending(current)) { 278 ret = -ERESTARTSYS; 279 break; 280 } 281 282 timeout = schedule_timeout(timeout); 283 } while (1); 284 285 __set_current_state(TASK_RUNNING); 286 *fence = wait.fence; 287 288 if (wait.node.next) 289 drm_syncobj_remove_wait(syncobj, &wait); 290 291 return ret; 292 } 293 EXPORT_SYMBOL(drm_syncobj_find_fence); 294 295 /** 296 * drm_syncobj_free - free a sync object. 297 * @kref: kref to free. 298 * 299 * Only to be called from kref_put in drm_syncobj_put. 300 */ 301 void drm_syncobj_free(struct kref *kref) 302 { 303 struct drm_syncobj *syncobj = container_of(kref, 304 struct drm_syncobj, 305 refcount); 306 drm_syncobj_replace_fence(syncobj, NULL); 307 kfree(syncobj); 308 } 309 EXPORT_SYMBOL(drm_syncobj_free); 310 311 /** 312 * drm_syncobj_create - create a new syncobj 313 * @out_syncobj: returned syncobj 314 * @flags: DRM_SYNCOBJ_* flags 315 * @fence: if non-NULL, the syncobj will represent this fence 316 * 317 * This is the first function to create a sync object. After creating, drivers 318 * probably want to make it available to userspace, either through 319 * drm_syncobj_get_handle() or drm_syncobj_get_fd(). 320 * 321 * Returns 0 on success or a negative error value on failure. 322 */ 323 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, 324 struct dma_fence *fence) 325 { 326 struct drm_syncobj *syncobj; 327 328 syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL); 329 if (!syncobj) 330 return -ENOMEM; 331 332 kref_init(&syncobj->refcount); 333 INIT_LIST_HEAD(&syncobj->cb_list); 334 spin_lock_init(&syncobj->lock); 335 336 if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) 337 drm_syncobj_assign_null_handle(syncobj); 338 339 if (fence) 340 drm_syncobj_replace_fence(syncobj, fence); 341 342 *out_syncobj = syncobj; 343 return 0; 344 } 345 EXPORT_SYMBOL(drm_syncobj_create); 346 347 /** 348 * drm_syncobj_get_handle - get a handle from a syncobj 349 * @file_private: drm file private pointer 350 * @syncobj: Sync object to export 351 * @handle: out parameter with the new handle 352 * 353 * Exports a sync object created with drm_syncobj_create() as a handle on 354 * @file_private to userspace. 355 * 356 * Returns 0 on success or a negative error value on failure. 357 */ 358 int drm_syncobj_get_handle(struct drm_file *file_private, 359 struct drm_syncobj *syncobj, u32 *handle) 360 { 361 int ret; 362 363 /* take a reference to put in the idr */ 364 drm_syncobj_get(syncobj); 365 366 idr_preload(GFP_KERNEL); 367 spin_lock(&file_private->syncobj_table_lock); 368 ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT); 369 spin_unlock(&file_private->syncobj_table_lock); 370 371 idr_preload_end(); 372 373 if (ret < 0) { 374 drm_syncobj_put(syncobj); 375 return ret; 376 } 377 378 *handle = ret; 379 return 0; 380 } 381 EXPORT_SYMBOL(drm_syncobj_get_handle); 382 383 static int drm_syncobj_create_as_handle(struct drm_file *file_private, 384 u32 *handle, uint32_t flags) 385 { 386 int ret; 387 struct drm_syncobj *syncobj; 388 389 ret = drm_syncobj_create(&syncobj, flags, NULL); 390 if (ret) 391 return ret; 392 393 ret = drm_syncobj_get_handle(file_private, syncobj, handle); 394 drm_syncobj_put(syncobj); 395 return ret; 396 } 397 398 static int drm_syncobj_destroy(struct drm_file *file_private, 399 u32 handle) 400 { 401 struct drm_syncobj *syncobj; 402 403 spin_lock(&file_private->syncobj_table_lock); 404 syncobj = idr_remove(&file_private->syncobj_idr, handle); 405 spin_unlock(&file_private->syncobj_table_lock); 406 407 if (!syncobj) 408 return -EINVAL; 409 410 drm_syncobj_put(syncobj); 411 return 0; 412 } 413 414 static int drm_syncobj_file_release(struct inode *inode, struct file *file) 415 { 416 struct drm_syncobj *syncobj = file->private_data; 417 418 drm_syncobj_put(syncobj); 419 return 0; 420 } 421 422 static const struct file_operations drm_syncobj_file_fops = { 423 .release = drm_syncobj_file_release, 424 }; 425 426 /** 427 * drm_syncobj_get_fd - get a file descriptor from a syncobj 428 * @syncobj: Sync object to export 429 * @p_fd: out parameter with the new file descriptor 430 * 431 * Exports a sync object created with drm_syncobj_create() as a file descriptor. 432 * 433 * Returns 0 on success or a negative error value on failure. 434 */ 435 int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd) 436 { 437 struct file *file; 438 int fd; 439 440 fd = get_unused_fd_flags(O_CLOEXEC); 441 if (fd < 0) 442 return fd; 443 444 file = anon_inode_getfile("syncobj_file", 445 &drm_syncobj_file_fops, 446 syncobj, 0); 447 if (IS_ERR(file)) { 448 put_unused_fd(fd); 449 return PTR_ERR(file); 450 } 451 452 drm_syncobj_get(syncobj); 453 fd_install(fd, file); 454 455 *p_fd = fd; 456 return 0; 457 } 458 EXPORT_SYMBOL(drm_syncobj_get_fd); 459 460 static int drm_syncobj_handle_to_fd(struct drm_file *file_private, 461 u32 handle, int *p_fd) 462 { 463 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); 464 int ret; 465 466 if (!syncobj) 467 return -EINVAL; 468 469 ret = drm_syncobj_get_fd(syncobj, p_fd); 470 drm_syncobj_put(syncobj); 471 return ret; 472 } 473 474 static int drm_syncobj_fd_to_handle(struct drm_file *file_private, 475 int fd, u32 *handle) 476 { 477 struct drm_syncobj *syncobj; 478 struct fd f = fdget(fd); 479 int ret; 480 481 if (!f.file) 482 return -EINVAL; 483 484 if (f.file->f_op != &drm_syncobj_file_fops) { 485 fdput(f); 486 return -EINVAL; 487 } 488 489 /* take a reference to put in the idr */ 490 syncobj = f.file->private_data; 491 drm_syncobj_get(syncobj); 492 493 idr_preload(GFP_KERNEL); 494 spin_lock(&file_private->syncobj_table_lock); 495 ret = idr_alloc(&file_private->syncobj_idr, syncobj, 1, 0, GFP_NOWAIT); 496 spin_unlock(&file_private->syncobj_table_lock); 497 idr_preload_end(); 498 499 if (ret > 0) { 500 *handle = ret; 501 ret = 0; 502 } else 503 drm_syncobj_put(syncobj); 504 505 fdput(f); 506 return ret; 507 } 508 509 static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, 510 int fd, int handle) 511 { 512 struct dma_fence *fence = sync_file_get_fence(fd); 513 struct drm_syncobj *syncobj; 514 515 if (!fence) 516 return -EINVAL; 517 518 syncobj = drm_syncobj_find(file_private, handle); 519 if (!syncobj) { 520 dma_fence_put(fence); 521 return -ENOENT; 522 } 523 524 drm_syncobj_replace_fence(syncobj, fence); 525 dma_fence_put(fence); 526 drm_syncobj_put(syncobj); 527 return 0; 528 } 529 530 static int drm_syncobj_export_sync_file(struct drm_file *file_private, 531 int handle, int *p_fd) 532 { 533 int ret; 534 struct dma_fence *fence; 535 struct sync_file *sync_file; 536 int fd = get_unused_fd_flags(O_CLOEXEC); 537 538 if (fd < 0) 539 return fd; 540 541 ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence); 542 if (ret) 543 goto err_put_fd; 544 545 sync_file = sync_file_create(fence); 546 547 dma_fence_put(fence); 548 549 if (!sync_file) { 550 ret = -EINVAL; 551 goto err_put_fd; 552 } 553 554 fd_install(fd, sync_file->file); 555 556 *p_fd = fd; 557 return 0; 558 err_put_fd: 559 put_unused_fd(fd); 560 return ret; 561 } 562 /** 563 * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time 564 * @file_private: drm file-private structure to set up 565 * 566 * Called at device open time, sets up the structure for handling refcounting 567 * of sync objects. 568 */ 569 void 570 drm_syncobj_open(struct drm_file *file_private) 571 { 572 idr_init_base(&file_private->syncobj_idr, 1); 573 spin_lock_init(&file_private->syncobj_table_lock); 574 } 575 576 static int 577 drm_syncobj_release_handle(int id, void *ptr, void *data) 578 { 579 struct drm_syncobj *syncobj = ptr; 580 581 drm_syncobj_put(syncobj); 582 return 0; 583 } 584 585 /** 586 * drm_syncobj_release - release file-private sync object resources 587 * @file_private: drm file-private structure to clean up 588 * 589 * Called at close time when the filp is going away. 590 * 591 * Releases any remaining references on objects by this filp. 592 */ 593 void 594 drm_syncobj_release(struct drm_file *file_private) 595 { 596 idr_for_each(&file_private->syncobj_idr, 597 &drm_syncobj_release_handle, file_private); 598 idr_destroy(&file_private->syncobj_idr); 599 } 600 601 int 602 drm_syncobj_create_ioctl(struct drm_device *dev, void *data, 603 struct drm_file *file_private) 604 { 605 struct drm_syncobj_create *args = data; 606 607 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 608 return -EOPNOTSUPP; 609 610 /* no valid flags yet */ 611 if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED) 612 return -EINVAL; 613 614 return drm_syncobj_create_as_handle(file_private, 615 &args->handle, args->flags); 616 } 617 618 int 619 drm_syncobj_destroy_ioctl(struct drm_device *dev, void *data, 620 struct drm_file *file_private) 621 { 622 struct drm_syncobj_destroy *args = data; 623 624 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 625 return -EOPNOTSUPP; 626 627 /* make sure padding is empty */ 628 if (args->pad) 629 return -EINVAL; 630 return drm_syncobj_destroy(file_private, args->handle); 631 } 632 633 int 634 drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data, 635 struct drm_file *file_private) 636 { 637 struct drm_syncobj_handle *args = data; 638 639 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 640 return -EOPNOTSUPP; 641 642 if (args->pad) 643 return -EINVAL; 644 645 if (args->flags != 0 && 646 args->flags != DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE) 647 return -EINVAL; 648 649 if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE) 650 return drm_syncobj_export_sync_file(file_private, args->handle, 651 &args->fd); 652 653 return drm_syncobj_handle_to_fd(file_private, args->handle, 654 &args->fd); 655 } 656 657 int 658 drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data, 659 struct drm_file *file_private) 660 { 661 struct drm_syncobj_handle *args = data; 662 663 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 664 return -EOPNOTSUPP; 665 666 if (args->pad) 667 return -EINVAL; 668 669 if (args->flags != 0 && 670 args->flags != DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE) 671 return -EINVAL; 672 673 if (args->flags & DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE) 674 return drm_syncobj_import_sync_file_fence(file_private, 675 args->fd, 676 args->handle); 677 678 return drm_syncobj_fd_to_handle(file_private, args->fd, 679 &args->handle); 680 } 681 682 static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, 683 struct drm_syncobj_transfer *args) 684 { 685 struct drm_syncobj *timeline_syncobj = NULL; 686 struct dma_fence *fence; 687 struct dma_fence_chain *chain; 688 int ret; 689 690 timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle); 691 if (!timeline_syncobj) { 692 return -ENOENT; 693 } 694 ret = drm_syncobj_find_fence(file_private, args->src_handle, 695 args->src_point, args->flags, 696 &fence); 697 if (ret) 698 goto err; 699 chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); 700 if (!chain) { 701 ret = -ENOMEM; 702 goto err1; 703 } 704 drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point); 705 err1: 706 dma_fence_put(fence); 707 err: 708 drm_syncobj_put(timeline_syncobj); 709 710 return ret; 711 } 712 713 static int 714 drm_syncobj_transfer_to_binary(struct drm_file *file_private, 715 struct drm_syncobj_transfer *args) 716 { 717 struct drm_syncobj *binary_syncobj = NULL; 718 struct dma_fence *fence; 719 int ret; 720 721 binary_syncobj = drm_syncobj_find(file_private, args->dst_handle); 722 if (!binary_syncobj) 723 return -ENOENT; 724 ret = drm_syncobj_find_fence(file_private, args->src_handle, 725 args->src_point, args->flags, &fence); 726 if (ret) 727 goto err; 728 drm_syncobj_replace_fence(binary_syncobj, fence); 729 dma_fence_put(fence); 730 err: 731 drm_syncobj_put(binary_syncobj); 732 733 return ret; 734 } 735 int 736 drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data, 737 struct drm_file *file_private) 738 { 739 struct drm_syncobj_transfer *args = data; 740 int ret; 741 742 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) 743 return -EOPNOTSUPP; 744 745 if (args->pad) 746 return -EINVAL; 747 748 if (args->dst_point) 749 ret = drm_syncobj_transfer_to_timeline(file_private, args); 750 else 751 ret = drm_syncobj_transfer_to_binary(file_private, args); 752 753 return ret; 754 } 755 756 static void syncobj_wait_fence_func(struct dma_fence *fence, 757 struct dma_fence_cb *cb) 758 { 759 struct syncobj_wait_entry *wait = 760 container_of(cb, struct syncobj_wait_entry, fence_cb); 761 762 wake_up_process(wait->task); 763 } 764 765 static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj, 766 struct syncobj_wait_entry *wait) 767 { 768 struct dma_fence *fence; 769 770 /* This happens inside the syncobj lock */ 771 fence = rcu_dereference_protected(syncobj->fence, 772 lockdep_is_held(&syncobj->lock)); 773 dma_fence_get(fence); 774 if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) { 775 dma_fence_put(fence); 776 return; 777 } else if (!fence) { 778 wait->fence = dma_fence_get_stub(); 779 } else { 780 wait->fence = fence; 781 } 782 783 wake_up_process(wait->task); 784 list_del_init(&wait->node); 785 } 786 787 static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, 788 void __user *user_points, 789 uint32_t count, 790 uint32_t flags, 791 signed long timeout, 792 uint32_t *idx) 793 { 794 struct syncobj_wait_entry *entries; 795 struct dma_fence *fence; 796 uint64_t *points; 797 uint32_t signaled_count, i; 798 799 points = kmalloc_array(count, sizeof(*points), GFP_KERNEL); 800 if (points == NULL) 801 return -ENOMEM; 802 803 if (!user_points) { 804 memset(points, 0, count * sizeof(uint64_t)); 805 806 } else if (copy_from_user(points, user_points, 807 sizeof(uint64_t) * count)) { 808 timeout = -EFAULT; 809 goto err_free_points; 810 } 811 812 entries = kcalloc(count, sizeof(*entries), GFP_KERNEL); 813 if (!entries) { 814 timeout = -ENOMEM; 815 goto err_free_points; 816 } 817 /* Walk the list of sync objects and initialize entries. We do 818 * this up-front so that we can properly return -EINVAL if there is 819 * a syncobj with a missing fence and then never have the chance of 820 * returning -EINVAL again. 821 */ 822 signaled_count = 0; 823 for (i = 0; i < count; ++i) { 824 struct dma_fence *fence; 825 826 entries[i].task = current; 827 entries[i].point = points[i]; 828 fence = drm_syncobj_fence_get(syncobjs[i]); 829 if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) { 830 dma_fence_put(fence); 831 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { 832 continue; 833 } else { 834 timeout = -EINVAL; 835 goto cleanup_entries; 836 } 837 } 838 839 if (fence) 840 entries[i].fence = fence; 841 else 842 entries[i].fence = dma_fence_get_stub(); 843 844 if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) || 845 dma_fence_is_signaled(entries[i].fence)) { 846 if (signaled_count == 0 && idx) 847 *idx = i; 848 signaled_count++; 849 } 850 } 851 852 if (signaled_count == count || 853 (signaled_count > 0 && 854 !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL))) 855 goto cleanup_entries; 856 857 /* There's a very annoying laxness in the dma_fence API here, in 858 * that backends are not required to automatically report when a 859 * fence is signaled prior to fence->ops->enable_signaling() being 860 * called. So here if we fail to match signaled_count, we need to 861 * fallthough and try a 0 timeout wait! 862 */ 863 864 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { 865 for (i = 0; i < count; ++i) 866 drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]); 867 } 868 869 do { 870 set_current_state(TASK_INTERRUPTIBLE); 871 872 signaled_count = 0; 873 for (i = 0; i < count; ++i) { 874 fence = entries[i].fence; 875 if (!fence) 876 continue; 877 878 if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) || 879 dma_fence_is_signaled(fence) || 880 (!entries[i].fence_cb.func && 881 dma_fence_add_callback(fence, 882 &entries[i].fence_cb, 883 syncobj_wait_fence_func))) { 884 /* The fence has been signaled */ 885 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) { 886 signaled_count++; 887 } else { 888 if (idx) 889 *idx = i; 890 goto done_waiting; 891 } 892 } 893 } 894 895 if (signaled_count == count) 896 goto done_waiting; 897 898 if (timeout == 0) { 899 timeout = -ETIME; 900 goto done_waiting; 901 } 902 903 if (signal_pending(current)) { 904 timeout = -ERESTARTSYS; 905 goto done_waiting; 906 } 907 908 timeout = schedule_timeout(timeout); 909 } while (1); 910 911 done_waiting: 912 __set_current_state(TASK_RUNNING); 913 914 cleanup_entries: 915 for (i = 0; i < count; ++i) { 916 drm_syncobj_remove_wait(syncobjs[i], &entries[i]); 917 if (entries[i].fence_cb.func) 918 dma_fence_remove_callback(entries[i].fence, 919 &entries[i].fence_cb); 920 dma_fence_put(entries[i].fence); 921 } 922 kfree(entries); 923 924 err_free_points: 925 kfree(points); 926 927 return timeout; 928 } 929 930 /** 931 * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value 932 * 933 * @timeout_nsec: timeout nsec component in ns, 0 for poll 934 * 935 * Calculate the timeout in jiffies from an absolute time in sec/nsec. 936 */ 937 signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) 938 { 939 ktime_t abs_timeout, now; 940 u64 timeout_ns, timeout_jiffies64; 941 942 /* make 0 timeout means poll - absolute 0 doesn't seem valid */ 943 if (timeout_nsec == 0) 944 return 0; 945 946 abs_timeout = ns_to_ktime(timeout_nsec); 947 now = ktime_get(); 948 949 if (!ktime_after(abs_timeout, now)) 950 return 0; 951 952 timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now)); 953 954 timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns); 955 /* clamp timeout to avoid infinite timeout */ 956 if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1) 957 return MAX_SCHEDULE_TIMEOUT - 1; 958 959 return timeout_jiffies64 + 1; 960 } 961 EXPORT_SYMBOL(drm_timeout_abs_to_jiffies); 962 963 static int drm_syncobj_array_wait(struct drm_device *dev, 964 struct drm_file *file_private, 965 struct drm_syncobj_wait *wait, 966 struct drm_syncobj_timeline_wait *timeline_wait, 967 struct drm_syncobj **syncobjs, bool timeline) 968 { 969 signed long timeout = 0; 970 uint32_t first = ~0; 971 972 if (!timeline) { 973 timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec); 974 timeout = drm_syncobj_array_wait_timeout(syncobjs, 975 NULL, 976 wait->count_handles, 977 wait->flags, 978 timeout, &first); 979 if (timeout < 0) 980 return timeout; 981 wait->first_signaled = first; 982 } else { 983 timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec); 984 timeout = drm_syncobj_array_wait_timeout(syncobjs, 985 u64_to_user_ptr(timeline_wait->points), 986 timeline_wait->count_handles, 987 timeline_wait->flags, 988 timeout, &first); 989 if (timeout < 0) 990 return timeout; 991 timeline_wait->first_signaled = first; 992 } 993 return 0; 994 } 995 996 static int drm_syncobj_array_find(struct drm_file *file_private, 997 void __user *user_handles, 998 uint32_t count_handles, 999 struct drm_syncobj ***syncobjs_out) 1000 { 1001 uint32_t i, *handles; 1002 struct drm_syncobj **syncobjs; 1003 int ret; 1004 1005 handles = kmalloc_array(count_handles, sizeof(*handles), GFP_KERNEL); 1006 if (handles == NULL) 1007 return -ENOMEM; 1008 1009 if (copy_from_user(handles, user_handles, 1010 sizeof(uint32_t) * count_handles)) { 1011 ret = -EFAULT; 1012 goto err_free_handles; 1013 } 1014 1015 syncobjs = kmalloc_array(count_handles, sizeof(*syncobjs), GFP_KERNEL); 1016 if (syncobjs == NULL) { 1017 ret = -ENOMEM; 1018 goto err_free_handles; 1019 } 1020 1021 for (i = 0; i < count_handles; i++) { 1022 syncobjs[i] = drm_syncobj_find(file_private, handles[i]); 1023 if (!syncobjs[i]) { 1024 ret = -ENOENT; 1025 goto err_put_syncobjs; 1026 } 1027 } 1028 1029 kfree(handles); 1030 *syncobjs_out = syncobjs; 1031 return 0; 1032 1033 err_put_syncobjs: 1034 while (i-- > 0) 1035 drm_syncobj_put(syncobjs[i]); 1036 kfree(syncobjs); 1037 err_free_handles: 1038 kfree(handles); 1039 1040 return ret; 1041 } 1042 1043 static void drm_syncobj_array_free(struct drm_syncobj **syncobjs, 1044 uint32_t count) 1045 { 1046 uint32_t i; 1047 for (i = 0; i < count; i++) 1048 drm_syncobj_put(syncobjs[i]); 1049 kfree(syncobjs); 1050 } 1051 1052 int 1053 drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, 1054 struct drm_file *file_private) 1055 { 1056 struct drm_syncobj_wait *args = data; 1057 struct drm_syncobj **syncobjs; 1058 int ret = 0; 1059 1060 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 1061 return -EOPNOTSUPP; 1062 1063 if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | 1064 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)) 1065 return -EINVAL; 1066 1067 if (args->count_handles == 0) 1068 return -EINVAL; 1069 1070 ret = drm_syncobj_array_find(file_private, 1071 u64_to_user_ptr(args->handles), 1072 args->count_handles, 1073 &syncobjs); 1074 if (ret < 0) 1075 return ret; 1076 1077 ret = drm_syncobj_array_wait(dev, file_private, 1078 args, NULL, syncobjs, false); 1079 1080 drm_syncobj_array_free(syncobjs, args->count_handles); 1081 1082 return ret; 1083 } 1084 1085 int 1086 drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, 1087 struct drm_file *file_private) 1088 { 1089 struct drm_syncobj_timeline_wait *args = data; 1090 struct drm_syncobj **syncobjs; 1091 int ret = 0; 1092 1093 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) 1094 return -EOPNOTSUPP; 1095 1096 if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | 1097 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | 1098 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) 1099 return -EINVAL; 1100 1101 if (args->count_handles == 0) 1102 return -EINVAL; 1103 1104 ret = drm_syncobj_array_find(file_private, 1105 u64_to_user_ptr(args->handles), 1106 args->count_handles, 1107 &syncobjs); 1108 if (ret < 0) 1109 return ret; 1110 1111 ret = drm_syncobj_array_wait(dev, file_private, 1112 NULL, args, syncobjs, true); 1113 1114 drm_syncobj_array_free(syncobjs, args->count_handles); 1115 1116 return ret; 1117 } 1118 1119 1120 int 1121 drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, 1122 struct drm_file *file_private) 1123 { 1124 struct drm_syncobj_array *args = data; 1125 struct drm_syncobj **syncobjs; 1126 uint32_t i; 1127 int ret; 1128 1129 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 1130 return -EOPNOTSUPP; 1131 1132 if (args->pad != 0) 1133 return -EINVAL; 1134 1135 if (args->count_handles == 0) 1136 return -EINVAL; 1137 1138 ret = drm_syncobj_array_find(file_private, 1139 u64_to_user_ptr(args->handles), 1140 args->count_handles, 1141 &syncobjs); 1142 if (ret < 0) 1143 return ret; 1144 1145 for (i = 0; i < args->count_handles; i++) 1146 drm_syncobj_replace_fence(syncobjs[i], NULL); 1147 1148 drm_syncobj_array_free(syncobjs, args->count_handles); 1149 1150 return 0; 1151 } 1152 1153 int 1154 drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, 1155 struct drm_file *file_private) 1156 { 1157 struct drm_syncobj_array *args = data; 1158 struct drm_syncobj **syncobjs; 1159 uint32_t i; 1160 int ret; 1161 1162 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) 1163 return -EOPNOTSUPP; 1164 1165 if (args->pad != 0) 1166 return -EINVAL; 1167 1168 if (args->count_handles == 0) 1169 return -EINVAL; 1170 1171 ret = drm_syncobj_array_find(file_private, 1172 u64_to_user_ptr(args->handles), 1173 args->count_handles, 1174 &syncobjs); 1175 if (ret < 0) 1176 return ret; 1177 1178 for (i = 0; i < args->count_handles; i++) 1179 drm_syncobj_assign_null_handle(syncobjs[i]); 1180 1181 drm_syncobj_array_free(syncobjs, args->count_handles); 1182 1183 return ret; 1184 } 1185 1186 int 1187 drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, 1188 struct drm_file *file_private) 1189 { 1190 struct drm_syncobj_timeline_array *args = data; 1191 struct drm_syncobj **syncobjs; 1192 struct dma_fence_chain **chains; 1193 uint64_t *points; 1194 uint32_t i, j; 1195 int ret; 1196 1197 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) 1198 return -EOPNOTSUPP; 1199 1200 if (args->pad != 0) 1201 return -EINVAL; 1202 1203 if (args->count_handles == 0) 1204 return -EINVAL; 1205 1206 ret = drm_syncobj_array_find(file_private, 1207 u64_to_user_ptr(args->handles), 1208 args->count_handles, 1209 &syncobjs); 1210 if (ret < 0) 1211 return ret; 1212 1213 points = kmalloc_array(args->count_handles, sizeof(*points), 1214 GFP_KERNEL); 1215 if (!points) { 1216 ret = -ENOMEM; 1217 goto out; 1218 } 1219 if (!u64_to_user_ptr(args->points)) { 1220 memset(points, 0, args->count_handles * sizeof(uint64_t)); 1221 } else if (copy_from_user(points, u64_to_user_ptr(args->points), 1222 sizeof(uint64_t) * args->count_handles)) { 1223 ret = -EFAULT; 1224 goto err_points; 1225 } 1226 1227 chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL); 1228 if (!chains) { 1229 ret = -ENOMEM; 1230 goto err_points; 1231 } 1232 for (i = 0; i < args->count_handles; i++) { 1233 chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); 1234 if (!chains[i]) { 1235 for (j = 0; j < i; j++) 1236 kfree(chains[j]); 1237 ret = -ENOMEM; 1238 goto err_chains; 1239 } 1240 } 1241 1242 for (i = 0; i < args->count_handles; i++) { 1243 struct dma_fence *fence = dma_fence_get_stub(); 1244 1245 drm_syncobj_add_point(syncobjs[i], chains[i], 1246 fence, points[i]); 1247 dma_fence_put(fence); 1248 } 1249 err_chains: 1250 kfree(chains); 1251 err_points: 1252 kfree(points); 1253 out: 1254 drm_syncobj_array_free(syncobjs, args->count_handles); 1255 1256 return ret; 1257 } 1258 1259 int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, 1260 struct drm_file *file_private) 1261 { 1262 struct drm_syncobj_timeline_array *args = data; 1263 struct drm_syncobj **syncobjs; 1264 uint64_t __user *points = u64_to_user_ptr(args->points); 1265 uint32_t i; 1266 int ret; 1267 1268 if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) 1269 return -EOPNOTSUPP; 1270 1271 if (args->pad != 0) 1272 return -EINVAL; 1273 1274 if (args->count_handles == 0) 1275 return -EINVAL; 1276 1277 ret = drm_syncobj_array_find(file_private, 1278 u64_to_user_ptr(args->handles), 1279 args->count_handles, 1280 &syncobjs); 1281 if (ret < 0) 1282 return ret; 1283 1284 for (i = 0; i < args->count_handles; i++) { 1285 struct dma_fence_chain *chain; 1286 struct dma_fence *fence; 1287 uint64_t point; 1288 1289 fence = drm_syncobj_fence_get(syncobjs[i]); 1290 chain = to_dma_fence_chain(fence); 1291 if (chain) { 1292 struct dma_fence *iter, *last_signaled = NULL; 1293 1294 dma_fence_chain_for_each(iter, fence) { 1295 if (!iter) 1296 break; 1297 dma_fence_put(last_signaled); 1298 last_signaled = dma_fence_get(iter); 1299 if (!to_dma_fence_chain(last_signaled)->prev_seqno) 1300 /* It is most likely that timeline has 1301 * unorder points. */ 1302 break; 1303 } 1304 point = dma_fence_is_signaled(last_signaled) ? 1305 last_signaled->seqno : 1306 to_dma_fence_chain(last_signaled)->prev_seqno; 1307 dma_fence_put(last_signaled); 1308 } else { 1309 point = 0; 1310 } 1311 ret = copy_to_user(&points[i], &point, sizeof(uint64_t)); 1312 ret = ret ? -EFAULT : 0; 1313 if (ret) 1314 break; 1315 } 1316 drm_syncobj_array_free(syncobjs, args->count_handles); 1317 1318 return ret; 1319 } 1320