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 find the affected queue and notify matching EVENTFD subscribers. Move the queue reset handling into amdgpu_userq.c so the queue lookup and queue handling are performed in one place. This avoids scanning all queues to find a matching doorbell. 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. Cc: Alex Deucher <[email protected]> Suggested-by: Christian König <[email protected]> Signed-off-by: Srinivasan Shanmugam <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 33 ++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 3 +- drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 73 ++++++++++++++-------- 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index ab3ef3a9f655..5bf231d7a630 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -242,7 +242,40 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) xa_unlock_irqrestore(xa, flags); } +/** + * amdgpu_userq_handle_hung_queue - handle a successfully reset hung queue + * @adev: AMDGPU device + * @queue: affected user queue + * + * Mark the queue as hung, notify matching QUEUE_RESET EVENTFD + * subscribers, force-complete its fences, and send the DRM wedged event. + * + * Return: + * true when the queue was handled, false for an invalid queue. + */ +bool +amdgpu_userq_handle_hung_queue(struct amdgpu_device *adev, + struct amdgpu_usermode_queue *queue) +{ + struct amdgpu_eventfd_mgr *eventfd_mgr; + if (!queue) + return false; + + queue->state = AMDGPU_USERQ_STATE_HUNG; + + eventfd_mgr = amdgpu_userq_eventfd_mgr(queue->userq_mgr); + amdgpu_eventfd_signal(eventfd_mgr, + DRM_AMDGPU_EVENT_TYPE_QUEUE_RESET, + queue); + + amdgpu_userq_fence_driver_force_completion(queue); + + drm_dev_wedged_event(adev_to_drm(adev), + DRM_WEDGE_RECOVERY_NONE, NULL); + + return true; +} int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, struct amdgpu_usermode_queue *queue, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index b69621311b80..187bfd66eb13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -180,7 +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); - +bool 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 * CTXID0[9:0] on priv-fault (same encoding KFD uses via diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 3fad95199e0c..4b546613c024 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,56 @@ 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; + + if (amdgpu_userq_handle_hung_queue(adev, uq)) + atomic_inc(&adev->gpu_reset_counter); + +out_put_queue: + amdgpu_userq_put(uq); + + return r; } static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr, -- 2.34.1
