On 7/14/26 10:02, Srinivasan Shanmugam wrote: > Signal QUEUE_RESET EVENTFD subscriptions when hung user queues are > detected. > > MES reports the doorbell indices of hung queues. Use the existing > doorbell-to-queue mapping to resolve the affected queue without scanning > all user queues. > > Consolidate the queue state update, reset accounting, EVENTFD signaling, > fence completion, and wedged event notification in a common helper. Use > the helper for both the original guilty queue and additional affected > queues. > > EVENTFD remains notification-only. > > v2: (per Christian) > - Use the doorbell xarray to look up affected queues instead of scanning > all queues. > - Move queue reset handling into amdgpu_userq.c. > - Consolidate queue state updates, EVENTFD signaling, and fence > completion in a single helper. > > v3: Rebase only. > > v4: (per Alex) > - Rebase on Alex's "drm/amdgpu/userq: properly account for resets". > - Preserve the reset counter update in the common hung queue helper. > - Use amdgpu_userq_handle_hung_queue() for both successful queue reset > paths. > > Suggested-by: Christian König <[email protected]> > Suggested-by: Alex Deucher <[email protected]> > Signed-off-by: Srinivasan Shanmugam <[email protected]>
Acked-by: Christian König <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 39 +++++++++--- > drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 + > drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 72 ++++++++++++++-------- > 3 files changed, 80 insertions(+), 33 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > index fb0d335875af..65b20d7a4b18 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > @@ -135,6 +135,34 @@ static void amdgpu_userq_mgr_reset_work(struct > work_struct *work) > amdgpu_device_gpu_recover(adev, NULL, &reset_context); > } > > +/** > + * amdgpu_userq_handle_hung_queue - handle a successfully reset hung queue > + * @adev: AMDGPU device > + * @queue: affected user queue > + * > + * Mark the queue as hung, account for the reset, force-complete its > + * fences, notify matching QUEUE_RESET EVENTFD subscribers, and send > + * the DRM wedged event. > + */ > +void amdgpu_userq_handle_hung_queue(struct amdgpu_device *adev, > + struct amdgpu_usermode_queue *queue) > +{ > + struct amdgpu_eventfd_mgr *eventfd_mgr; > + > + queue->state = AMDGPU_USERQ_STATE_HUNG; > + atomic_inc(&adev->gpu_reset_counter); > + > + amdgpu_userq_fence_driver_force_completion(queue); > + > + eventfd_mgr = amdgpu_userq_eventfd_mgr(queue->userq_mgr); > + amdgpu_eventfd_signal(eventfd_mgr, > + DRM_AMDGPU_EVENT_TYPE_QUEUE_RESET, > + queue); > + > + drm_dev_wedged_event(adev_to_drm(adev), > + DRM_WEDGE_RECOVERY_NONE, NULL); > +} > + > static void amdgpu_userq_hang_detect_work(struct work_struct *work) > { > struct amdgpu_usermode_queue *queue = > @@ -167,13 +195,10 @@ 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, NULL); > - } > + else > + amdgpu_userq_handle_hung_queue(adev, queue); > } else { > gpu_reset = true; > } > @@ -247,8 +272,6 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device > *adev, u32 doorbell) > xa_unlock_irqrestore(xa, flags); > } > > - > - > int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, > struct amdgpu_usermode_queue *queue, > u64 addr, u64 expected_size, > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h > index b69621311b80..526e007e300e 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h > @@ -180,6 +180,8 @@ void amdgpu_userq_pre_reset(struct amdgpu_device *adev); > int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); > void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue > *queue); > void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 > doorbell); > +void amdgpu_userq_handle_hung_queue(struct amdgpu_device *adev, > + struct amdgpu_usermode_queue *queue); > > /* > * CP packs the per-process doorbell_id of the queue in > diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c > b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c > index 3fad95199e0c..27adcea7b9a0 100644 > --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c > +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c > @@ -26,6 +26,7 @@ > #include "amdgpu_gfx.h" > #include "mes_userqueue.h" > #include "amdgpu_userq_fence.h" > +#include "amdgpu_userq_internal.h" > #include "amdgpu_cwsr.h" > > #define AMDGPU_USERQ_PROC_CTX_SZ PAGE_SIZE > @@ -238,34 +239,55 @@ int mes_userq_reset_queue(struct amdgpu_device *adev, > unsigned int queue, > unsigned int db) > { > + struct xarray *xa = &adev->userq_doorbell_xa; > struct amdgpu_usermode_queue *uq; > bool use_mmio = adev->gfx.mec.use_mmio_for_reset; > - unsigned long uq_id; > - int r; > + unsigned long flags; > + int r = 0; > > - xa_for_each(&adev->userq_doorbell_xa, uq_id, uq) { > - if (uq->queue_type == queue_type) { > - if (uq == guilty_uq) > - continue; > - if (uq->doorbell_index == db) { > - uq->state = AMDGPU_USERQ_STATE_HUNG; > - if (use_mmio) > - r = amdgpu_mes_reset_queue_mmio(adev, > queue_type, 0, 1, pipe, queue, 0); > - else > - r = amdgpu_mes_reset_user_queue(adev, > queue_type, db, 0); > - if (r) > - return r; > - 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; > - } > - } > - } > - return 0; > + /* > + * Resolve the doorbell directly to the affected queue instead of > + * scanning all user queues. > + */ > + xa_lock_irqsave(xa, flags); > + > + uq = xa_load(xa, db); > + if (uq) > + kref_get(&uq->refcount); > + > + xa_unlock_irqrestore(xa, flags); > + > + if (!uq) > + return 0; > + > + /* > + * The guilty queue is handled separately by the caller. > + */ > + if (uq == guilty_uq) > + goto out_put_queue; > + > + if (uq->queue_type != queue_type) > + goto out_put_queue; > + > + if (use_mmio) > + r = amdgpu_mes_reset_queue_mmio(adev, queue_type, > + 0, 1, pipe, queue, 0); > + else > + r = amdgpu_mes_reset_user_queue(adev, queue_type, db, 0); > + > + if (r) > + goto out_put_queue; > + > + r = mes_userq_unmap(uq); > + if (r) > + goto out_put_queue; > + > + amdgpu_userq_handle_hung_queue(adev, uq); > + > +out_put_queue: > + amdgpu_userq_put(uq); > + > + return r; > } > > static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
