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]> --- 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, -- 2.34.1
