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

Reply via email to