AMD General

> -----Original Message-----
> From: amd-gfx <[email protected]> On Behalf Of Alex
> Deucher
> Sent: Tuesday, July 14, 2026 9:25 PM
> To: [email protected]
> Cc: Deucher, Alexander <[email protected]>; SHANMUGAM,
> SRINIVASAN <[email protected]>; Liang, Prike
> <[email protected]>; Khatri, Sunil <[email protected]>; Lazar, Lijo
> <[email protected]>
> Subject: [PATCH V2] drm/amdgpu: properly account for resets with user queues
>
> We need to increment the reset counter, force fence completion, and set the
> wedged event when a user queue is reset, but only for the guilty queue.  We 
> don't
> want additional events for collateral damage.
>
> Only increment the reset counter and set the wedged event in the top level 
> userq
> reset callers (both KGD and KFD).
> This aligns with how this is managed for kernel queue resets.
>
> v2: fix task info refcount handling, align with
>     kfd error reporting.
>
> Signed-off-by: Alex Deucher <[email protected]>
> Cc: Srinivasan Shanmugam <[email protected]>
> Cc: Prike Liang <[email protected]>
> Cc: Sunil Khatri <[email protected]>
> Cc: Lazar, Lijo <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c      | 18 +++++++++++++++++-
>  drivers/gpu/drm/amd/amdgpu/mes_userqueue.c     |  2 --
>  .../drm/amd/amdkfd/kfd_device_queue_manager.c  | 17 ++++++++++++++++-
>  3 files changed, 33 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> index 6aa75da27f912..58754fc41bb6c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> @@ -123,6 +123,8 @@ static void amdgpu_userq_hang_detect_work(struct
> work_struct *work)
>       struct amdgpu_device *adev = uq_mgr->adev;
>       const struct amdgpu_userq_funcs *userq_funcs =
>               adev->userq_funcs[queue->queue_type];
> +     struct drm_wedge_task_info *info = NULL;
> +     struct amdgpu_task_info *ti = NULL;
>       bool gpu_reset = false;
>
>       if (unlikely(adev->debug_disable_gpu_ring_reset)) { @@ -137,6 +139,14
> @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
>       if (!amdgpu_gpu_recovery)
>               return;
>
> +     if (queue->vm && queue->vm->pasid) {
> +             ti = amdgpu_vm_get_task_info_pasid(adev, queue->vm->pasid);
> +             if (ti) {
> +                     amdgpu_vm_print_task_info(adev, ti);
> +                     info = &ti->task;
> +             }
> +     }
> +
>       if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
>
> AMDGPU_RESET_TYPE_PER_QUEUE)) {
>               int r;
> @@ -146,11 +156,17 @@ static void amdgpu_userq_hang_detect_work(struct
> work_struct *work)
>                                                        queue, NULL, NULL);
>               else
>                       r = userq_funcs->reset(queue);
> -             if (r)
> +             if (r) {
>                       gpu_reset = true;
> +             } else {
> +                     atomic_inc(&adev->gpu_reset_counter);
> +                     amdgpu_userq_fence_driver_force_completion(queue);
> +                     drm_dev_wedged_event(adev_to_drm(adev),
> DRM_WEDGE_RECOVERY_NONE, info);
> +             }
>       } else {
>               gpu_reset = true;
>       }
> +     amdgpu_vm_put_task_info(ti);
>
>       /*
>        * Don't schedule the work here! Scheduling or queue work from one reset
> diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> index d3d79bbaf9eb7..a1371a9f961d1 100644
> --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
> @@ -234,9 +234,7 @@ int mes_userq_reset_queue(struct amdgpu_device *adev,
>                               r = mes_userq_unmap(uq);
>                               if (r)
>                                       return r;
> -                             atomic_inc(&adev->gpu_reset_counter);
>                               amdgpu_userq_fence_driver_force_completion(uq);
> -                             drm_dev_wedged_event(adev_to_drm(adev),
> DRM_WEDGE_RECOVERY_NONE, NULL);
>                               break;
>                       }
>               }
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> index 0419fe869d4b0..58ccbf955f287 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> @@ -448,6 +448,9 @@ int kfd_reset_queue_mes(struct device_queue_manager
> *dqm, int queue_type,  static int reset_queues_mes(struct device_queue_manager
> *dqm, struct queue *q)  {
>       struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
> +     struct drm_wedge_task_info *info = NULL;
> +     struct amdgpu_task_info *ti = NULL;
> +     struct kfd_process_device *pdd;
>       unsigned int num_hung = 0;
>       int r = 0;
>       struct mes_remove_queue_input queue_input; @@ -476,13 +479,25 @@
> static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q)
>       r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL, NULL,
> &num_hung, &queue_input);
>       if (r)
>               goto fail;
> +     pdd = kfd_get_process_device_data(q->device, q->process);
> +     if (pdd) {
> +             ti = amdgpu_vm_get_task_info_pasid(adev, pdd->pasid);
> +             if (ti) {
> +                     amdgpu_vm_print_task_info(adev, ti);
> +                     info = &ti->task;
> +             }
> +     }
>
>       dqm->detect_hang_count = num_hung;
>       /* When MES doesn't detect any queue hang, no reset happens. Don't
> signal reset
>        * event.
>        */
> -     if (dqm->detect_hang_count)
> +     if (dqm->detect_hang_count) {
>               kfd_signal_reset_event(dqm->dev);
> +             atomic_inc(&adev->gpu_reset_counter);
> +             drm_dev_wedged_event(adev_to_drm(adev),
> DRM_WEDGE_RECOVERY_NONE, info);
> +     }
> +     amdgpu_vm_put_task_info(ti);
>
>  fail:
>       dqm->detect_hang_count = 0;
> --

Thanks for addressing the review comments.

Looks good to me.

The reset accounting is now performed only for the guilty queue in the
top-level KGD/KFD reset paths. During a queue recovery, additional
collateral queues may also need to be reset as part of the same recovery
operation. Those collateral queues still have their fences
force-completed, but they no longer increment the device reset counter
or generate additional DRM wedged events. As a result, a single
recovery operation generates one device-level reset notification,
which aligns with the kernel queue reset handling.

The task-info reference handling is also now consistent with the
existing amdgpu_job_timedout() path. The reference obtained through
amdgpu_vm_get_task_info_pasid() is released with
amdgpu_vm_put_task_info() after its final use.

Reviewed-by: Srinivasan Shanmugam <[email protected]>

> 2.55.0

Reply via email to