Blob Blame History Raw
From f920d1bb9c4e77efb08c41d70b6d442f46fd8902 Mon Sep 17 00:00:00 2001
From: changzhu <Changfeng.Zhu@amd.com>
Date: Tue, 19 Nov 2019 11:13:29 +0800
Subject: drm/amdgpu: invalidate mmhub semaphore workaround in gmc9/gmc10
Git-commit: f920d1bb9c4e77efb08c41d70b6d442f46fd8902
Patch-mainline: v5.5-rc1
References: bsc#1152472

It may lose gpuvm invalidate acknowldege state across power-gating off
cycle. To avoid this issue in gmc9/gmc10 invalidation, add semaphore acquire
before invalidation and semaphore release after invalidation.

After adding semaphore acquire before invalidation, the semaphore
register become read-only if another process try to acquire semaphore.
Then it will not be able to release this semaphore. Then it may cause
deadlock problem. If this deadlock problem happens, it needs a semaphore
firmware fix.

Signed-off-by: changzhu <Changfeng.Zhu@amd.com>
Acked-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h |    2 +
 drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c |   57 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c  |   58 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/soc15.h     |    4 +-
 4 files changed, 119 insertions(+), 2 deletions(-)

--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -103,6 +103,8 @@ struct amdgpu_bo_list_entry;
 #define AMDGPU_MAX_VMHUBS			2
 #define AMDGPU_GFXHUB				0
 #define AMDGPU_MMHUB				1
+#define AMDGPU_MMHUB_0                          1
+#define AMDGPU_MMHUB_1                          2
 
 /* hardcode that limit for now */
 #define AMDGPU_VA_RESERVED_SIZE			(1ULL << 20)
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -204,6 +204,29 @@ static void gmc_v10_0_flush_vm_hub(struc
 	const unsigned eng = 17;
 	unsigned int i;
 
+	spin_lock(&adev->gmc.invalidate_lock);
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (vmhub == AMDGPU_MMHUB_0 ||
+	    vmhub == AMDGPU_MMHUB_1) {
+		for (i = 0; i < adev->usec_timeout; i++) {
+			/* a read return value of 1 means semaphore acuqire */
+			tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
+			if (tmp & 0x1)
+				break;
+			udelay(1);
+		}
+
+		if (i >= adev->usec_timeout)
+			DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
+	}
+
 	WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
 
 	/* Wait for ACK with a delay.*/
@@ -216,6 +239,17 @@ static void gmc_v10_0_flush_vm_hub(struc
 		udelay(1);
 	}
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (vmhub == AMDGPU_MMHUB_0 ||
+	    vmhub == AMDGPU_MMHUB_1)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
+
+	spin_unlock(&adev->gmc.invalidate_lock);
+
 	if (i < adev->usec_timeout)
 		return;
 
@@ -293,6 +327,20 @@ static uint64_t gmc_v10_0_emit_flush_gpu
 	uint32_t req = gmc_v10_0_get_invalidate_req(vmid, 0);
 	unsigned eng = ring->vm_inv_eng;
 
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/* a read return value of 1 means semaphore acuqire */
+		amdgpu_ring_emit_reg_wait(ring,
+					  hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
+
 	amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
 			      lower_32_bits(pd_addr));
 
@@ -305,6 +353,15 @@ static uint64_t gmc_v10_0_emit_flush_gpu
 	amdgpu_ring_emit_reg_wait(ring, hub->vm_inv_eng0_ack + eng,
 				  1 << vmid, 1 << vmid);
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
+
 	return pd_addr;
 }
 
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -420,6 +420,7 @@ static void gmc_v9_0_flush_gpu_tlb(struc
 	unsigned i, j;
 
 	for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
+		uint32_t vmhub = i;
 		struct amdgpu_vmhub *hub = &adev->vmhub[i];
 		u32 tmp = gmc_v9_0_get_invalidate_req(vmid, flush_type);
 
@@ -438,6 +439,29 @@ static void gmc_v9_0_flush_gpu_tlb(struc
 		}
 
 		spin_lock(&adev->gmc.invalidate_lock);
+
+		/*
+		 * It may lose gpuvm invalidate acknowldege state across power-gating
+		 * off cycle, add semaphore acquire before invalidation and semaphore
+		 * release after invalidation to avoid entering power gated state
+		 * to WA the Issue
+		 */
+
+		/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+		if (vmhub == AMDGPU_MMHUB_0 ||
+		    vmhub == AMDGPU_MMHUB_1) {
+			for (j = 0; j < adev->usec_timeout; j++) {
+				/* a read return value of 1 means semaphore acuqire */
+				tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
+				if (tmp & 0x1)
+					break;
+				udelay(1);
+			}
+
+			if (j >= adev->usec_timeout)
+				DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
+		}
+
 		WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
 		for (j = 0; j < adev->usec_timeout; j++) {
 			tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + eng);
@@ -445,7 +469,18 @@ static void gmc_v9_0_flush_gpu_tlb(struc
 				break;
 			udelay(1);
 		}
+
+		/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+		if (vmhub == AMDGPU_MMHUB_0 ||
+		    vmhub == AMDGPU_MMHUB_1)
+			/*
+			 * add semaphore release after invalidation,
+			 * write with 0 means semaphore release
+			 */
+			WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
+
 		spin_unlock(&adev->gmc.invalidate_lock);
+
 		if (j < adev->usec_timeout)
 			continue;
 
@@ -461,6 +496,20 @@ static uint64_t gmc_v9_0_emit_flush_gpu_
 	uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0);
 	unsigned eng = ring->vm_inv_eng;
 
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/* a read return value of 1 means semaphore acuqire */
+		amdgpu_ring_emit_reg_wait(ring,
+					  hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
+
 	amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
 			      lower_32_bits(pd_addr));
 
@@ -471,6 +520,15 @@ static uint64_t gmc_v9_0_emit_flush_gpu_
 					    hub->vm_inv_eng0_ack + eng,
 					    req, 1 << vmid);
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
+
 	return pd_addr;
 }
 
--- a/drivers/gpu/drm/amd/amdgpu/soc15.h
+++ b/drivers/gpu/drm/amd/amdgpu/soc15.h
@@ -28,8 +28,8 @@
 #include "nbio_v7_0.h"
 #include "nbio_v7_4.h"
 
-#define SOC15_FLUSH_GPU_TLB_NUM_WREG		4
-#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT	1
+#define SOC15_FLUSH_GPU_TLB_NUM_WREG		6
+#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT	3
 
 extern const struct amd_ip_funcs soc15_common_ip_funcs;