summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v11_0.c137
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;
}