summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Zhang <Jesse.Zhang@amd.com>2026-04-14 16:58:52 +0800
committerAlex Deucher <alexander.deucher@amd.com>2026-06-17 15:51:34 -0400
commit2c476a67c6452ffe56ee14c0789c0acdb044427b (patch)
treee429e1c67210afab92c2dc32850e270a0d014de1
parent5adb005e26321a23566dba746359ed5816f9f2e5 (diff)
drm/amdgpu/gfx12: Refactor compute pipe reset and add HQD cleanup
Refactor gfx_v12_0_reset_compute_pipe() to accept explicit me, pipe, and queue parameters instead of deriving them from the ring structure. This enables the function to be used in generic pipe reset flows. Introduce gfx_v12_0_clear_hqds_on_mec_pipe() to properly clear CP_HQD_ACTIVE and CP_HQD_DEQUEUE_REQUEST for all queues on a given MEC pipe while the pipe reset is asserted, ensuring the HQDs are torn down correctly before deasserting reset. Switch the KCQ reset path to use the common MEC pipe reset helper amdgpu_gfx_mec_pipe_reset_run(), which coordinates the reset sequence including KFD suspend/resume to avoid conflicts with user mode queues. v2: just update the sequence (Alex) v3: directly clear ACTIVE and DEQUEUE_REQUEST (Shaoyun Liu) Suggested-by: Manu Rastogi <manu.rastogi@amd.com> Suggested-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Jesse Zhang <jesse.zhang@amd.com> Reviewed-by: Prike Liang <Prike.Liang@amd.com> Reviewed-by: Shaoyun Liu <shaoyun.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c112
1 files changed, 66 insertions, 46 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index be3231c574b7..8d68d40808f4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -5338,10 +5338,29 @@ static int gfx_v12_0_reset_kgq(struct amdgpu_ring *ring,
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}
-static int gfx_v12_0_reset_compute_pipe(struct amdgpu_ring *ring)
+/*
+ * With MEC pipe reset asserted, clear CP_HQD_ACTIVE / CP_HQD_DEQUEUE_REQUEST for
+ * every queue on (me, pipe). HQDs must be torn down while pipe reset stays
+ * asserted; only then clear the pipe reset bit.
+ * Caller must hold adev->srbm_mutex.
+ */
+static void gfx_v12_0_clear_hqds_on_mec_pipe(struct amdgpu_device *adev, u32 me,
+ u32 pipe)
{
- struct amdgpu_device *adev = ring->adev;
- uint32_t reset_pipe = 0, clean_pipe = 0;
+ unsigned int q;
+
+ for (q = 0; q < adev->gfx.mec.num_queue_per_pipe; q++) {
+ soc24_grbm_select(adev, me, pipe, q, 0);
+ /* Start from a clean HQD dequeue state before forcing HQD inactive. */
+ WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, 0);
+ WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0);
+ }
+}
+
+static int gfx_v12_0_reset_compute_pipe(struct amdgpu_device *adev,
+ u32 me, u32 pipe, u32 queue)
+{
+ uint32_t reset_val, clean_val;
int r = 0;
if (!gfx_v12_pipe_reset_support(adev))
@@ -5349,75 +5368,76 @@ static int gfx_v12_0_reset_compute_pipe(struct amdgpu_ring *ring)
gfx_v12_0_set_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
- soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
-
- reset_pipe = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
- clean_pipe = reset_pipe;
-
+ soc24_grbm_select(adev, me, pipe, queue, 0);
if (adev->gfx.rs64_enable) {
- switch (ring->pipe) {
+ reset_val = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
+ clean_val = reset_val;
+
+ switch (pipe) {
case 0:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE0_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE0_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE0_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE0_RESET, 0);
break;
case 1:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE1_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE1_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE1_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE1_RESET, 0);
break;
case 2:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE2_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE2_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE2_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE2_RESET, 0);
break;
case 3:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE3_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
- MEC_PIPE3_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE3_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
+ MEC_PIPE3_RESET, 0);
break;
default:
break;
}
- WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_pipe);
- WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_pipe);
+ WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_val);
+ gfx_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe);
+ WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_val);
r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) -
RS64_FW_UC_START_ADDR_LO;
} else {
- switch (ring->pipe) {
+ reset_val = RREG32_SOC15(GC, 0, regCP_MEC_CNTL);
+ clean_val = reset_val;
+
+ switch (pipe) {
case 0:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
- MEC_ME1_PIPE0_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
- MEC_ME1_PIPE0_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
+ MEC_ME1_PIPE0_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
+ MEC_ME1_PIPE0_RESET, 0);
break;
case 1:
- reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
- MEC_ME1_PIPE1_RESET, 1);
- clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
- MEC_ME1_PIPE1_RESET, 0);
+ reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
+ MEC_ME1_PIPE1_RESET, 1);
+ clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
+ MEC_ME1_PIPE1_RESET, 0);
break;
default:
- break;
+ break;
}
- WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_pipe);
- WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_pipe);
- /* Doesn't find the F32 MEC instruction pointer register, and suppose
- * the driver won't run into the F32 mode.
- */
+
+ WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_val);
+ gfx_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe);
+ WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_val);
}
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
gfx_v12_0_unset_safe_mode(adev, 0);
- dev_info(adev->dev, "The ring %s pipe resets: %s\n", ring->name,
- r == 0 ? "successfully" : "failed");
- /* Need the ring test to verify the pipe reset result.*/
+ dev_dbg(adev->dev, "MEC pipe me%u pipe%u queue%u resets to MEC FW start PC: %s\n",
+ me, pipe, queue, r == 0 ? "successfully" : "failed");
return 0;
}
@@ -5434,7 +5454,7 @@ static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring,
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
if (r) {
dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r);
- r = gfx_v12_0_reset_compute_pipe(ring);
+ r = gfx_v12_0_reset_compute_pipe(adev, ring->me, ring->pipe, ring->queue);
if (r)
return r;
}