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 | 39 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 ++ drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 21 ++++-------- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index ab3f6509a5bc..3ccaa571d90b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -241,7 +241,46 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) xa_unlock_irqrestore(xa, flags); } +bool amdgpu_userq_handle_hung_doorbell(struct amdgpu_device *adev, + int queue_type, u32 doorbell) +{ + struct xarray *xa = &adev->userq_doorbell_xa; + struct amdgpu_usermode_queue *queue; + struct amdgpu_eventfd_mgr *eventfd_mgr; + unsigned long flags; + bool handled = false; + + xa_lock_irqsave(xa, flags); + queue = xa_load(xa, doorbell); + if (queue) + kref_get(&queue->refcount); + xa_unlock_irqrestore(xa, flags); + if (!queue) + return false; + + if (queue->queue_type != queue_type) + goto out; + + 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); + + handled = true; + +out: + amdgpu_userq_put(queue); + + return handled; +} 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 e1a7d0dbc436..73fec6b623e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -173,6 +173,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_doorbell(struct amdgpu_device *adev, + int queue_type, u32 doorbell); int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, struct amdgpu_usermode_queue *queue, diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index e9189f07c6dc..befe83a5b8eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -210,9 +210,7 @@ static int mes_userq_detect_and_reset(struct amdgpu_device *adev, { int db_array_size = amdgpu_mes_get_hung_queue_db_array_size(adev); struct mes_detect_and_reset_queue_input input; - struct amdgpu_usermode_queue *queue; unsigned int hung_db_num = 0; - unsigned long queue_id; u32 db_array[8]; bool found_hung_queue = false; int r, i; @@ -232,19 +230,14 @@ static int mes_userq_detect_and_reset(struct amdgpu_device *adev, &hung_db_num, db_array, 0); amdgpu_mes_unlock(&adev->mes); if (r) { - dev_err(adev->dev, "Failed to detect and reset queues, err (%d)\n", r); + dev_err(adev->dev, + "Failed to detect and reset queues, err (%d)\n", r); } else if (hung_db_num) { - xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) { - if (queue->queue_type == queue_type) { - for (i = 0; i < hung_db_num; i++) { - if (queue->doorbell_index == db_array[i]) { - queue->state = AMDGPU_USERQ_STATE_HUNG; - found_hung_queue = true; - 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); - } - } + for (i = 0; i < hung_db_num; i++) { + if (amdgpu_userq_handle_hung_doorbell(adev, queue_type, + db_array[i])) { + found_hung_queue = true; + atomic_inc(&adev->gpu_reset_counter); } } } -- 2.34.1
