diff options
| author | Jesse Zhang <Jesse.Zhang@amd.com> | 2026-09-03 17:36:37 +0800 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-09-10 12:08:25 -0400 |
| commit | 4a263bc34083b35235c8b5b09fb37b789e60b321 (patch) | |
| tree | 9020674a541606dd8d5803a1bc9b80534a649520 | |
| parent | 6537bd210878a59b103a193c4eb808a7504ecca6 (diff) | |
| download | linux-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.c | 47 |
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, |
