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