diff options
| -rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo.c | 171 |
1 files changed, 107 insertions, 64 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 4a73f401644d..a1cb783c7131 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
| @@ -455,100 +455,123 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) | |||
| 455 | wake_up_all(&bo->event_queue); | 455 | wake_up_all(&bo->event_queue); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | 458 | static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) | |
| 459 | /** | ||
| 460 | * If bo idle, remove from delayed- and lru lists, and unref. | ||
| 461 | * If not idle, and already on delayed list, do nothing. | ||
| 462 | * If not idle, and not on delayed list, put on delayed list, | ||
| 463 | * up the list_kref and schedule a delayed list check. | ||
| 464 | */ | ||
| 465 | |||
| 466 | static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all) | ||
| 467 | { | 459 | { |
| 468 | struct ttm_bo_device *bdev = bo->bdev; | 460 | struct ttm_bo_device *bdev = bo->bdev; |
| 469 | struct ttm_bo_global *glob = bo->glob; | 461 | struct ttm_bo_global *glob = bo->glob; |
| 470 | struct ttm_bo_driver *driver = bdev->driver; | 462 | struct ttm_bo_driver *driver; |
| 463 | void *sync_obj; | ||
| 464 | void *sync_obj_arg; | ||
| 465 | int put_count; | ||
| 471 | int ret; | 466 | int ret; |
| 472 | 467 | ||
| 473 | spin_lock(&bo->lock); | 468 | spin_lock(&bo->lock); |
| 474 | retry: | 469 | (void) ttm_bo_wait(bo, false, false, true); |
| 475 | (void) ttm_bo_wait(bo, false, false, !remove_all); | ||
| 476 | |||
| 477 | if (!bo->sync_obj) { | 470 | if (!bo->sync_obj) { |
| 478 | int put_count; | ||
| 479 | |||
| 480 | spin_unlock(&bo->lock); | ||
| 481 | 471 | ||
| 482 | spin_lock(&glob->lru_lock); | 472 | spin_lock(&glob->lru_lock); |
| 483 | ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0); | ||
| 484 | 473 | ||
| 485 | /** | 474 | /** |
| 486 | * Someone else has the object reserved. Bail and retry. | 475 | * Lock inversion between bo::reserve and bo::lock here, |
| 476 | * but that's OK, since we're only trylocking. | ||
| 487 | */ | 477 | */ |
| 488 | 478 | ||
| 489 | if (unlikely(ret == -EBUSY)) { | 479 | ret = ttm_bo_reserve_locked(bo, false, true, false, 0); |
| 490 | spin_unlock(&glob->lru_lock); | ||
| 491 | spin_lock(&bo->lock); | ||
| 492 | goto requeue; | ||
| 493 | } | ||
| 494 | |||
| 495 | /** | ||
| 496 | * We can re-check for sync object without taking | ||
| 497 | * the bo::lock since setting the sync object requires | ||
| 498 | * also bo::reserved. A busy object at this point may | ||
| 499 | * be caused by another thread starting an accelerated | ||
| 500 | * eviction. | ||
| 501 | */ | ||
| 502 | 480 | ||
| 503 | if (unlikely(bo->sync_obj)) { | 481 | if (unlikely(ret == -EBUSY)) |
| 504 | atomic_set(&bo->reserved, 0); | 482 | goto queue; |
| 505 | wake_up_all(&bo->event_queue); | ||
| 506 | spin_unlock(&glob->lru_lock); | ||
| 507 | spin_lock(&bo->lock); | ||
| 508 | if (remove_all) | ||
| 509 | goto retry; | ||
| 510 | else | ||
| 511 | goto requeue; | ||
| 512 | } | ||
| 513 | 483 | ||
| 484 | spin_unlock(&bo->lock); | ||
| 514 | put_count = ttm_bo_del_from_lru(bo); | 485 | put_count = ttm_bo_del_from_lru(bo); |
| 515 | 486 | ||
| 516 | if (!list_empty(&bo->ddestroy)) { | ||
| 517 | list_del_init(&bo->ddestroy); | ||
| 518 | ++put_count; | ||
| 519 | } | ||
| 520 | spin_unlock(&glob->lru_lock); | 487 | spin_unlock(&glob->lru_lock); |
| 521 | ttm_bo_cleanup_memtype_use(bo); | 488 | ttm_bo_cleanup_memtype_use(bo); |
| 522 | 489 | ||
| 523 | while (put_count--) | 490 | while (put_count--) |
| 524 | kref_put(&bo->list_kref, ttm_bo_ref_bug); | 491 | kref_put(&bo->list_kref, ttm_bo_ref_bug); |
| 525 | 492 | ||
| 526 | return 0; | 493 | return; |
| 494 | } else { | ||
| 495 | spin_lock(&glob->lru_lock); | ||
| 527 | } | 496 | } |
| 528 | requeue: | 497 | queue: |
| 498 | sync_obj = bo->sync_obj; | ||
| 499 | sync_obj_arg = bo->sync_obj_arg; | ||
| 500 | driver = bdev->driver; | ||
| 501 | |||
| 502 | kref_get(&bo->list_kref); | ||
| 503 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); | ||
| 504 | spin_unlock(&glob->lru_lock); | ||
| 505 | spin_unlock(&bo->lock); | ||
| 506 | |||
| 507 | if (sync_obj) | ||
| 508 | driver->sync_obj_flush(sync_obj, sync_obj_arg); | ||
| 509 | schedule_delayed_work(&bdev->wq, | ||
| 510 | ((HZ / 100) < 1) ? 1 : HZ / 100); | ||
| 511 | } | ||
| 512 | |||
| 513 | /** | ||
| 514 | * function ttm_bo_cleanup_refs | ||
| 515 | * If bo idle, remove from delayed- and lru lists, and unref. | ||
| 516 | * If not idle, do nothing. | ||
| 517 | * | ||
| 518 | * @interruptible Any sleeps should occur interruptibly. | ||
| 519 | * @no_wait_reserve Never wait for reserve. Return -EBUSY instead. | ||
| 520 | * @no_wait_gpu Never wait for gpu. Return -EBUSY instead. | ||
| 521 | */ | ||
| 522 | |||
| 523 | static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, | ||
| 524 | bool interruptible, | ||
| 525 | bool no_wait_reserve, | ||
| 526 | bool no_wait_gpu) | ||
| 527 | { | ||
| 528 | struct ttm_bo_global *glob = bo->glob; | ||
| 529 | int put_count; | ||
| 530 | int ret = 0; | ||
| 531 | |||
| 532 | retry: | ||
| 533 | spin_lock(&bo->lock); | ||
| 534 | ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); | ||
| 535 | spin_unlock(&bo->lock); | ||
| 536 | |||
| 537 | if (unlikely(ret != 0)) | ||
| 538 | return ret; | ||
| 539 | |||
| 529 | spin_lock(&glob->lru_lock); | 540 | spin_lock(&glob->lru_lock); |
| 530 | if (list_empty(&bo->ddestroy)) { | 541 | ret = ttm_bo_reserve_locked(bo, interruptible, |
| 531 | void *sync_obj = bo->sync_obj; | 542 | no_wait_reserve, false, 0); |
| 532 | void *sync_obj_arg = bo->sync_obj_arg; | ||
| 533 | 543 | ||
| 534 | kref_get(&bo->list_kref); | 544 | if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) { |
| 535 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); | ||
| 536 | spin_unlock(&glob->lru_lock); | 545 | spin_unlock(&glob->lru_lock); |
| 537 | spin_unlock(&bo->lock); | 546 | return ret; |
| 547 | } | ||
| 538 | 548 | ||
| 539 | if (sync_obj) | 549 | /** |
| 540 | driver->sync_obj_flush(sync_obj, sync_obj_arg); | 550 | * We can re-check for sync object without taking |
| 541 | schedule_delayed_work(&bdev->wq, | 551 | * the bo::lock since setting the sync object requires |
| 542 | ((HZ / 100) < 1) ? 1 : HZ / 100); | 552 | * also bo::reserved. A busy object at this point may |
| 543 | ret = 0; | 553 | * be caused by another thread recently starting an accelerated |
| 554 | * eviction. | ||
| 555 | */ | ||
| 544 | 556 | ||
| 545 | } else { | 557 | if (unlikely(bo->sync_obj)) { |
| 558 | atomic_set(&bo->reserved, 0); | ||
| 559 | wake_up_all(&bo->event_queue); | ||
| 546 | spin_unlock(&glob->lru_lock); | 560 | spin_unlock(&glob->lru_lock); |
| 547 | spin_unlock(&bo->lock); | 561 | goto retry; |
| 548 | ret = -EBUSY; | ||
| 549 | } | 562 | } |
| 550 | 563 | ||
| 551 | return ret; | 564 | put_count = ttm_bo_del_from_lru(bo); |
| 565 | list_del_init(&bo->ddestroy); | ||
| 566 | ++put_count; | ||
| 567 | |||
| 568 | spin_unlock(&glob->lru_lock); | ||
| 569 | ttm_bo_cleanup_memtype_use(bo); | ||
| 570 | |||
| 571 | while (put_count--) | ||
| 572 | kref_put(&bo->list_kref, ttm_bo_ref_bug); | ||
| 573 | |||
| 574 | return 0; | ||
| 552 | } | 575 | } |
| 553 | 576 | ||
| 554 | /** | 577 | /** |
| @@ -580,7 +603,8 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) | |||
| 580 | } | 603 | } |
| 581 | 604 | ||
| 582 | spin_unlock(&glob->lru_lock); | 605 | spin_unlock(&glob->lru_lock); |
| 583 | ret = ttm_bo_cleanup_refs(entry, remove_all); | 606 | ret = ttm_bo_cleanup_refs(entry, false, !remove_all, |
| 607 | !remove_all); | ||
| 584 | kref_put(&entry->list_kref, ttm_bo_release_list); | 608 | kref_put(&entry->list_kref, ttm_bo_release_list); |
| 585 | entry = nentry; | 609 | entry = nentry; |
| 586 | 610 | ||
| @@ -623,7 +647,7 @@ static void ttm_bo_release(struct kref *kref) | |||
| 623 | bo->vm_node = NULL; | 647 | bo->vm_node = NULL; |
| 624 | } | 648 | } |
| 625 | write_unlock(&bdev->vm_lock); | 649 | write_unlock(&bdev->vm_lock); |
| 626 | ttm_bo_cleanup_refs(bo, false); | 650 | ttm_bo_cleanup_refs_or_queue(bo); |
| 627 | kref_put(&bo->list_kref, ttm_bo_release_list); | 651 | kref_put(&bo->list_kref, ttm_bo_release_list); |
| 628 | write_lock(&bdev->vm_lock); | 652 | write_lock(&bdev->vm_lock); |
| 629 | } | 653 | } |
| @@ -731,6 +755,18 @@ retry: | |||
| 731 | bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); | 755 | bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); |
| 732 | kref_get(&bo->list_kref); | 756 | kref_get(&bo->list_kref); |
| 733 | 757 | ||
| 758 | if (!list_empty(&bo->ddestroy)) { | ||
| 759 | spin_unlock(&glob->lru_lock); | ||
| 760 | ret = ttm_bo_cleanup_refs(bo, interruptible, | ||
| 761 | no_wait_reserve, no_wait_gpu); | ||
| 762 | kref_put(&bo->list_kref, ttm_bo_release_list); | ||
| 763 | |||
| 764 | if (likely(ret == 0 || ret == -ERESTARTSYS)) | ||
| 765 | return ret; | ||
| 766 | |||
| 767 | goto retry; | ||
| 768 | } | ||
| 769 | |||
| 734 | ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0); | 770 | ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0); |
| 735 | 771 | ||
| 736 | if (unlikely(ret == -EBUSY)) { | 772 | if (unlikely(ret == -EBUSY)) { |
| @@ -1754,6 +1790,13 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) | |||
| 1754 | struct ttm_buffer_object, swap); | 1790 | struct ttm_buffer_object, swap); |
| 1755 | kref_get(&bo->list_kref); | 1791 | kref_get(&bo->list_kref); |
| 1756 | 1792 | ||
| 1793 | if (!list_empty(&bo->ddestroy)) { | ||
| 1794 | spin_unlock(&glob->lru_lock); | ||
| 1795 | (void) ttm_bo_cleanup_refs(bo, false, false, false); | ||
| 1796 | kref_put(&bo->list_kref, ttm_bo_release_list); | ||
| 1797 | continue; | ||
| 1798 | } | ||
| 1799 | |||
| 1757 | /** | 1800 | /** |
| 1758 | * Reserve buffer. Since we unlock while sleeping, we need | 1801 | * Reserve buffer. Since we unlock while sleeping, we need |
| 1759 | * to re-check that nobody removed us from the swap-list while | 1802 | * to re-check that nobody removed us from the swap-list while |
