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