summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Zhang <Jesse.Zhang@amd.com>2026-09-03 17:36:37 +0800
committerAlex Deucher <alexander.deucher@amd.com>2026-09-10 12:08:25 -0400
commit4a263bc34083b35235c8b5b09fb37b789e60b321 (patch)
tree9020674a541606dd8d5803a1bc9b80534a649520
parent6537bd210878a59b103a193c4eb808a7504ecca6 (diff)
downloadlinux-next-4a263bc34083b35235c8b5b09fb37b789e60b321.tar.gz
linux-next-4a263bc34083b35235c8b5b09fb37b789e60b321.zip
drm/amdgpu/userq: reset a hung SDMA user queue over MMIO
A hung SDMA user queue wedges MES, so the MES packet reset times out and falls back to a full MODE1 reset - once per in-flight job, a reset storm. The queue is still on its HW slot at the first hang-detect, so use detect_hung_queue to recover its slot from the doorbell and reset it over MMIO, which does not need MES. Mark it HUNG (not UNMAPPED) so the restore worker does not re-map and re-run the guilty job, and short-circuit the per-fence hang-detect re-entry once the queue is already reset. Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 46ebc002548d..68beccee9fc0 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -213,26 +213,55 @@ int mes_userq_reset(struct amdgpu_usermode_queue *queue)
struct mes_reset_queue_input queue_input;
int r;
- /* XXX: add a FW version check for SDMA per queue reset */
+ /* already reset by an earlier job's hang-detect; just signal and bail */
+ if (queue->state == AMDGPU_USERQ_STATE_HUNG)
+ return 0;
+
memset(&queue_input, 0x0, sizeof(struct mes_reset_queue_input));
queue_input.doorbell_offset = queue->doorbell_index;
queue_input.queue_type = queue->queue_type;
+ /*
+ * The MES packet reset fails once the hung queue wedges MES. For SDMA the
+ * queue is still on its HW slot, so reset it over MMIO instead: recover
+ * the (instance, queue_id) slot from the doorbell.
+ */
+ if (queue->queue_type == AMDGPU_HW_IP_DMA &&
+ adev->sdma.instance[0].funcs &&
+ adev->sdma.instance[0].funcs->detect_hung_queue) {
+ u32 instance, hw_queue_id;
+
+ if (adev->sdma.instance[0].funcs->detect_hung_queue(adev,
+ queue->doorbell_index, &instance, &hw_queue_id)) {
+ queue_input.use_mmio = true;
+ queue_input.me_id = instance;
+ queue_input.queue_id = hw_queue_id;
+ } else {
+ dev_warn(adev->dev,
+ "SDMA userq (doorbell %llu) not on any HW slot; falling back to MES reset\n",
+ queue->doorbell_index);
+ }
+ }
+
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes);
if (r)
return r;
- /* mes_userq_unmap() does not update queue->state; mark it UNMAPPED so the
- * destroy path does not issue a second REMOVE_QUEUE for the removed queue.
- */
+ /* drop the queue from MES */
r = mes_userq_unmap(queue);
- if (!r) {
- trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED);
- queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
- }
- return r;
+ if (r)
+ return r;
+
+ /*
+ * HUNG, not UNMAPPED: the guilty job is still in the ring, so the
+ * restore worker must not re-map and re-run it.
+ */
+ trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
+ queue->state = AMDGPU_USERQ_STATE_HUNG;
+
+ return 0;
}
int mes_userq_reset_queue(struct amdgpu_device *adev,