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_v11_0.c | 137 ++++++++++++++++++++-----
 1 file 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 c81e4b8616d0..be3941ae337a 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -410,19 +410,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,
@@ -448,21 +514,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);
 }
 
 /*
@@ -614,20 +694,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)
@@ -722,6 +788,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)
 {
@@ -1084,7 +1166,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;
        }
 
-- 
2.49.0

Reply via email to