The eviction fence suspend worker can submit MES REMOVE_QUEUE packets
without holding the reset-domain semaphore. If GPU recovery starts while
the worker is running, both paths can access the hardware concurrently.
This triggers the hardware-access lockdep assertion and can submit a MES
packet while recovery is resetting the device.

Try to take the reset-domain semaphore for read around userq eviction. Do
not block on it while holding userq_mutex because recovery takes the reset
semaphore for write before acquiring buffer reservations and userq_mutex.
Instead, drop userq_mutex, wait for recovery without holding any other
lock, and retry the queue-state checks after recovery completes.

This makes recovery wait for an in-flight MES eviction, while an eviction
which starts after recovery waits without introducing the reverse lock
dependency that caused the reported circular-lock warning.

Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
index 2ea8553c82f0..93307cbf55dc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
@@ -67,10 +67,18 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct 
*work)
        bool cookie;
        int r;
 
+retry:
        mutex_lock(&uq_mgr->userq_mutex);
 
        /* Fence waits are not allowed in a fence signalling critical section. 
*/
        amdgpu_userq_wait_for_signal(uq_mgr);
+       if (!down_read_trylock(&uq_mgr->adev->reset_domain->sem)) {
+               mutex_unlock(&uq_mgr->userq_mutex);
+
+               down_read(&uq_mgr->adev->reset_domain->sem);
+               up_read(&uq_mgr->adev->reset_domain->sem);
+               goto retry;
+       }
 
        /*
         * This is intentionally after taking the userq_mutex since we do
@@ -81,6 +89,7 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
 
        ev_fence = amdgpu_evf_mgr_get_fence(evf_mgr);
        r = amdgpu_userq_evict(uq_mgr);
+       up_read(&uq_mgr->adev->reset_domain->sem);
        if (r)
                dma_fence_set_error(ev_fence, r);
 
-- 
2.34.1

Reply via email to