diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1037-drm-amdgpu-fix-IH-overflow-on-Vega10-v2.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.19.8/1037-drm-amdgpu-fix-IH-overflow-on-Vega10-v2.patch | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1037-drm-amdgpu-fix-IH-overflow-on-Vega10-v2.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1037-drm-amdgpu-fix-IH-overflow-on-Vega10-v2.patch new file mode 100644 index 00000000..51f6ea51 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1037-drm-amdgpu-fix-IH-overflow-on-Vega10-v2.patch @@ -0,0 +1,83 @@ +From 49fafcd45bef899d0c9811e7e9d3499061f09abb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> +Date: Fri, 14 Dec 2018 15:31:24 +0100 +Subject: [PATCH 1037/2940] drm/amdgpu: fix IH overflow on Vega10 v2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When an ring buffer overflow happens the appropriate bit is set in the WPTR +register which is also written back to memory. But clearing the bit in the +WPTR doesn't trigger another memory writeback. + +So what can happen is that we end up processing the buffer overflow over and +over again because the bit is never cleared. Resulting in a random system +lockup because of an infinite loop in an interrupt handler. + +This is 100% reproducible on Vega10, but it's most likely an issue we have +in the driver over all generations all the way back to radeon. + +v2: rebase + +Signed-off-by: Christian König <christian.koenig@amd.com> +Reviewed-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/amdgpu/vega10_ih.c | 41 ++++++++++++++++---------- + 1 file changed, 25 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +index 3e9ebb0de94d..562701939d3e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +@@ -192,22 +192,31 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, + + wptr = le32_to_cpu(*ih->wptr_cpu); + +- if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) { +- wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0); +- +- /* When a ring buffer overflow happen start parsing interrupt +- * from the last not overwritten vector (wptr + 32). Hopefully +- * this should allow us to catchup. +- */ +- tmp = (wptr + 32) & ih->ptr_mask; +- dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", +- wptr, ih->rptr, tmp); +- ih->rptr = tmp; +- +- tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL)); +- tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); +- WREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp); +- } ++ if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) ++ goto out; ++ ++ /* Double check that the overflow wasn't already cleared. */ ++ wptr = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR)); ++ if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) ++ goto out; ++ ++ wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0); ++ ++ /* When a ring buffer overflow happen start parsing interrupt ++ * from the last not overwritten vector (wptr + 32). Hopefully ++ * this should allow us to catchup. ++ */ ++ tmp = (wptr + 32) & ih->ptr_mask; ++ dev_warn(adev->dev, "IH ring buffer overflow " ++ "(0x%08X, 0x%08X, 0x%08X)\n", ++ wptr, ih->rptr, tmp); ++ ih->rptr = tmp; ++ ++ tmp = RREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL)); ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); ++ WREG32_NO_KIQ(SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL), tmp); ++ ++out: + return (wptr & ih->ptr_mask); + } + +-- +2.17.1 + |