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

Reply via email to