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

Reply via email to