drm/radeon/kms: add cayman asic reset support
authorAlex Deucher <alexdeucher@gmail.com>
Thu, 3 Mar 2011 01:07:33 +0000 (20:07 -0500)
committerDave Airlie <airlied@redhat.com>
Thu, 3 Mar 2011 01:51:21 +0000 (11:51 +1000)
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h

index ffdc8332b76e0dfb7a57b7b0c95cf823b996c478..0a3d6fc13c2db0eee8de2434de500adfeceaa9ff 100644 (file)
@@ -804,7 +804,7 @@ void evergreen_bandwidth_update(struct radeon_device *rdev)
        }
 }
 
-static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
+int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
 {
        unsigned i;
        u32 tmp;
@@ -957,7 +957,7 @@ void evergreen_agp_enable(struct radeon_device *rdev)
        WREG32(VM_CONTEXT1_CNTL, 0);
 }
 
-static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
+void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
        save->vga_control[0] = RREG32(D1VGA_CONTROL);
        save->vga_control[1] = RREG32(D2VGA_CONTROL);
@@ -1011,7 +1011,7 @@ static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_sa
        WREG32(EVERGREEN_D6VGA_CONTROL, 0);
 }
 
-static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
+void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
        WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
               upper_32_bits(rdev->mc.vram_start));
index 0fecad24000785d0f06d34ddbd8ce454f2b3eb22..3a3fdf5b5dd25d400fd92f0909b3ca3eb8f26d62 100644 (file)
 #include "ni_reg.h"
 #include "cayman_blit_shaders.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);
+extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
+
 #define EVERGREEN_PFP_UCODE_SIZE 1120
 #define EVERGREEN_PM4_UCODE_SIZE 1376
 #define EVERGREEN_RLC_UCODE_SIZE 768
@@ -1249,3 +1253,96 @@ int cayman_cp_resume(struct radeon_device *rdev)
        return 0;
 }
 
+bool cayman_gpu_is_lockup(struct radeon_device *rdev)
+{
+       u32 srbm_status;
+       u32 grbm_status;
+       u32 grbm_status_se0, grbm_status_se1;
+       struct r100_gpu_lockup *lockup = &rdev->config.cayman.lockup;
+       int r;
+
+       srbm_status = RREG32(SRBM_STATUS);
+       grbm_status = RREG32(GRBM_STATUS);
+       grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+       grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+       if (!(grbm_status & GUI_ACTIVE)) {
+               r100_gpu_lockup_update(lockup, &rdev->cp);
+               return false;
+       }
+       /* force CP activities */
+       r = radeon_ring_lock(rdev, 2);
+       if (!r) {
+               /* PACKET2 NOP */
+               radeon_ring_write(rdev, 0x80000000);
+               radeon_ring_write(rdev, 0x80000000);
+               radeon_ring_unlock_commit(rdev);
+       }
+       /* XXX deal with CP0,1,2 */
+       rdev->cp.rptr = RREG32(CP_RB0_RPTR);
+       return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp);
+}
+
+static int cayman_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 softreset \n");
+       dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+               RREG32(GRBM_STATUS));
+       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, "  SRBM_STATUS=0x%08X\n",
+               RREG32(SRBM_STATUS));
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_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);
+
+       /* reset all the gfx blocks */
+       grbm_reset = (SOFT_RESET_CP |
+                     SOFT_RESET_CB |
+                     SOFT_RESET_DB |
+                     SOFT_RESET_GDS |
+                     SOFT_RESET_PA |
+                     SOFT_RESET_SC |
+                     SOFT_RESET_SPI |
+                     SOFT_RESET_SH |
+                     SOFT_RESET_SX |
+                     SOFT_RESET_TC |
+                     SOFT_RESET_TA |
+                     SOFT_RESET_VGT |
+                     SOFT_RESET_IA);
+
+       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_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, "  SRBM_STATUS=0x%08X\n",
+               RREG32(SRBM_STATUS));
+       evergreen_mc_resume(rdev, &save);
+       return 0;
+}
+
+int cayman_asic_reset(struct radeon_device *rdev)
+{
+       return cayman_gpu_soft_reset(rdev);
+}
+
index 57062f14acc93d1e9699712b49c0d24af58a584c..0f9a08b53fbd4b9b4e4e90e8c63aad02a554f229 100644 (file)
@@ -42,6 +42,7 @@
 #define CAYMAN_MAX_TCC_MASK          0xFF
 
 #define DMIF_ADDR_CONFIG                               0xBD4
+#define        SRBM_STATUS                                     0x0E50
 
 #define VM_CONTEXT0_REQUEST_RESPONSE                   0x1470
 #define                REQUEST_TYPE(x)                                 (((x) & 0xf) << 0)