diff options
| author | Jesse Zhang <Jesse.Zhang@amd.com> | 2026-09-16 15:53:15 +0800 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-10-01 11:20:52 -0400 |
| commit | cd3de60ae64c0e63348b00a0e4a736c7bc585bb1 (patch) | |
| tree | a87c5c4be51ca3dcd8ae09c6464772bf0989473b /drivers | |
| parent | f3a41f6fe5d55d57d22fee743b456ddaadac5417 (diff) | |
| download | linux-next-cd3de60ae64c0e63348b00a0e4a736c7bc585bb1.tar.gz linux-next-cd3de60ae64c0e63348b00a0e4a736c7bc585bb1.zip | |
drm/amdgpu/mes11: restore collateral gfx queues after pipe reset
A pipe reset restarts the shared PFP/ME, but CP firmware dequeues only
the requested queue. Wait for its CP_VMID_RESET bit and HQD_ACTIVE to
clear, and return -ETIMEDOUT if recovery does not complete.
Preempt each collateral kernel queue and wait for its HQD to deactivate
before rebuilding its MQD/ring and remapping it. Leave the guilty kernel
queue to the outer reset helper.
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>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 137 |
1 files changed, 110 insertions, 27 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 51bfb672bed7..cc691cd0aca0 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -413,19 +413,85 @@ static bool mes_v11_0_pipe_reset_support(struct amdgpu_device *adev) dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n"); return false; } + +/* Use MES callbacks directly while holding the MES lock. */ +static int mes_v11_0_restore_gfx_kernel_queue(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 guilty_queue, + bool is_kq) +{ + struct amdgpu_ring *ring; + int i, j, r; + + /* + * Only the guilty HQD was dequeued; stop collateral HQDs before rebuild. + * The outer reset helper restores the guilty kernel queue. + */ + for (i = 0; i < adev->gfx.num_gfx_rings; i++) { + struct mes_unmap_legacy_queue_input unmap = { 0 }; + struct mes_map_legacy_queue_input map = { 0 }; + + ring = &adev->gfx.gfx_ring[i]; + if (ring->me != me || ring->pipe != pipe || + (is_kq && ring->queue == guilty_queue)) + continue; + + unmap.action = PREEMPT_QUEUES; + unmap.queue_type = ring->funcs->type; + unmap.doorbell_offset = ring->doorbell_index; + unmap.pipe_id = ring->pipe; + unmap.queue_id = ring->queue; + r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &unmap); + if (r) + return r; + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + mutex_lock(&adev->srbm_mutex); + soc21_grbm_select(adev, me, pipe, ring->queue, 0); + for (j = 0; j < adev->usec_timeout; j++) { + if (!(RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + soc21_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + if (j == adev->usec_timeout) + return -ETIMEDOUT; + + amdgpu_gfx_mqd_reset_restore(ring); + + map.queue_type = ring->funcs->type; + map.doorbell_offset = ring->doorbell_index; + map.pipe_id = ring->pipe; + map.queue_id = ring->queue; + map.mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj); + map.wptr_addr = ring->wptr_gpu_addr; + r = adev->mes.funcs->map_legacy_queue(&adev->mes, &map); + if (r) + return r; + } + + return 0; +} + static int mes_v11_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev, - u32 me, u32 pipe, u32 queue) + u32 me, u32 pipe, u32 queue, + bool is_kq) { - uint32_t reset_pipe = 0, clean_pipe = 0; - int r; + /* gfx11 keeps a setup ring object even when kernel queues are disabled. */ + bool has_kq = !adev->gfx.disable_kq && adev->gfx.num_gfx_rings >= 1; + uint32_t reset_pipe, clean_pipe; + int i; if (!mes_v11_0_pipe_reset_support(adev)) return -EOPNOTSUPP; - amdgpu_gfx_rlc_enter_safe_mode(adev, 0); mutex_lock(&adev->srbm_mutex); soc21_grbm_select(adev, me, pipe, queue, 0); + reset_pipe = RREG32_SOC15(GC, 0, regCP_ME_CNTL); + clean_pipe = reset_pipe; + switch (pipe) { case 0: reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, @@ -451,21 +517,35 @@ static int mes_v11_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev, break; } + /* Preserve ACTIVE/DEQUEUE so warm firmware can complete queue release. */ WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe); + soc21_grbm_select(adev, me, pipe, queue, 0); WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe); - r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) - - RS64_FW_UC_START_ADDR_LO; + /* CP firmware releases only the queue named in CP_VMID_RESET. */ + soc21_grbm_select(adev, me, pipe, queue, 0); + for (i = 0; i < adev->usec_timeout; i++) { + if (!(RREG32_SOC15(GC, 0, regCP_VMID_RESET) & + BIT(16 + pipe * 8 + queue)) && + !(RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + soc21_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); amdgpu_gfx_rlc_exit_safe_mode(adev, 0); - dev_info(adev->dev, "The gfx pipe reset to the ME firmware start PC: %s\n", - r == 0 ? "successfully" : "failed"); - /* FIXME: Sometimes driver can't cache the ME firmware start PC correctly, - * so the pipe reset status relies on the later gfx ring test result. - */ - return 0; + if (i >= adev->usec_timeout) { + dev_err(adev->dev, + "gfx pipe reset: CP front-end still busy, CP still wedged\n"); + return -ETIMEDOUT; + } + + if (!has_kq) + return 0; + + return mes_v11_0_restore_gfx_kernel_queue(adev, me, pipe, queue, is_kq); } /* @@ -617,20 +697,6 @@ static int mes_v11_0_reset_compute_pipe_mmio(struct amdgpu_device *adev, return 0; } -static int mes_v11_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type, - uint32_t me_id, uint32_t pipe_id, - uint32_t queue_id, uint32_t vmid) -{ - struct amdgpu_device *adev = mes->adev; - - if (queue_type == AMDGPU_RING_TYPE_GFX) - return mes_v11_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id); - else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) - return mes_v11_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id); - else - return -EOPNOTSUPP; -} - static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_type, uint32_t me_id, uint32_t pipe_id, uint32_t queue_id, uint32_t vmid) @@ -725,6 +791,22 @@ static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ return r; } +static int mes_v11_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type, + uint32_t me_id, uint32_t pipe_id, + uint32_t queue_id, uint32_t vmid, + bool is_kq) +{ + struct amdgpu_device *adev = mes->adev; + + if (queue_type == AMDGPU_RING_TYPE_GFX) + return mes_v11_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, + queue_id, is_kq); + else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) + return mes_v11_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id); + else + return -EOPNOTSUPP; +} + static int mes_v11_0_map_legacy_queue(struct amdgpu_mes *mes, struct mes_map_legacy_queue_input *input) { @@ -1087,7 +1169,8 @@ static int mes_v11_0_reset_hw_queue(struct amdgpu_mes *mes, if (r) return mes_v11_0_reset_pipe_mmio(mes, input->queue_type, input->me_id, input->pipe_id, - input->queue_id, input->vmid); + input->queue_id, input->vmid, + input->is_kq); return 0; } |
