Merge branch 'drm-radeon-lockup' into drm-core-next
[pandora-kernel.git] / drivers / gpu / drm / radeon / r300.c
index bd75f99..bb005bf 100644 (file)
@@ -27,8 +27,9 @@
  */
 #include <linux/seq_file.h>
 #include <linux/slab.h>
-#include "drmP.h"
-#include "drm.h"
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include <drm/drm_crtc_helper.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "radeon_asic.h"
@@ -151,6 +152,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev)
        u32 tmp;
        int r;
 
+       WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
        tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
        tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
        WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN);
@@ -323,7 +328,6 @@ void r300_gpu_init(struct radeon_device *rdev)
 {
        uint32_t gb_tile_config, tmp;
 
-       r100_hdp_reset(rdev);
        /* FIXME: rv380 one pipes ? */
        if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) ||
            (rdev->family == CHIP_R350)) {
@@ -376,89 +380,93 @@ void r300_gpu_init(struct radeon_device *rdev)
                 rdev->num_gb_pipes, rdev->num_z_pipes);
 }
 
-int r300_ga_reset(struct radeon_device *rdev)
+bool r300_gpu_is_lockup(struct radeon_device *rdev)
 {
-       uint32_t tmp;
-       bool reinit_cp;
-       int i;
+       u32 rbbm_status;
+       int r;
 
-       reinit_cp = rdev->cp.ready;
-       rdev->cp.ready = false;
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               WREG32(RADEON_CP_CSQ_MODE, 0);
-               WREG32(RADEON_CP_CSQ_CNTL, 0);
-               WREG32(RADEON_RBBM_SOFT_RESET, 0x32005);
-               (void)RREG32(RADEON_RBBM_SOFT_RESET);
-               udelay(200);
-               WREG32(RADEON_RBBM_SOFT_RESET, 0);
-               /* Wait to prevent race in RBBM_STATUS */
-               mdelay(1);
-               tmp = RREG32(RADEON_RBBM_STATUS);
-               if (tmp & ((1 << 20) | (1 << 26))) {
-                       DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp);
-                       /* GA still busy soft reset it */
-                       WREG32(0x429C, 0x200);
-                       WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
-                       WREG32(R300_RE_SCISSORS_TL, 0);
-                       WREG32(R300_RE_SCISSORS_BR, 0);
-                       WREG32(0x24AC, 0);
-               }
-               /* Wait to prevent race in RBBM_STATUS */
-               mdelay(1);
-               tmp = RREG32(RADEON_RBBM_STATUS);
-               if (!(tmp & ((1 << 20) | (1 << 26)))) {
-                       break;
-               }
+       rbbm_status = RREG32(R_000E40_RBBM_STATUS);
+       if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
+               r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+               return false;
        }
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RADEON_RBBM_STATUS);
-               if (!(tmp & ((1 << 20) | (1 << 26)))) {
-                       DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
-                                tmp);
-                       if (reinit_cp) {
-                               return r100_cp_init(rdev, rdev->cp.ring_size);
-                       }
-                       return 0;
-               }
-               DRM_UDELAY(1);
+       /* 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);
        }
-       tmp = RREG32(RADEON_RBBM_STATUS);
-       DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
-       return -1;
+       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
 }
 
-int r300_gpu_reset(struct radeon_device *rdev)
+int r300_asic_reset(struct radeon_device *rdev)
 {
-       uint32_t status;
-
-       /* reset order likely matter */
-       status = RREG32(RADEON_RBBM_STATUS);
-       /* reset HDP */
-       r100_hdp_reset(rdev);
-       /* reset rb2d */
-       if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
-               r100_rb2d_reset(rdev);
-       }
-       /* reset GA */
-       if (status & ((1 << 20) | (1 << 26))) {
-               r300_ga_reset(rdev);
-       }
-       /* reset CP */
-       status = RREG32(RADEON_RBBM_STATUS);
-       if (status & (1 << 16)) {
-               r100_cp_reset(rdev);
+       struct r100_mc_save save;
+       u32 status, tmp;
+
+       r100_mc_stop(rdev, &save);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       if (!G_000E40_GUI_ACTIVE(status)) {
+               return 0;
        }
+       status = RREG32(R_000E40_RBBM_STATUS);
+       dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+       /* stop CP */
+       WREG32(RADEON_CP_CSQ_CNTL, 0);
+       tmp = RREG32(RADEON_CP_RB_CNTL);
+       WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+       WREG32(RADEON_CP_RB_RPTR_WR, 0);
+       WREG32(RADEON_CP_RB_WPTR, 0);
+       WREG32(RADEON_CP_RB_CNTL, tmp);
+       /* save PCI state */
+       pci_save_state(rdev->pdev);
+       /* disable bus mastering */
+       r100_bm_disable(rdev);
+       WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
+                                       S_0000F0_SOFT_RESET_GA(1));
+       RREG32(R_0000F0_RBBM_SOFT_RESET);
+       mdelay(500);
+       WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+       mdelay(1);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+       /* resetting the CP seems to be problematic sometimes it end up
+        * hard locking the computer, but it's necessary for successfull
+        * reset more test & playing is needed on R3XX/R4XX to find a
+        * reliable (if any solution)
+        */
+       WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
+       RREG32(R_0000F0_RBBM_SOFT_RESET);
+       mdelay(500);
+       WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+       mdelay(1);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+       /* reset MC */
+       WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1));
+       RREG32(R_0000F0_RBBM_SOFT_RESET);
+       mdelay(500);
+       WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
+       mdelay(1);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
+       /* restore PCI & busmastering */
+       pci_restore_state(rdev->pdev);
+       r100_enable_bm(rdev);
        /* Check if GPU is idle */
-       status = RREG32(RADEON_RBBM_STATUS);
-       if (status & RADEON_RBBM_ACTIVE) {
-               DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+       if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
+               dev_err(rdev->dev, "failed to reset GPU\n");
+               rdev->gpu_lockup = true;
                return -1;
        }
-       DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+       r100_mc_resume(rdev, &save);
+       dev_info(rdev->dev, "GPU reset succeed\n");
        return 0;
 }
 
-
 /*
  * r300,r350,rv350,rv380 VRAM info
  */
@@ -1317,7 +1325,7 @@ int r300_resume(struct radeon_device *rdev)
        /* Resume clock before doing reset */
        r300_clock_startup(rdev);
        /* Reset gpu before posting otherwise ATOM will enter infinite loop */
-       if (radeon_gpu_reset(rdev)) {
+       if (radeon_asic_reset(rdev)) {
                dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
                        RREG32(R_000E40_RBBM_STATUS),
                        RREG32(R_0007C0_CP_STAT));
@@ -1388,7 +1396,7 @@ int r300_init(struct radeon_device *rdev)
                        return r;
        }
        /* Reset gpu before posting otherwise ATOM will enter infinite loop */
-       if (radeon_gpu_reset(rdev)) {
+       if (radeon_asic_reset(rdev)) {
                dev_warn(rdev->dev,
                        "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
                        RREG32(R_000E40_RBBM_STATUS),