amdgpu_userq_destroy() takes reset_domain->sem for read in
amdgpu_userq_detach_doorbell() while holding userq_mutex. GPU recovery
holds reset_domain->sem for write and then takes clientlist_mutex in
drm_client_dev_suspend(), which already depends on userq_mutex through
the fbdev reservation and userq restore paths. Lockdep reports:

  Chain exists of:
    &dev->clientlist_mutex --> &userq_mgr->userq_mutex --> &reset_domain->sem

Keep waiting for the last fence under userq_mutex only, as the fence of a
hung queue is only force-completed by the reset, then take
reset_domain->sem before re-acquiring userq_mutex for the doorbell
detach, unmap and fence driver teardown. This also keeps the MES unmap
from racing with an in-progress GPU reset.

Fixes: f18719ef4bb7 ("drm/amdgpu: Convert amdgpu userqueue management from IDR 
to XArray")
Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 5fef0cc7703c..a34ea8ecd700 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -415,15 +415,6 @@ static void amdgpu_userq_wait_for_last_fence(struct 
amdgpu_usermode_queue *queue
        dma_fence_wait(f, false);
 }
 
-static void amdgpu_userq_detach_doorbell(struct amdgpu_usermode_queue *queue)
-{
-       struct amdgpu_device *adev = queue->userq_mgr->adev;
-
-       down_read(&adev->reset_domain->sem);
-       xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
-       up_read(&adev->reset_domain->sem);
-}
-
 /**
  * amdgpu_userq_ensure_ev_fence - ensure a valid, unsignaled eviction fence 
exists
  * @uq_mgr: the usermode queue manager for this process
@@ -547,8 +538,12 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, 
struct amdgpu_usermode_que
 
        mutex_lock(&uq_mgr->userq_mutex);
        amdgpu_userq_wait_for_last_fence(queue);
+       mutex_unlock(&uq_mgr->userq_mutex);
 
-       amdgpu_userq_detach_doorbell(queue);
+       /* GPU recovery takes userq_mutex under reset_domain->sem, keep that 
order */
+       down_read(&adev->reset_domain->sem);
+       mutex_lock(&uq_mgr->userq_mutex);
+       xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
 
 #if defined(CONFIG_DEBUG_FS)
        debugfs_remove_recursive(queue->debugfs_queue);
@@ -558,6 +553,7 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, 
struct amdgpu_usermode_que
        amdgpu_userq_fence_driver_free(queue);
        queue->fence_drv = NULL;
        mutex_unlock(&uq_mgr->userq_mutex);
+       up_read(&adev->reset_domain->sem);
 
        /*
         * A failed unmap means MES could not remove the hung queue and is now
-- 
2.34.1

Reply via email to