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 <[email protected]> --- drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 111 +++++++++++++++++++++---- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index ee72afdb0a1d..41d6799177d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -425,11 +425,73 @@ static bool mes_v12_0_pipe_reset_support(struct amdgpu_device *adev) return false; } +/* Use MES callbacks directly while holding the MES lock. */ +static int mes_v12_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); + soc24_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); + } + soc24_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_v12_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; + bool has_kq = adev->gfx.num_gfx_rings >= 1; + uint32_t reset_pipe, clean_pipe; + int i; if (!mes_v12_0_pipe_reset_support(adev)) return -EOPNOTSUPP; @@ -438,6 +500,9 @@ static int mes_v12_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev, mutex_lock(&adev->srbm_mutex); soc24_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, @@ -463,22 +528,35 @@ static int mes_v12_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); + soc24_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. */ + soc24_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); + } + soc24_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: %s\n", - r == 0 ? "successfully" : "failed"); - /* Sometimes the ME start pc counter can't cache correctly, so the - * PC check only as a reference and pipe reset result rely on the - * later ring test. - */ - 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_v12_0_restore_gfx_kernel_queue(adev, me, pipe, queue, is_kq); } /* @@ -679,12 +757,14 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ static int mes_v12_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) + 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_v12_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id); + return mes_v12_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id, + is_kq); else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) return mes_v12_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id); else @@ -1106,7 +1186,8 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes, if (r) return mes_v12_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; } -- 2.49.0
