Re: [PATCH 2/2] drm/amdgpu: rework the amdgpu_device_gpu_recover() lock sequence

Christian König <[email protected]> Wed, 5 Aug 2026 09:57:30 +0200
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
On 7/27/26 15:35, Prike Liang wrote:
> Suspend the KMS/DRM clients before locking the reset domain.
> drm_client_dev_suspend() acquires clientlist_mutex, which must be
> taken outside reset_domain->sem. Acquiring it while holding the
> reset domain lock inverts the ordering established elsewhere
> (clientlist_mutex -> ... -> reset_domain->sem) and can deadlock.


That is a good catch, but clearly not the correct resolution.

drm_client_dev_suspend() should *never* be called from the reset path in the first place.

This is only for suspend/resume and can trivially deadlock here through quite a number of other locks.

Regards,
Christian.

> 
> Signed-off-by: Prike Liang <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 20 ++++++++++++++++++--
>  1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 472e96ae884e..c670d5cfe3cc 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -5371,8 +5371,6 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev,
>  		 */
>  		amdgpu_unregister_gpu_instance(tmp_adev);
>  
> -		drm_client_dev_suspend(adev_to_drm(tmp_adev));
> -
>  		/* disable ras on ALL IPs */
>  		if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev))
>  			amdgpu_ras_suspend(tmp_adev);
> @@ -5535,6 +5533,22 @@ static void amdgpu_device_gpu_resume(struct amdgpu_device *adev,
>  }
>  
>  
> +static void amdgpu_device_recovery_suspend_clients(struct list_head *device_list)
> +{
> +	struct amdgpu_device *tmp_adev = NULL;
> +
> +	list_for_each_entry(tmp_adev, device_list, reset_list)
> +		drm_client_dev_suspend(adev_to_drm(tmp_adev));
> +}
> +
> +static void amdgpu_device_recovery_resume_clients(struct list_head *device_list)
> +{
> +	struct amdgpu_device *tmp_adev = NULL;
> +
> +	list_for_each_entry(tmp_adev, device_list, reset_list)
> +		drm_client_dev_resume(adev_to_drm(tmp_adev));
> +}
> +
>  /**
>   * amdgpu_device_gpu_recover - reset the asic and recover scheduler
>   *
> @@ -5613,6 +5627,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>  	/* Cannot be called after locking reset domain */
>  	amdgpu_ras_pre_reset(adev, &device_list);
>  
> +	amdgpu_device_recovery_suspend_clients(&device_list);
>  	/* We need to lock reset domain only once both for XGMI and single device */
>  	amdgpu_device_recovery_get_reset_lock(adev, &device_list);
>  
> @@ -5649,6 +5664,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>  	amdgpu_device_gpu_resume(adev, &device_list, need_emergency_restart);
>  reset_unlock:
>  	amdgpu_device_recovery_put_reset_lock(adev, &device_list);
> +	amdgpu_device_recovery_resume_clients(&device_list);
>  	amdgpu_ras_post_reset(adev, &device_list);
>  end_reset:
>  	if (hive) {