summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2013-04-09 20:43:41 +0400
committerAlex Deucher <alexander.deucher@amd.com>2013-06-26 01:50:25 +0400
commit6f2043ce15f0de02749ab228c2d11169b580a304 (patch)
treed066854b0b474730bbd02b6df6f4df5116a96e59 /drivers/gpu
parent8cc1a5328b7406063812e3341e8f02718b54e3bc (diff)
downloadlinux-6f2043ce15f0de02749ab228c2d11169b580a304.tar.xz
drm/radeon: Add support for CIK GPU reset (v2)
v2: split soft reset into compute and gfx. Still need to make reset more fine grained, but this should be a start. Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/cik.c197
-rw-r--r--drivers/gpu/drm/radeon/cikd.h80
2 files changed, 277 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 28f68dc96fdb..e448ae2230e6 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -27,9 +27,13 @@
#include <linux/module.h>
#include "drmP.h"
#include "radeon.h"
+#include "radeon_asic.h"
#include "cikd.h"
#include "atom.h"
+extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+
/*
* Core functions
*/
@@ -1190,3 +1194,196 @@ static void cik_gpu_init(struct radeon_device *rdev)
udelay(50);
}
+/**
+ * cik_gpu_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ u32 srbm_status, srbm_status2;
+ u32 grbm_status, grbm_status2;
+ u32 grbm_status_se0, grbm_status_se1, grbm_status_se2, grbm_status_se3;
+
+ srbm_status = RREG32(SRBM_STATUS);
+ srbm_status2 = RREG32(SRBM_STATUS2);
+ grbm_status = RREG32(GRBM_STATUS);
+ grbm_status2 = RREG32(GRBM_STATUS2);
+ grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+ grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+ grbm_status_se2 = RREG32(GRBM_STATUS_SE2);
+ grbm_status_se3 = RREG32(GRBM_STATUS_SE3);
+ if (!(grbm_status & GUI_ACTIVE)) {
+ radeon_ring_lockup_update(ring);
+ return false;
+ }
+ /* force CP activities */
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
+}
+
+/**
+ * cik_gfx_gpu_soft_reset - soft reset the 3D engine and CPG
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the GFX engine and CPG blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_gfx_gpu_soft_reset(struct radeon_device *rdev)
+{
+ struct evergreen_mc_save save;
+ u32 grbm_reset = 0;
+
+ if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+ return 0;
+
+ dev_info(rdev->dev, "GPU GFX softreset \n");
+ dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(GRBM_STATUS));
+ dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(GRBM_STATUS2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(GRBM_STATUS_SE0));
+ dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(GRBM_STATUS_SE1));
+ dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(GRBM_STATUS_SE2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(GRBM_STATUS_SE3));
+ dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(SRBM_STATUS));
+ dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(SRBM_STATUS2));
+ evergreen_mc_stop(rdev, &save);
+ if (radeon_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ /* Disable CP parsing/prefetching */
+ WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+ /* reset all the gfx block and all CPG blocks */
+ grbm_reset = SOFT_RESET_CPG | SOFT_RESET_GFX;
+
+ dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+ WREG32(GRBM_SOFT_RESET, grbm_reset);
+ (void)RREG32(GRBM_SOFT_RESET);
+ udelay(50);
+ WREG32(GRBM_SOFT_RESET, 0);
+ (void)RREG32(GRBM_SOFT_RESET);
+ /* Wait a little for things to settle down */
+ udelay(50);
+ dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(GRBM_STATUS));
+ dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(GRBM_STATUS2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(GRBM_STATUS_SE0));
+ dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(GRBM_STATUS_SE1));
+ dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(GRBM_STATUS_SE2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(GRBM_STATUS_SE3));
+ dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(SRBM_STATUS));
+ dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(SRBM_STATUS2));
+ evergreen_mc_resume(rdev, &save);
+ return 0;
+}
+
+/**
+ * cik_compute_gpu_soft_reset - soft reset CPC
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: deal with reseting RLC and CPF
+ * Returns 0 for success.
+ */
+static int cik_compute_gpu_soft_reset(struct radeon_device *rdev)
+{
+ struct evergreen_mc_save save;
+ u32 grbm_reset = 0;
+
+ dev_info(rdev->dev, "GPU compute softreset \n");
+ dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(GRBM_STATUS));
+ dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(GRBM_STATUS2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(GRBM_STATUS_SE0));
+ dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(GRBM_STATUS_SE1));
+ dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(GRBM_STATUS_SE2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(GRBM_STATUS_SE3));
+ dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(SRBM_STATUS));
+ dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(SRBM_STATUS2));
+ evergreen_mc_stop(rdev, &save);
+ if (radeon_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ /* Disable CP parsing/prefetching */
+ WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+ /* reset all the CPC blocks */
+ grbm_reset = SOFT_RESET_CPG;
+
+ dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+ WREG32(GRBM_SOFT_RESET, grbm_reset);
+ (void)RREG32(GRBM_SOFT_RESET);
+ udelay(50);
+ WREG32(GRBM_SOFT_RESET, 0);
+ (void)RREG32(GRBM_SOFT_RESET);
+ /* Wait a little for things to settle down */
+ udelay(50);
+ dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(GRBM_STATUS));
+ dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(GRBM_STATUS2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(GRBM_STATUS_SE0));
+ dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(GRBM_STATUS_SE1));
+ dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(GRBM_STATUS_SE2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(GRBM_STATUS_SE3));
+ dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(SRBM_STATUS));
+ dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(SRBM_STATUS2));
+ evergreen_mc_resume(rdev, &save);
+ return 0;
+}
+
+/**
+ * cik_asic_reset - soft reset compute and gfx
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Soft reset the CPC blocks (CIK).
+ * XXX: make this more fine grained and only reset
+ * what is necessary.
+ * Returns 0 for success.
+ */
+int cik_asic_reset(struct radeon_device *rdev)
+{
+ int r;
+
+ r = cik_compute_gpu_soft_reset(rdev);
+ if (r)
+ dev_info(rdev->dev, "Compute reset failed!\n");
+
+ return cik_gfx_gpu_soft_reset(rdev);
+}
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index e51fb41a859a..41b2316958ae 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -30,6 +30,9 @@
#define DMIF_ADDR_CALC 0xC00
+#define SRBM_STATUS2 0xE4C
+#define SRBM_STATUS 0xE50
+
#define MC_SHARED_CHMAP 0x2004
#define NOOFCHAN_SHIFT 12
#define NOOFCHAN_MASK 0x0000f000
@@ -65,6 +68,83 @@
#define GRBM_CNTL 0x8000
#define GRBM_READ_TIMEOUT(x) ((x) << 0)
+#define GRBM_STATUS2 0x8008
+#define ME0PIPE1_CMDFIFO_AVAIL_MASK 0x0000000F
+#define ME0PIPE1_CF_RQ_PENDING (1 << 4)
+#define ME0PIPE1_PF_RQ_PENDING (1 << 5)
+#define ME1PIPE0_RQ_PENDING (1 << 6)
+#define ME1PIPE1_RQ_PENDING (1 << 7)
+#define ME1PIPE2_RQ_PENDING (1 << 8)
+#define ME1PIPE3_RQ_PENDING (1 << 9)
+#define ME2PIPE0_RQ_PENDING (1 << 10)
+#define ME2PIPE1_RQ_PENDING (1 << 11)
+#define ME2PIPE2_RQ_PENDING (1 << 12)
+#define ME2PIPE3_RQ_PENDING (1 << 13)
+#define RLC_RQ_PENDING (1 << 14)
+#define RLC_BUSY (1 << 24)
+#define TC_BUSY (1 << 25)
+#define CPF_BUSY (1 << 28)
+#define CPC_BUSY (1 << 29)
+#define CPG_BUSY (1 << 30)
+
+#define GRBM_STATUS 0x8010
+#define ME0PIPE0_CMDFIFO_AVAIL_MASK 0x0000000F
+#define SRBM_RQ_PENDING (1 << 5)
+#define ME0PIPE0_CF_RQ_PENDING (1 << 7)
+#define ME0PIPE0_PF_RQ_PENDING (1 << 8)
+#define GDS_DMA_RQ_PENDING (1 << 9)
+#define DB_CLEAN (1 << 12)
+#define CB_CLEAN (1 << 13)
+#define TA_BUSY (1 << 14)
+#define GDS_BUSY (1 << 15)
+#define WD_BUSY_NO_DMA (1 << 16)
+#define VGT_BUSY (1 << 17)
+#define IA_BUSY_NO_DMA (1 << 18)
+#define IA_BUSY (1 << 19)
+#define SX_BUSY (1 << 20)
+#define WD_BUSY (1 << 21)
+#define SPI_BUSY (1 << 22)
+#define BCI_BUSY (1 << 23)
+#define SC_BUSY (1 << 24)
+#define PA_BUSY (1 << 25)
+#define DB_BUSY (1 << 26)
+#define CP_COHERENCY_BUSY (1 << 28)
+#define CP_BUSY (1 << 29)
+#define CB_BUSY (1 << 30)
+#define GUI_ACTIVE (1 << 31)
+#define GRBM_STATUS_SE0 0x8014
+#define GRBM_STATUS_SE1 0x8018
+#define GRBM_STATUS_SE2 0x8038
+#define GRBM_STATUS_SE3 0x803C
+#define SE_DB_CLEAN (1 << 1)
+#define SE_CB_CLEAN (1 << 2)
+#define SE_BCI_BUSY (1 << 22)
+#define SE_VGT_BUSY (1 << 23)
+#define SE_PA_BUSY (1 << 24)
+#define SE_TA_BUSY (1 << 25)
+#define SE_SX_BUSY (1 << 26)
+#define SE_SPI_BUSY (1 << 27)
+#define SE_SC_BUSY (1 << 29)
+#define SE_DB_BUSY (1 << 30)
+#define SE_CB_BUSY (1 << 31)
+
+#define GRBM_SOFT_RESET 0x8020
+#define SOFT_RESET_CP (1 << 0) /* All CP blocks */
+#define SOFT_RESET_RLC (1 << 2) /* RLC */
+#define SOFT_RESET_GFX (1 << 16) /* GFX */
+#define SOFT_RESET_CPF (1 << 17) /* CP fetcher shared by gfx and compute */
+#define SOFT_RESET_CPC (1 << 18) /* CP Compute (MEC1/2) */
+#define SOFT_RESET_CPG (1 << 19) /* CP GFX (PFP, ME, CE) */
+
+#define CP_MEC_CNTL 0x8234
+#define MEC_ME2_HALT (1 << 28)
+#define MEC_ME1_HALT (1 << 30)
+
+#define CP_ME_CNTL 0x86D8
+#define CP_CE_HALT (1 << 24)
+#define CP_PFP_HALT (1 << 26)
+#define CP_ME_HALT (1 << 28)
+
#define CP_MEQ_THRESHOLDS 0x8764
#define MEQ1_START(x) ((x) << 0)
#define MEQ2_START(x) ((x) << 8)