Retire all old queues after successful hardware reset. Pre-reset suspension,
removal and resumption are therefore unnecessary for that lifecycle. Remove
these firmware operations and only mark the queues RESET_PENDING. Leave
their fences pending until hardware reset establishes quiescence, including
when reset fails or is skipped. Clear the count before draining to prevent a
running worker from rearming.

Fixes: a33a2db6af0a ("drm/amdgpu: bracket pre-reset userq removal with MES 
suspend and resume")
Fixes: 99f2f5b9ef67 ("drm/amdgpu/userq: complete eviction fences after hardware 
reset")
Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c    | 17 +++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h    |  1 +
 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 | 17 +++++++++--
 5 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
index 4138080edbea..851405d9fea4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
@@ -1243,6 +1243,23 @@ void amdgpu_mes_userq_queue_unmapped(struct 
amdgpu_device *adev)
                cancel_delayed_work(&adev->mes.userq_notify_unmap_work);
 }
 
+/* Hardware reset discarded all old user queues, including failed removals. */
+void amdgpu_mes_userq_reset_complete(struct amdgpu_device *adev)
+{
+       lockdep_assert_held_write(&adev->reset_domain->sem);
+
+       if (!adev->enable_mes || amdgpu_sriov_vf(adev))
+               return;
+
+       if (!(amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0) &&
+             amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(12, 0, 0)))
+               return;
+
+       /* Stop rearming before draining a worker that may have dropped its 
lock. */
+       atomic_set(&adev->mes.userq_hw_queue_count, 0);
+       cancel_delayed_work_sync(&adev->mes.userq_notify_unmap_work);
+}
+
 #if defined(CONFIG_DEBUG_FS)
 
 static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
index 5160b227943b..738226b3ac2a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
@@ -653,5 +653,6 @@ void amdgpu_mes_free_gang_ctx_index(struct amdgpu_mes *mes,
 int amdgpu_mes_notify_unmap_queue(struct amdgpu_device *adev);
 void amdgpu_mes_userq_queue_mapped(struct amdgpu_device *adev);
 void amdgpu_mes_userq_queue_unmapped(struct amdgpu_device *adev);
+void amdgpu_mes_userq_reset_complete(struct amdgpu_device *adev);
 
 #endif /* __AMDGPU_MES_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 0f509e67ca1a..5fe16185b887 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -1626,33 +1626,21 @@ void amdgpu_userq_gem_va_unmap_validate(struct 
amdgpu_device *adev,
 
 void amdgpu_userq_pre_reset(struct amdgpu_device *adev)
 {
-       const struct amdgpu_userq_funcs *userq_funcs;
        struct amdgpu_usermode_queue *queue;
        unsigned long queue_id;
 
        lockdep_assert_held_write(&adev->reset_domain->sem);
-       if (xa_empty(&adev->userq_doorbell_xa))
-               return;
-
-       /* Best effort: only the subsequent hardware reset proves quiescence. */
-       if (amdgpu_mes_suspend(adev, 0))
-               dev_dbg(adev->dev, "Continuing GPU reset after MES suspend 
failure\n");
 
+       /*
+        * Device reset will retire these queues. Asking a faulted MES to 
suspend
+        * or remove them can time out once per queue and delays the reset. Do
+        * not resume them either: keep their memory protected until hardware
+        * reset proves that all queue access has stopped.
+        */
        xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
-               if (queue->state == AMDGPU_USERQ_STATE_MAPPED ||
-                   queue->state == AMDGPU_USERQ_STATE_PREEMPTED) {
-                       trace_amdgpu_userq_state_start(queue);
-                       userq_funcs = adev->userq_funcs[queue->queue_type];
-                       userq_funcs->unmap(queue);
-               }
-               /* A failed unmap is not proof that hardware access has 
stopped. */
                trace_amdgpu_userq_state_changed(queue, 
AMDGPU_USERQ_STATE_RESET_PENDING);
                queue->state = AMDGPU_USERQ_STATE_RESET_PENDING;
        }
-
-       /* Pair locally, including partial suspension and failed queue removal. 
*/
-       if (amdgpu_mes_resume(adev, 0))
-               dev_dbg(adev->dev, "Continuing GPU reset after MES resume 
failure\n");
 }
 
 /* Called after successful hardware reset, before allocations during resume. */
@@ -1661,13 +1649,18 @@ void amdgpu_userq_reset_complete(struct amdgpu_device 
*adev)
        struct amdgpu_usermode_queue *queue;
        unsigned long queue_id;
 
+       lockdep_assert_held_write(&adev->reset_domain->sem);
+       amdgpu_mes_userq_reset_complete(adev);
+
        if (xa_empty(&adev->userq_doorbell_xa))
                return;
 
-       lockdep_assert_held_write(&adev->reset_domain->sem);
-
        /* Release queue-fence waiters before acquiring their manager mutexes. 
*/
        xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
+               const struct amdgpu_userq_funcs *funcs = 
adev->userq_funcs[queue->queue_type];
+
+               if (funcs->reset_complete)
+                       funcs->reset_complete(queue);
                trace_amdgpu_userq_state_changed(queue, 
AMDGPU_USERQ_STATE_HUNG);
                queue->state = AMDGPU_USERQ_STATE_HUNG;
                amdgpu_userq_fence_driver_force_completion(queue);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index d17dbc284688..eb4e51613908 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -103,6 +103,7 @@ struct amdgpu_usermode_queue {
        } userq_vas;
 
        uint32_t        gang_ctx_array_index;
+       bool            gang_ctx_allocated;
 };
 
 struct amdgpu_userq_funcs {
@@ -116,6 +117,8 @@ struct amdgpu_userq_funcs {
        int (*preempt)(struct amdgpu_usermode_queue *queue);
        int (*restore)(struct amdgpu_usermode_queue *queue);
        int (*reset)(struct amdgpu_usermode_queue *queue);
+       /* Release software resources only after successful device reset. */
+       void (*reset_complete)(struct amdgpu_usermode_queue *queue);
 };
 
 /* Usermode queues for gfx */
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c 
b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 3b973ea0c24a..fa67899fcd32 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -161,6 +161,7 @@ static int mes_userq_map(struct amdgpu_usermode_queue 
*queue)
                        DRM_ERROR("Failed to allocate userq gang index 
err:%d\n", r);
                        return r;
                }
+               queue->gang_ctx_allocated = true;
                queue_input.process_context_array_index = 
uq_mgr->proc_ctx_array_index;
                queue_input.gang_context_array_index = 
queue->gang_ctx_array_index;
        }
@@ -178,13 +179,23 @@ static int mes_userq_map(struct amdgpu_usermode_queue 
*queue)
        return 0;
 }
 
+/* The queue must have been removed successfully or stopped by device reset. */
+static void mes_userq_release_gang_ctx(struct amdgpu_usermode_queue *queue)
+{
+       struct amdgpu_mes *mes = &queue->userq_mgr->adev->mes;
+
+       if (queue->gang_ctx_allocated) {
+               amdgpu_mes_free_gang_ctx_index(mes, 
queue->gang_ctx_array_index);
+               queue->gang_ctx_allocated = false;
+       }
+}
+
 static int mes_userq_unmap(struct amdgpu_usermode_queue *queue)
 {
        struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
        struct amdgpu_device *adev = uq_mgr->adev;
        struct mes_remove_queue_input queue_input;
        struct amdgpu_userq_obj *ctx = &queue->fw_obj;
-       struct amdgpu_mes *mes = &adev->mes;
        int r;
 
        memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input));
@@ -196,13 +207,12 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue 
*queue)
        amdgpu_mes_lock(&adev->mes);
        r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
        amdgpu_mes_unlock(&adev->mes);
-       if (mes->use_rs64mem)
-               amdgpu_mes_free_gang_ctx_index(mes, 
queue->gang_ctx_array_index);
        if (r) {
                DRM_ERROR("Failed to unmap queue in HW, err (%d)\n", r);
                return r;
        }
 
+       mes_userq_release_gang_ctx(queue);
        amdgpu_mes_userq_queue_unmapped(adev);
        return 0;
 }
@@ -646,4 +656,5 @@ const struct amdgpu_userq_funcs userq_mes_funcs = {
        .preempt = mes_userq_preempt,
        .restore = mes_userq_restore,
        .reset = mes_userq_reset,
+       .reset_complete = mes_userq_release_gang_ctx,
 };
-- 
2.34.1

Reply via email to