On 10/13/26 10:24, Prike Liang wrote:
> amdgpu_userq_destroy() takes reset_domain->sem for read in
> amdgpu_userq_detach_doorbell() while holding userq_mutex.

Yeah that is correct behavior.

> GPU recovery
> holds reset_domain->sem for write and then takes clientlist_mutex in
> drm_client_dev_suspend(),

That is completely broken behavior and need to be fixed.

The GPU reset can *NEVER* call drm_client_dev_suspend(), who came up with that 
nonsense?

Regards,
Christian.

> 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

Reply via email to