drm/amdgpu: support gfx soft reset for gfx v11
authorLikun Gao <Likun.Gao@amd.com>
Tue, 14 Jun 2022 09:36:57 +0000 (17:36 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 13 Jul 2022 15:25:16 +0000 (11:25 -0400)
Support GFX soft reset for gfx v11.

V3: use ib test check soft reset.
V4: squash in unused variable fix (Alex)

Signed-off-by: Likun Gao <Likun.Gao@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c

index 942d41a65f2f0df453b508602a94d1377120a632..4e26681178d8244b6e6e22c83e38a348a979270e 100644 (file)
@@ -126,6 +126,8 @@ static int gfx_v11_0_wait_for_rlc_autoload_complete(struct amdgpu_device *adev);
 static void gfx_v11_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
                                           uint16_t pasid, uint32_t flush_type,
                                           bool all_hub, uint8_t dst_sel);
+static void gfx_v11_0_set_safe_mode(struct amdgpu_device *adev);
+static void gfx_v11_0_unset_safe_mode(struct amdgpu_device *adev);
 
 static void gfx11_kiq_set_resources(struct amdgpu_ring *kiq_ring, uint64_t queue_mask)
 {
@@ -4743,63 +4745,143 @@ static int gfx_v11_0_soft_reset(void *handle)
 {
        u32 grbm_soft_reset = 0;
        u32 tmp;
+       int i, j, k;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       /* GRBM_STATUS */
-       tmp = RREG32_SOC15(GC, 0, regGRBM_STATUS);
-       if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK |
-                  GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK |
-                  GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__DB_BUSY_MASK |
-                  GRBM_STATUS__CB_BUSY_MASK | GRBM_STATUS__GDS_BUSY_MASK |
-                  GRBM_STATUS__SPI_BUSY_MASK | GRBM_STATUS__GE_BUSY_NO_DMA_MASK)) {
-               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
-                                               GRBM_SOFT_RESET, SOFT_RESET_CP,
-                                               1);
-               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
-                                               GRBM_SOFT_RESET, SOFT_RESET_GFX,
-                                               1);
-       }
-
-       if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) {
-               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
-                                               GRBM_SOFT_RESET, SOFT_RESET_CP,
-                                               1);
-       }
-
-       /* GRBM_STATUS2 */
-       tmp = RREG32_SOC15(GC, 0, regGRBM_STATUS2);
-       if (REG_GET_FIELD(tmp, GRBM_STATUS2, RLC_BUSY))
-               grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
-                                               GRBM_SOFT_RESET,
-                                               SOFT_RESET_RLC,
-                                               1);
-
-       if (grbm_soft_reset) {
-               /* stop the rlc */
-               gfx_v11_0_rlc_stop(adev);
-
-               /* Disable GFX parsing/prefetching */
-               gfx_v11_0_cp_gfx_enable(adev, false);
+       tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CMP_BUSY_INT_ENABLE, 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_BUSY_INT_ENABLE, 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_EMPTY_INT_ENABLE, 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, GFX_IDLE_INT_ENABLE, 0);
+       WREG32_SOC15(GC, 0, regCP_INT_CNTL, tmp);
 
-               /* Disable MEC parsing/prefetching */
-               gfx_v11_0_cp_compute_enable(adev, false);
+       gfx_v11_0_set_safe_mode(adev);
 
-               tmp = RREG32_SOC15(GC, 0, regGRBM_SOFT_RESET);
-               tmp |= grbm_soft_reset;
-               dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
-               WREG32_SOC15(GC, 0, regGRBM_SOFT_RESET, tmp);
-               tmp = RREG32_SOC15(GC, 0, regGRBM_SOFT_RESET);
+       for (i = 0; i < adev->gfx.mec.num_mec; ++i) {
+               for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) {
+                       for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; k++) {
+                               tmp = RREG32_SOC15(GC, 0, regGRBM_GFX_CNTL);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, MEID, i);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, QUEUEID, j);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, PIPEID, k);
+                               WREG32_SOC15(GC, 0, regGRBM_GFX_CNTL, tmp);
+
+                               WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0x2);
+                               WREG32_SOC15(GC, 0, regSPI_COMPUTE_QUEUE_RESET, 0x1);
+                       }
+               }
+       }
+       for (i = 0; i < adev->gfx.me.num_me; ++i) {
+               for (j = 0; j < adev->gfx.me.num_queue_per_pipe; j++) {
+                       for (k = 0; k < adev->gfx.me.num_pipe_per_me; k++) {
+                               tmp = RREG32_SOC15(GC, 0, regGRBM_GFX_CNTL);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, MEID, i);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, QUEUEID, j);
+                               tmp = REG_SET_FIELD(tmp, GRBM_GFX_CNTL, PIPEID, k);
+                               WREG32_SOC15(GC, 0, regGRBM_GFX_CNTL, tmp);
+
+                               WREG32_SOC15(GC, 0, regCP_GFX_HQD_DEQUEUE_REQUEST, 0x1);
+                       }
+               }
+       }
 
-               udelay(50);
+       WREG32_SOC15(GC, 0, regCP_VMID_RESET, 0xfffffffe);
 
-               tmp &= ~grbm_soft_reset;
-               WREG32_SOC15(GC, 0, regGRBM_SOFT_RESET, tmp);
-               tmp = RREG32_SOC15(GC, 0, regGRBM_SOFT_RESET);
+       // Read CP_VMID_RESET register three times.
+       // to get sufficient time for GFX_HQD_ACTIVE reach 0
+       RREG32_SOC15(GC, 0, regCP_VMID_RESET);
+       RREG32_SOC15(GC, 0, regCP_VMID_RESET);
+       RREG32_SOC15(GC, 0, regCP_VMID_RESET);
 
-               /* Wait a little for things to settle down */
-               udelay(50);
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (!RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) &&
+                   !RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE))
+                       break;
+               udelay(1);
        }
-       return 0;
+       if (i >= adev->usec_timeout) {
+               printk("Failed to wait all pipes clean\n");
+               return -EINVAL;
+       }
+
+       /**********  trigger soft reset  ***********/
+       grbm_soft_reset = RREG32_SOC15(GC, 0, regGRBM_SOFT_RESET);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CP, 1);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_GFX, 1);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPF, 1);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPC, 1);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPG, 1);
+       WREG32_SOC15(GC, 0, regGRBM_SOFT_RESET, grbm_soft_reset);
+       /**********  exit soft reset  ***********/
+       grbm_soft_reset = RREG32_SOC15(GC, 0, regGRBM_SOFT_RESET);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CP, 0);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_GFX, 0);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPF, 0);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPC, 0);
+       grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
+                                       SOFT_RESET_CPG, 0);
+       WREG32_SOC15(GC, 0, regGRBM_SOFT_RESET, grbm_soft_reset);
+
+       tmp = RREG32_SOC15(GC, 0, regCP_SOFT_RESET_CNTL);
+       tmp = REG_SET_FIELD(tmp, CP_SOFT_RESET_CNTL, CMP_HQD_REG_RESET, 0x1);
+       WREG32_SOC15(GC, 0, regCP_SOFT_RESET_CNTL, tmp);
+
+       WREG32_SOC15(GC, 0, regCP_ME_CNTL, 0x0);
+       WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, 0x0);
+
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (!RREG32_SOC15(GC, 0, regCP_VMID_RESET))
+                       break;
+               udelay(1);
+       }
+       if (i >= adev->usec_timeout) {
+               printk("Failed to wait CP_VMID_RESET to 0\n");
+               return -EINVAL;
+       }
+
+       tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CMP_BUSY_INT_ENABLE, 1);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_BUSY_INT_ENABLE, 1);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_EMPTY_INT_ENABLE, 1);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, GFX_IDLE_INT_ENABLE, 1);
+       WREG32_SOC15(GC, 0, regCP_INT_CNTL, tmp);
+
+       gfx_v11_0_unset_safe_mode(adev);
+
+       return gfx_v11_0_cp_resume(adev);
+}
+
+static bool gfx_v11_0_check_soft_reset(void *handle)
+{
+       int i, r;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct amdgpu_ring *ring;
+       long tmo = msecs_to_jiffies(1000);
+
+       for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
+               ring = &adev->gfx.gfx_ring[i];
+               r = amdgpu_ring_test_ib(ring, tmo);
+               if (r)
+                       return true;
+       }
+
+       for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+               ring = &adev->gfx.compute_ring[i];
+               r = amdgpu_ring_test_ib(ring, tmo);
+               if (r)
+                       return true;
+       }
+
+       return false;
 }
 
 static uint64_t gfx_v11_0_get_gpu_clock_counter(struct amdgpu_device *adev)
@@ -6132,6 +6214,7 @@ static const struct amd_ip_funcs gfx_v11_0_ip_funcs = {
        .is_idle = gfx_v11_0_is_idle,
        .wait_for_idle = gfx_v11_0_wait_for_idle,
        .soft_reset = gfx_v11_0_soft_reset,
+       .check_soft_reset = gfx_v11_0_check_soft_reset,
        .set_clockgating_state = gfx_v11_0_set_clockgating_state,
        .set_powergating_state = gfx_v11_0_set_powergating_state,
        .get_clockgating_state = gfx_v11_0_get_clockgating_state,