From 4e31b8fc7e8628d60b2332b691c6bd5ba4cfec83 Mon Sep 17 00:00:00 2001
From: Likun Gao <Likun.Gao@amd.com>
Date: Tue, 14 Jun 2022 17:36:57 +0800
Subject: drm/amdgpu: support gfx soft reset for gfx v11
Git-commit: a84e43b81e45b3da19e51e1e9426ba9e4d0fd1bc
Patch-mainline: v6.0-rc1
References: jsc#PED-1166 jsc#PED-1168 jsc#PED-1170 jsc#PED-1218 jsc#PED-1220 jsc#PED-1222 jsc#PED-1223 jsc#PED-1225 jsc#PED-2849

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>
Acked-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 181 ++++++++++++++++++-------
 1 file changed, 132 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index 942d41a65f2f..4e26681178d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -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,
-- 
2.38.1

