Skip to content

Commit 85b144f

Browse files
Maarten Lankhorstairlied
authored andcommitted
drm/ttm: call ttm_bo_cleanup_refs with reservation and lru lock held, v3
By removing the unlocking of lru and retaking it immediately, a race is removed where the bo is taken off the swap list or the lru list between the unlock and relock. As such the cleanup_refs code can be simplified, it will attempt to call ttm_bo_wait non-blockingly, and if it fails it will drop the locks and perform a blocking wait, or return an error if no_wait_gpu was set. The need for looping is also eliminated, since swapout and evict_mem_first will always follow the destruction path, no new fence is allowed to be attached. As far as I can see this may already have been the case, but the unlocking / relocking required a complicated loop to deal with re-reservation. Changes since v1: - Simplify no_wait_gpu case by folding it in with empty ddestroy. - Hold a reservation while calling ttm_bo_cleanup_memtype_use again. Changes since v2: - Do not remove bo from lru list while waiting Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
1 parent 6ed9ccb commit 85b144f

File tree

1 file changed

+76
-47
lines changed

1 file changed

+76
-47
lines changed

drivers/gpu/drm/ttm/ttm_bo.c

Lines changed: 76 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -488,12 +488,16 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
488488
ttm_bo_mem_put(bo, &bo->mem);
489489

490490
atomic_set(&bo->reserved, 0);
491+
wake_up_all(&bo->event_queue);
491492

492493
/*
493-
* Make processes trying to reserve really pick it up.
494+
* Since the final reference to this bo may not be dropped by
495+
* the current task we have to put a memory barrier here to make
496+
* sure the changes done in this function are always visible.
497+
*
498+
* This function only needs protection against the final kref_put.
494499
*/
495-
smp_mb__after_atomic_dec();
496-
wake_up_all(&bo->event_queue);
500+
smp_mb__before_atomic_dec();
497501
}
498502

499503
static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
@@ -543,68 +547,84 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
543547
}
544548

545549
/**
546-
* function ttm_bo_cleanup_refs
550+
* function ttm_bo_cleanup_refs_and_unlock
547551
* If bo idle, remove from delayed- and lru lists, and unref.
548552
* If not idle, do nothing.
549553
*
554+
* Must be called with lru_lock and reservation held, this function
555+
* will drop both before returning.
556+
*
550557
* @interruptible Any sleeps should occur interruptibly.
551-
* @no_wait_reserve Never wait for reserve. Return -EBUSY instead.
552558
* @no_wait_gpu Never wait for gpu. Return -EBUSY instead.
553559
*/
554560

555-
static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
556-
bool interruptible,
557-
bool no_wait_reserve,
558-
bool no_wait_gpu)
561+
static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
562+
bool interruptible,
563+
bool no_wait_gpu)
559564
{
560565
struct ttm_bo_device *bdev = bo->bdev;
566+
struct ttm_bo_driver *driver = bdev->driver;
561567
struct ttm_bo_global *glob = bo->glob;
562568
int put_count;
563-
int ret = 0;
569+
int ret;
564570

565-
retry:
566571
spin_lock(&bdev->fence_lock);
567-
ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
568-
spin_unlock(&bdev->fence_lock);
572+
ret = ttm_bo_wait(bo, false, false, true);
569573

570-
if (unlikely(ret != 0))
571-
return ret;
574+
if (ret && !no_wait_gpu) {
575+
void *sync_obj;
572576

573-
retry_reserve:
574-
spin_lock(&glob->lru_lock);
577+
/*
578+
* Take a reference to the fence and unreserve,
579+
* at this point the buffer should be dead, so
580+
* no new sync objects can be attached.
581+
*/
582+
sync_obj = driver->sync_obj_ref(&bo->sync_obj);
583+
spin_unlock(&bdev->fence_lock);
575584

576-
if (unlikely(list_empty(&bo->ddestroy))) {
585+
atomic_set(&bo->reserved, 0);
586+
wake_up_all(&bo->event_queue);
577587
spin_unlock(&glob->lru_lock);
578-
return 0;
579-
}
580588

581-
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
582-
583-
if (unlikely(ret == -EBUSY)) {
584-
spin_unlock(&glob->lru_lock);
585-
if (likely(!no_wait_reserve))
586-
ret = ttm_bo_wait_unreserved(bo, interruptible);
587-
if (unlikely(ret != 0))
589+
ret = driver->sync_obj_wait(sync_obj, false, interruptible);
590+
driver->sync_obj_unref(&sync_obj);
591+
if (ret)
588592
return ret;
589593

590-
goto retry_reserve;
591-
}
594+
/*
595+
* remove sync_obj with ttm_bo_wait, the wait should be
596+
* finished, and no new wait object should have been added.
597+
*/
598+
spin_lock(&bdev->fence_lock);
599+
ret = ttm_bo_wait(bo, false, false, true);
600+
WARN_ON(ret);
601+
spin_unlock(&bdev->fence_lock);
602+
if (ret)
603+
return ret;
592604

593-
BUG_ON(ret != 0);
605+
spin_lock(&glob->lru_lock);
606+
ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
594607

595-
/**
596-
* We can re-check for sync object without taking
597-
* the bo::lock since setting the sync object requires
598-
* also bo::reserved. A busy object at this point may
599-
* be caused by another thread recently starting an accelerated
600-
* eviction.
601-
*/
608+
/*
609+
* We raced, and lost, someone else holds the reservation now,
610+
* and is probably busy in ttm_bo_cleanup_memtype_use.
611+
*
612+
* Even if it's not the case, because we finished waiting any
613+
* delayed destruction would succeed, so just return success
614+
* here.
615+
*/
616+
if (ret) {
617+
spin_unlock(&glob->lru_lock);
618+
return 0;
619+
}
620+
} else
621+
spin_unlock(&bdev->fence_lock);
602622

603-
if (unlikely(bo->sync_obj)) {
623+
if (ret || unlikely(list_empty(&bo->ddestroy))) {
604624
atomic_set(&bo->reserved, 0);
605625
wake_up_all(&bo->event_queue);
606626
spin_unlock(&glob->lru_lock);
607-
goto retry;
627+
return ret;
608628
}
609629

610630
put_count = ttm_bo_del_from_lru(bo);
@@ -647,9 +667,13 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
647667
kref_get(&nentry->list_kref);
648668
}
649669

650-
spin_unlock(&glob->lru_lock);
651-
ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
652-
!remove_all);
670+
ret = ttm_bo_reserve_locked(entry, false, !remove_all, false, 0);
671+
if (!ret)
672+
ret = ttm_bo_cleanup_refs_and_unlock(entry, false,
673+
!remove_all);
674+
else
675+
spin_unlock(&glob->lru_lock);
676+
653677
kref_put(&entry->list_kref, ttm_bo_release_list);
654678
entry = nentry;
655679

@@ -800,9 +824,13 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
800824
kref_get(&bo->list_kref);
801825

802826
if (!list_empty(&bo->ddestroy)) {
803-
spin_unlock(&glob->lru_lock);
804-
ret = ttm_bo_cleanup_refs(bo, interruptible,
805-
no_wait_reserve, no_wait_gpu);
827+
ret = ttm_bo_reserve_locked(bo, interruptible, no_wait_reserve, false, 0);
828+
if (!ret)
829+
ret = ttm_bo_cleanup_refs_and_unlock(bo, interruptible,
830+
no_wait_gpu);
831+
else
832+
spin_unlock(&glob->lru_lock);
833+
806834
kref_put(&bo->list_kref, ttm_bo_release_list);
807835

808836
return ret;
@@ -1796,8 +1824,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
17961824
kref_get(&bo->list_kref);
17971825

17981826
if (!list_empty(&bo->ddestroy)) {
1799-
spin_unlock(&glob->lru_lock);
1800-
(void) ttm_bo_cleanup_refs(bo, false, false, false);
1827+
ttm_bo_reserve_locked(bo, false, false, false, 0);
1828+
ttm_bo_cleanup_refs_and_unlock(bo, false, false);
1829+
18011830
kref_put(&bo->list_kref, ttm_bo_release_list);
18021831
spin_lock(&glob->lru_lock);
18031832
continue;

0 commit comments

Comments
 (0)