Merge branch 'drm-radeon-lockup' into drm-core-next
authorDave Airlie <airlied@redhat.com>
Tue, 20 Apr 2010 03:15:05 +0000 (13:15 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 20 Apr 2010 03:15:05 +0000 (13:15 +1000)
* drm-radeon-lockup:
  drm/radeon/kms: simplify & improve GPU reset V2
  drm/radeon/kms: rename gpu_reset to asic_reset
  drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4

Conflicts:
drivers/gpu/drm/radeon/r300.c

1  2 
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c

@@@ -23,7 -23,6 +23,7 @@@
   */
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "radeon.h"
  #include "radeon_asic.h"
@@@ -487,7 -486,13 +487,13 @@@ int evergreen_mc_init(struct radeon_dev
        return 0;
  }
  
- int evergreen_gpu_reset(struct radeon_device *rdev)
+ bool evergreen_gpu_is_lockup(struct radeon_device *rdev)
+ {
+       /* FIXME: implement for evergreen */
+       return false;
+ }
+ int evergreen_asic_reset(struct radeon_device *rdev)
  {
        /* FIXME: implement for evergreen */
        return 0;
@@@ -26,7 -26,6 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/seq_file.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "drm.h"
  #include "radeon_drm.h"
@@@ -663,26 -662,6 +663,6 @@@ int r100_cp_init(struct radeon_device *
        if (r100_debugfs_cp_init(rdev)) {
                DRM_ERROR("Failed to register debugfs file for CP !\n");
        }
-       /* Reset CP */
-       tmp = RREG32(RADEON_CP_CSQ_STAT);
-       if ((tmp & (1 << 31))) {
-               DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp);
-               WREG32(RADEON_CP_CSQ_MODE, 0);
-               WREG32(RADEON_CP_CSQ_CNTL, 0);
-               WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
-               tmp = RREG32(RADEON_RBBM_SOFT_RESET);
-               mdelay(2);
-               WREG32(RADEON_RBBM_SOFT_RESET, 0);
-               tmp = RREG32(RADEON_RBBM_SOFT_RESET);
-               mdelay(2);
-               tmp = RREG32(RADEON_CP_CSQ_STAT);
-               if ((tmp & (1 << 31))) {
-                       DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp);
-               }
-       } else {
-               DRM_INFO("radeon: cp idle (0x%08X)\n", tmp);
-       }
        if (!rdev->me_fw) {
                r = r100_cp_init_microcode(rdev);
                if (r) {
@@@ -787,39 -766,6 +767,6 @@@ void r100_cp_disable(struct radeon_devi
        }
  }
  
- int r100_cp_reset(struct radeon_device *rdev)
- {
-       uint32_t tmp;
-       bool reinit_cp;
-       int i;
-       reinit_cp = rdev->cp.ready;
-       rdev->cp.ready = false;
-       WREG32(RADEON_CP_CSQ_MODE, 0);
-       WREG32(RADEON_CP_CSQ_CNTL, 0);
-       WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
-       (void)RREG32(RADEON_RBBM_SOFT_RESET);
-       udelay(200);
-       WREG32(RADEON_RBBM_SOFT_RESET, 0);
-       /* Wait to prevent race in RBBM_STATUS */
-       mdelay(1);
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RADEON_RBBM_STATUS);
-               if (!(tmp & (1 << 16))) {
-                       DRM_INFO("CP 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);
-       }
-       tmp = RREG32(RADEON_RBBM_STATUS);
-       DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp);
-       return -1;
- }
  void r100_cp_commit(struct radeon_device *rdev)
  {
        WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
@@@ -1733,76 -1679,163 +1680,163 @@@ int r100_mc_wait_for_idle(struct radeon
        return -1;
  }
  
- void r100_gpu_init(struct radeon_device *rdev)
+ void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
  {
-       /* TODO: anythings to do here ? pipes ? */
-       r100_hdp_reset(rdev);
+       lockup->last_cp_rptr = cp->rptr;
+       lockup->last_jiffies = jiffies;
+ }
+ /**
+  * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information
+  * @rdev:     radeon device structure
+  * @lockup:   r100_gpu_lockup structure holding CP lockup tracking informations
+  * @cp:               radeon_cp structure holding CP information
+  *
+  * We don't need to initialize the lockup tracking information as we will either
+  * have CP rptr to a different value of jiffies wrap around which will force
+  * initialization of the lockup tracking informations.
+  *
+  * A possible false positivie is if we get call after while and last_cp_rptr ==
+  * the current CP rptr, even if it's unlikely it might happen. To avoid this
+  * if the elapsed time since last call is bigger than 2 second than we return
+  * false and update the tracking information. Due to this the caller must call
+  * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported
+  * the fencing code should be cautious about that.
+  *
+  * Caller should write to the ring to force CP to do something so we don't get
+  * false positive when CP is just gived nothing to do.
+  *
+  **/
+ bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
+ {
+       unsigned long cjiffies, elapsed;
+       cjiffies = jiffies;
+       if (!time_after(cjiffies, lockup->last_jiffies)) {
+               /* likely a wrap around */
+               lockup->last_cp_rptr = cp->rptr;
+               lockup->last_jiffies = jiffies;
+               return false;
+       }
+       if (cp->rptr != lockup->last_cp_rptr) {
+               /* CP is still working no lockup */
+               lockup->last_cp_rptr = cp->rptr;
+               lockup->last_jiffies = jiffies;
+               return false;
+       }
+       elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies);
+       if (elapsed >= 3000) {
+               /* very likely the improbable case where current
+                * rptr is equal to last recorded, a while ago, rptr
+                * this is more likely a false positive update tracking
+                * information which should force us to be recall at
+                * latter point
+                */
+               lockup->last_cp_rptr = cp->rptr;
+               lockup->last_jiffies = jiffies;
+               return false;
+       }
+       if (elapsed >= 1000) {
+               dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
+               return true;
+       }
+       /* give a chance to the GPU ... */
+       return false;
  }
  
void r100_hdp_reset(struct radeon_device *rdev)
bool r100_gpu_is_lockup(struct radeon_device *rdev)
  {
-       uint32_t tmp;
+       u32 rbbm_status;
+       int r;
  
-       tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
-       tmp |= (7 << 28);
-       WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
-       (void)RREG32(RADEON_HOST_PATH_CNTL);
-       udelay(200);
-       WREG32(RADEON_RBBM_SOFT_RESET, 0);
-       WREG32(RADEON_HOST_PATH_CNTL, tmp);
-       (void)RREG32(RADEON_HOST_PATH_CNTL);
+       rbbm_status = RREG32(R_000E40_RBBM_STATUS);
+       if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
+               r100_gpu_lockup_update(&rdev->config.r100.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);
+       }
+       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
  }
  
int r100_rb2d_reset(struct radeon_device *rdev)
void r100_bm_disable(struct radeon_device *rdev)
  {
-       uint32_t tmp;
-       int i;
+       u32 tmp;
  
-       WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2);
-       (void)RREG32(RADEON_RBBM_SOFT_RESET);
-       udelay(200);
-       WREG32(RADEON_RBBM_SOFT_RESET, 0);
-       /* Wait to prevent race in RBBM_STATUS */
+       /* disable bus mastering */
+       tmp = RREG32(R_000030_BUS_CNTL);
+       WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044);
+       mdelay(1);
+       WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042);
+       mdelay(1);
+       WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
+       tmp = RREG32(RADEON_BUS_CNTL);
+       mdelay(1);
+       pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+       pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
        mdelay(1);
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RADEON_RBBM_STATUS);
-               if (!(tmp & (1 << 26))) {
-                       DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n",
-                                tmp);
-                       return 0;
-               }
-               DRM_UDELAY(1);
-       }
-       tmp = RREG32(RADEON_RBBM_STATUS);
-       DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp);
-       return -1;
  }
  
- int r100_gpu_reset(struct radeon_device *rdev)
+ int r100_asic_reset(struct radeon_device *rdev)
  {
-       uint32_t status;
+       struct r100_mc_save save;
+       u32 status, tmp;
  
-       /* 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);
+       r100_mc_stop(rdev, &save);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       if (!G_000E40_GUI_ACTIVE(status)) {
+               return 0;
        }
-       /* TODO: reset 3D engine */
+       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_SE(1) |
+                                       S_0000F0_SOFT_RESET_RE(1) |
+                                       S_0000F0_SOFT_RESET_PP(1) |
+                                       S_0000F0_SOFT_RESET_RB(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 CP */
-       status = RREG32(RADEON_RBBM_STATUS);
-       if (status & (1 << 16)) {
-               r100_cp_reset(rdev);
-       }
+       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);
+       /* 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_SE_BUSY(status) || G_000E40_RE_BUSY(status) ||
+               G_000E40_TAM_BUSY(status) || G_000E40_PB_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;
  }
  
@@@ -2891,7 -2924,7 +2925,7 @@@ static int r100_cs_track_texture_check(
  {
        struct radeon_bo *robj;
        unsigned long size;
 -      unsigned u, i, w, h;
 +      unsigned u, i, w, h, d;
        int ret;
  
        for (u = 0; u < track->num_texture; u++) {
                        h = h / (1 << i);
                        if (track->textures[u].roundup_h)
                                h = roundup_pow_of_two(h);
 +                      if (track->textures[u].tex_coord_type == 1) {
 +                              d = (1 << track->textures[u].txdepth) / (1 << i);
 +                              if (!d)
 +                                      d = 1;
 +                      } else {
 +                              d = 1;
 +                      }
                        if (track->textures[u].compress_format) {
  
 -                              size += r100_track_compress_size(track->textures[u].compress_format, w, h);
 +                              size += r100_track_compress_size(track->textures[u].compress_format, w, h) * d;
                                /* compressed textures are block based */
                        } else
 -                              size += w * h;
 +                              size += w * h * d;
                }
                size *= track->textures[u].cpp;
  
                switch (track->textures[u].tex_coord_type) {
                case 0:
 -                      break;
                case 1:
 -                      size *= (1 << track->textures[u].txdepth);
                        break;
                case 2:
                        if (track->separate_cube) {
@@@ -3012,11 -3040,7 +3046,11 @@@ int r100_cs_track_check(struct radeon_d
                }
        }
        prim_walk = (track->vap_vf_cntl >> 4) & 0x3;
 -      nverts = (track->vap_vf_cntl >> 16) & 0xFFFF;
 +      if (track->vap_vf_cntl & (1 << 14)) {
 +              nverts = track->vap_alt_nverts;
 +      } else {
 +              nverts = (track->vap_vf_cntl >> 16) & 0xFFFF;
 +      }
        switch (prim_walk) {
        case 1:
                for (i = 0; i < track->num_arrays; i++) {
@@@ -3399,7 -3423,7 +3433,7 @@@ static int r100_startup(struct radeon_d
        /* Resume clock */
        r100_clock_startup(rdev);
        /* Initialize GPU configuration (# pipes, ...) */
      r100_gpu_init(rdev);
//    r100_gpu_init(rdev);
        /* Initialize GART (initialize after TTM so we can allocate
         * memory through TTM but finalize after TTM) */
        r100_enable_bm(rdev);
@@@ -3436,7 -3460,7 +3470,7 @@@ int r100_resume(struct radeon_device *r
        /* Resume clock before doing reset */
        r100_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));
@@@ -3505,7 -3529,7 +3539,7 @@@ int r100_init(struct radeon_device *rde
                        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),
   *          Jerome Glisse
   */
  #include <linux/seq_file.h>
- #include "drmP.h"
- #include "drm.h"
 +#include <linux/slab.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 -151,10 +152,10 @@@ void rv370_pcie_gart_disable(struct rad
        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 -327,6 +328,6 @@@ void r300_gpu_init(struct radeon_devic
  {
        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)) {
                 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
   */
@@@ -730,12 -737,6 +738,12 @@@ static int r300_packet0_check(struct ra
                /* VAP_VF_MAX_VTX_INDX */
                track->max_indx = idx_value & 0x00FFFFFFUL;
                break;
 +      case 0x2088:
 +              /* VAP_ALT_NUM_VERTICES - only valid on r500 */
 +              if (p->rdev->family < CHIP_RV515)
 +                      goto fail;
 +              track->vap_alt_nverts = idx_value & 0xFFFFFF;
 +              break;
        case 0x43E4:
                /* SC_SCISSOR1 */
                track->maxy = ((idx_value >> 13) & 0x1FFF) + 1;
                tmp = idx_value & ~(0x7 << 16);
                tmp |= tile_flags;
                ib[idx] = tmp;
 -
                i = (reg - 0x4E38) >> 2;
                track->cb[i].pitch = idx_value & 0x3FFE;
                switch (((idx_value >> 21) & 0xF)) {
                        break;
                /* fallthrough do not move */
        default:
 -              printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
 -                     reg, idx);
 -              return -EINVAL;
 +              goto fail;
        }
        return 0;
 +fail:
 +      printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
 +             reg, idx);
 +      return -EINVAL;
  }
  
  static int r300_packet3_check(struct radeon_cs_parser *p,
@@@ -1317,7 -1317,7 +1325,7 @@@ int r300_resume(struct radeon_device *r
        /* 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 -1388,7 +1396,7 @@@ int r300_init(struct radeon_device *rde
                        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),
@@@ -26,7 -26,6 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/seq_file.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "radeon_reg.h"
  #include "radeon.h"
@@@ -235,7 -234,7 +235,7 @@@ int r420_resume(struct radeon_device *r
        /* Resume clock before doing reset */
        r420_clock_resume(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));
@@@ -316,7 -315,7 +316,7 @@@ int r420_init(struct radeon_device *rde
                }
        }
        /* 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),
@@@ -25,7 -25,6 +25,7 @@@
   *          Alex Deucher
   *          Jerome Glisse
   */
 +#include <linux/slab.h>
  #include <linux/seq_file.h>
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
@@@ -750,7 -749,6 +750,6 @@@ int r600_gpu_soft_reset(struct radeon_d
                        S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) |
                        S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) |
                        S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
-       u32 srbm_reset = 0;
        u32 tmp;
  
        dev_info(rdev->dev, "GPU softreset \n");
                dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
        }
        /* Disable CP parsing/prefetching */
-       WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff));
+       WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
        /* Check if any of the rendering block is busy and reset it */
        if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
            (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
                        S_008020_SOFT_RESET_VGT(1);
                dev_info(rdev->dev, "  R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
                WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-               (void)RREG32(R_008020_GRBM_SOFT_RESET);
-               udelay(50);
+               RREG32(R_008020_GRBM_SOFT_RESET);
+               mdelay(15);
                WREG32(R_008020_GRBM_SOFT_RESET, 0);
-               (void)RREG32(R_008020_GRBM_SOFT_RESET);
        }
        /* Reset CP (we always reset CP) */
        tmp = S_008020_SOFT_RESET_CP(1);
        dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
        WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-       (void)RREG32(R_008020_GRBM_SOFT_RESET);
-       udelay(50);
+       RREG32(R_008020_GRBM_SOFT_RESET);
+       mdelay(15);
        WREG32(R_008020_GRBM_SOFT_RESET, 0);
-       (void)RREG32(R_008020_GRBM_SOFT_RESET);
-       /* Reset others GPU block if necessary */
-       if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-       if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_GRBM(1);
-       if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_IH(1);
-       if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_VMC(1);
-       if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-       if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_SEM(1);
-       if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_BIF(1);
-       dev_info(rdev->dev, "  R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
-       WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       udelay(50);
-       WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       udelay(50);
-       WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
        /* Wait a little for things to settle down */
-       udelay(50);
+       mdelay(1);
        dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
                RREG32(R_008010_GRBM_STATUS));
        dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
                RREG32(R_008014_GRBM_STATUS2));
        dev_info(rdev->dev, "  R_000E50_SRBM_STATUS=0x%08X\n",
                RREG32(R_000E50_SRBM_STATUS));
-       /* After reset we need to reinit the asic as GPU often endup in an
-        * incoherent state.
-        */
-       atom_asic_init(rdev->mode_info.atom_context);
        rv515_mc_resume(rdev, &save);
        return 0;
  }
  
- int r600_gpu_reset(struct radeon_device *rdev)
+ bool r600_gpu_is_lockup(struct radeon_device *rdev)
+ {
+       u32 srbm_status;
+       u32 grbm_status;
+       u32 grbm_status2;
+       int r;
+       srbm_status = RREG32(R_000E50_SRBM_STATUS);
+       grbm_status = RREG32(R_008010_GRBM_STATUS);
+       grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
+       if (!G_008010_GUI_ACTIVE(grbm_status)) {
+               r100_gpu_lockup_update(&rdev->config.r300.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);
+       }
+       rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+ }
+ int r600_asic_reset(struct radeon_device *rdev)
  {
        return r600_gpu_soft_reset(rdev);
  }
@@@ -26,7 -26,6 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/console.h>
 +#include <linux/slab.h>
  #include <drm/drmP.h>
  #include <drm/drm_crtc_helper.h>
  #include <drm/radeon_drm.h>
  #include "radeon.h"
  #include "atom.h"
  
 +static const char radeon_family_name[][16] = {
 +      "R100",
 +      "RV100",
 +      "RS100",
 +      "RV200",
 +      "RS200",
 +      "R200",
 +      "RV250",
 +      "RS300",
 +      "RV280",
 +      "R300",
 +      "R350",
 +      "RV350",
 +      "RV380",
 +      "R420",
 +      "R423",
 +      "RV410",
 +      "RS400",
 +      "RS480",
 +      "RS600",
 +      "RS690",
 +      "RS740",
 +      "RV515",
 +      "R520",
 +      "RV530",
 +      "RV560",
 +      "RV570",
 +      "R580",
 +      "R600",
 +      "RV610",
 +      "RV630",
 +      "RV670",
 +      "RV620",
 +      "RV635",
 +      "RS780",
 +      "RS880",
 +      "RV770",
 +      "RV730",
 +      "RV710",
 +      "RV740",
 +      "CEDAR",
 +      "REDWOOD",
 +      "JUNIPER",
 +      "CYPRESS",
 +      "HEMLOCK",
 +      "LAST",
 +};
 +
  /*
   * Clear GPU surface registers.
   */
@@@ -574,6 -525,7 +574,6 @@@ int radeon_device_init(struct radeon_de
        int r;
        int dma_bits;
  
 -      DRM_INFO("radeon: Initializing kernel modesetting.\n");
        rdev->shutdown = false;
        rdev->dev = &pdev->dev;
        rdev->ddev = ddev;
        rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
        rdev->gpu_lockup = false;
        rdev->accel_working = false;
 +
 +      DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n",
 +              radeon_family_name[rdev->family], pdev->vendor, pdev->device);
 +
        /* mutex initialization are all done here so we
         * can recall function without having locking issues */
        mutex_init(&rdev->cs_mutex);
                /* Acceleration not working on AGP card try again
                 * with fallback to PCI or PCIE GART
                 */
-               radeon_gpu_reset(rdev);
+               radeon_asic_reset(rdev);
                radeon_fini(rdev);
                radeon_agp_disable(rdev);
                r = radeon_init(rdev);
@@@ -691,6 -639,8 +691,8 @@@ void radeon_device_fini(struct radeon_d
  {
        DRM_INFO("radeon: finishing device.\n");
        rdev->shutdown = true;
+       /* evict vram memory */
+       radeon_bo_evict_vram(rdev);
        radeon_fini(rdev);
        destroy_workqueue(rdev->wq);
        vga_switcheroo_unregister_client(rdev->pdev);
@@@ -789,6 -739,26 +791,26 @@@ int radeon_resume_kms(struct drm_devic
        return 0;
  }
  
+ int radeon_gpu_reset(struct radeon_device *rdev)
+ {
+       int r;
+       radeon_save_bios_scratch_regs(rdev);
+       radeon_suspend(rdev);
+       r = radeon_asic_reset(rdev);
+       if (!r) {
+               dev_info(rdev->dev, "GPU reset succeed\n");
+               radeon_resume(rdev);
+               radeon_restore_bios_scratch_regs(rdev);
+               drm_helper_resume_force_mode(rdev->ddev);
+               return 0;
+       }
+       /* bad news, how to tell it to userspace ? */
+       dev_info(rdev->dev, "GPU reset failed\n");
+       return r;
+ }
  
  /*
   * Debugfs
@@@ -33,7 -33,6 +33,7 @@@
  #include <linux/wait.h>
  #include <linux/list.h>
  #include <linux/kref.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "drm.h"
  #include "radeon_reg.h"
@@@ -58,7 -57,6 +58,6 @@@ int radeon_fence_emit(struct radeon_dev
                radeon_fence_ring_emit(rdev, fence);
  
        fence->emited = true;
-       fence->timeout = jiffies + ((2000 * HZ) / 1000);
        list_del(&fence->list);
        list_add_tail(&fence->list, &rdev->fence_drv.emited);
        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
@@@ -71,15 -69,34 +70,34 @@@ static bool radeon_fence_poll_locked(st
        struct list_head *i, *n;
        uint32_t seq;
        bool wake = false;
+       unsigned long cjiffies;
  
-       if (rdev == NULL) {
-               return true;
-       }
-       if (rdev->shutdown) {
-               return true;
-       }
        seq = RREG32(rdev->fence_drv.scratch_reg);
-       rdev->fence_drv.last_seq = seq;
+       if (seq != rdev->fence_drv.last_seq) {
+               rdev->fence_drv.last_seq = seq;
+               rdev->fence_drv.last_jiffies = jiffies;
+               rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+       } else {
+               cjiffies = jiffies;
+               if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) {
+                       cjiffies -= rdev->fence_drv.last_jiffies;
+                       if (time_after(rdev->fence_drv.last_timeout, cjiffies)) {
+                               /* update the timeout */
+                               rdev->fence_drv.last_timeout -= cjiffies;
+                       } else {
+                               /* the 500ms timeout is elapsed we should test
+                                * for GPU lockup
+                                */
+                               rdev->fence_drv.last_timeout = 1;
+                       }
+               } else {
+                       /* wrap around update last jiffies, we will just wait
+                        * a little longer
+                        */
+                       rdev->fence_drv.last_jiffies = cjiffies;
+               }
+               return false;
+       }
        n = NULL;
        list_for_each(i, &rdev->fence_drv.emited) {
                fence = list_entry(i, struct radeon_fence, list);
@@@ -171,9 -188,8 +189,8 @@@ bool radeon_fence_signaled(struct radeo
  int radeon_fence_wait(struct radeon_fence *fence, bool intr)
  {
        struct radeon_device *rdev;
-       unsigned long cur_jiffies;
-       unsigned long timeout;
-       bool expired = false;
+       unsigned long irq_flags, timeout;
+       u32 seq;
        int r;
  
        if (fence == NULL) {
        if (radeon_fence_signaled(fence)) {
                return 0;
        }
+       timeout = rdev->fence_drv.last_timeout;
  retry:
-       cur_jiffies = jiffies;
-       timeout = HZ / 100;
-       if (time_after(fence->timeout, cur_jiffies)) {
-               timeout = fence->timeout - cur_jiffies;
-       }
+       /* save current sequence used to check for GPU lockup */
+       seq = rdev->fence_drv.last_seq;
        if (intr) {
                radeon_irq_kms_sw_irq_get(rdev);
                r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
                                radeon_fence_signaled(fence), timeout);
                radeon_irq_kms_sw_irq_put(rdev);
-               if (unlikely(r < 0))
+               if (unlikely(r < 0)) {
                        return r;
+               }
        } else {
                radeon_irq_kms_sw_irq_get(rdev);
                r = wait_event_timeout(rdev->fence_drv.queue,
                radeon_irq_kms_sw_irq_put(rdev);
        }
        if (unlikely(!radeon_fence_signaled(fence))) {
-               if (unlikely(r == 0)) {
-                       expired = true;
+               /* we were interrupted for some reason and fence isn't
+                * isn't signaled yet, resume wait
+                */
+               if (r) {
+                       timeout = r;
+                       goto retry;
                }
-               if (unlikely(expired)) {
-                       timeout = 1;
-                       if (time_after(cur_jiffies, fence->timeout)) {
-                               timeout = cur_jiffies - fence->timeout;
-                       }
-                       timeout = jiffies_to_msecs(timeout);
-                       if (timeout > 500) {
-                               DRM_ERROR("fence(%p:0x%08X) %lums timeout "
-                                         "going to reset GPU\n",
-                                         fence, fence->seq, timeout);
-                               radeon_gpu_reset(rdev);
-                               WREG32(rdev->fence_drv.scratch_reg, fence->seq);
-                       }
+               /* don't protect read access to rdev->fence_drv.last_seq
+                * if we experiencing a lockup the value doesn't change
+                */
+               if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
+                       /* good news we believe it's a lockup */
+                       WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
+                       /* FIXME: what should we do ? marking everyone
+                        * as signaled for now
+                        */
+                       rdev->gpu_lockup = true;
+                       WREG32(rdev->fence_drv.scratch_reg, fence->seq);
+                       r = radeon_gpu_reset(rdev);
+                       if (r)
+                               return r;
+                       rdev->gpu_lockup = false;
                }
+               timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+               write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+               rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
+               rdev->fence_drv.last_jiffies = jiffies;
+               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
                goto retry;
        }
-       if (unlikely(expired)) {
-               rdev->fence_drv.count_timeout++;
-               cur_jiffies = jiffies;
-               timeout = 1;
-               if (time_after(cur_jiffies, fence->timeout)) {
-                       timeout = cur_jiffies - fence->timeout;
-               }
-               timeout = jiffies_to_msecs(timeout);
-               DRM_ERROR("fence(%p:0x%08X) %lums timeout\n",
-                         fence, fence->seq, timeout);
-               DRM_ERROR("last signaled fence(0x%08X)\n",
-                         rdev->fence_drv.last_seq);
-       }
        return 0;
  }
  
@@@ -333,7 -344,6 +345,6 @@@ int radeon_fence_driver_init(struct rad
        INIT_LIST_HEAD(&rdev->fence_drv.created);
        INIT_LIST_HEAD(&rdev->fence_drv.emited);
        INIT_LIST_HEAD(&rdev->fence_drv.signaled);
-       rdev->fence_drv.count_timeout = 0;
        init_waitqueue_head(&rdev->fence_drv.queue);
        rdev->fence_drv.initialized = true;
        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
@@@ -26,7 -26,6 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/seq_file.h>
 +#include <linux/slab.h>
  #include <drm/drmP.h>
  #include "radeon.h"
  #include "radeon_asic.h"
@@@ -243,8 -242,6 +243,6 @@@ int rs400_mc_wait_for_idle(struct radeo
  
  void rs400_gpu_init(struct radeon_device *rdev)
  {
-       /* FIXME: HDP same place on rs400 ? */
-       r100_hdp_reset(rdev);
        /* FIXME: is this correct ? */
        r420_pipes_init(rdev);
        if (rs400_mc_wait_for_idle(rdev)) {
@@@ -433,7 -430,7 +431,7 @@@ int rs400_resume(struct radeon_device *
        /* setup MC before calling post tables */
        rs400_mc_program(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));
@@@ -497,7 -494,7 +495,7 @@@ int rs400_init(struct radeon_device *rd
                        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),
@@@ -147,6 -147,78 +147,78 @@@ void rs600_hpd_fini(struct radeon_devic
        }
  }
  
+ void rs600_bm_disable(struct radeon_device *rdev)
+ {
+       u32 tmp;
+       /* disable bus mastering */
+       pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+       pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
+       mdelay(1);
+ }
+ int rs600_asic_reset(struct radeon_device *rdev)
+ {
+       u32 status, tmp;
+       struct rv515_mc_save save;
+       /* Stops all mc clients */
+       rv515_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);
+       pci_save_state(rdev->pdev);
+       /* disable bus mastering */
+       rs600_bm_disable(rdev);
+       /* reset GA+VAP */
+       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);
+       /* reset CP */
+       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);
+       /* Check if GPU is idle */
+       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;
+       }
+       rv515_mc_resume(rdev, &save);
+       dev_info(rdev->dev, "GPU reset succeed\n");
+       return 0;
+ }
  /*
   * GART.
   */
@@@ -159,7 -231,7 +231,7 @@@ void rs600_gart_tlb_flush(struct radeon
        WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
  
        tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
 -      tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) & S_000100_INVALIDATE_L2_CACHE(1);
 +      tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) | S_000100_INVALIDATE_L2_CACHE(1);
        WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
  
        tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
@@@ -454,7 -526,6 +526,6 @@@ int rs600_mc_wait_for_idle(struct radeo
  
  void rs600_gpu_init(struct radeon_device *rdev)
  {
-       r100_hdp_reset(rdev);
        r420_pipes_init(rdev);
        /* Wait for mc idle */
        if (rs600_mc_wait_for_idle(rdev))
@@@ -601,7 -672,7 +672,7 @@@ int rs600_resume(struct radeon_device *
        /* Resume clock before doing reset */
        rv515_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));
@@@ -664,7 -735,7 +735,7 @@@ int rs600_init(struct radeon_device *rd
                return -EINVAL;
        }
        /* 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),
@@@ -26,7 -26,6 +26,7 @@@
   *          Jerome Glisse
   */
  #include <linux/seq_file.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "rv515d.h"
  #include "radeon.h"
@@@ -147,16 -146,11 +147,11 @@@ void rv515_gpu_init(struct radeon_devic
  {
        unsigned pipe_select_current, gb_pipe_select, tmp;
  
-       r100_hdp_reset(rdev);
-       r100_rb2d_reset(rdev);
        if (r100_gui_wait_for_idle(rdev)) {
                printk(KERN_WARNING "Failed to wait GUI idle while "
                       "reseting GPU. Bad things might happen.\n");
        }
        rv515_vga_render_disable(rdev);
        r420_pipes_init(rdev);
        gb_pipe_select = RREG32(0x402C);
        tmp = RREG32(0x170C);
        }
  }
  
- int rv515_ga_reset(struct radeon_device *rdev)
- {
-       uint32_t tmp;
-       bool reinit_cp;
-       int i;
-       reinit_cp = rdev->cp.ready;
-       rdev->cp.ready = false;
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               WREG32(CP_CSQ_MODE, 0);
-               WREG32(CP_CSQ_CNTL, 0);
-               WREG32(RBBM_SOFT_RESET, 0x32005);
-               (void)RREG32(RBBM_SOFT_RESET);
-               udelay(200);
-               WREG32(RBBM_SOFT_RESET, 0);
-               /* Wait to prevent race in RBBM_STATUS */
-               mdelay(1);
-               tmp = RREG32(RBBM_STATUS);
-               if (tmp & ((1 << 20) | (1 << 26))) {
-                       DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp);
-                       /* GA still busy soft reset it */
-                       WREG32(0x429C, 0x200);
-                       WREG32(VAP_PVS_STATE_FLUSH_REG, 0);
-                       WREG32(0x43E0, 0);
-                       WREG32(0x43E4, 0);
-                       WREG32(0x24AC, 0);
-               }
-               /* Wait to prevent race in RBBM_STATUS */
-               mdelay(1);
-               tmp = RREG32(RBBM_STATUS);
-               if (!(tmp & ((1 << 20) | (1 << 26)))) {
-                       break;
-               }
-       }
-       for (i = 0; i < rdev->usec_timeout; i++) {
-               tmp = RREG32(RBBM_STATUS);
-               if (!(tmp & ((1 << 20) | (1 << 26)))) {
-                       DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
-                                tmp);
-                       DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C));
-                       DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0));
-                       DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724));
-                       if (reinit_cp) {
-                               return r100_cp_init(rdev, rdev->cp.ring_size);
-                       }
-                       return 0;
-               }
-               DRM_UDELAY(1);
-       }
-       tmp = RREG32(RBBM_STATUS);
-       DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
-       return -1;
- }
- int rv515_gpu_reset(struct radeon_device *rdev)
- {
-       uint32_t status;
-       /* reset order likely matter */
-       status = RREG32(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))) {
-               rv515_ga_reset(rdev);
-       }
-       /* reset CP */
-       status = RREG32(RBBM_STATUS);
-       if (status & (1 << 16)) {
-               r100_cp_reset(rdev);
-       }
-       /* Check if GPU is idle */
-       status = RREG32(RBBM_STATUS);
-       if (status & (1 << 31)) {
-               DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
-               return -1;
-       }
-       DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
-       return 0;
- }
  static void rv515_vram_get_type(struct radeon_device *rdev)
  {
        uint32_t tmp;
@@@ -335,7 -244,7 +245,7 @@@ static int rv515_debugfs_ga_info(struc
  
        tmp = RREG32(0x2140);
        seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp);
-       radeon_gpu_reset(rdev);
+       radeon_asic_reset(rdev);
        tmp = RREG32(0x425C);
        seq_printf(m, "GA_IDLE 0x%08x\n", tmp);
        return 0;
@@@ -503,7 -412,7 +413,7 @@@ int rv515_resume(struct radeon_device *
        /* Resume clock before doing reset */
        rv515_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));
@@@ -573,7 -482,7 +483,7 @@@ int rv515_init(struct radeon_device *rd
                return -EINVAL;
        }
        /* 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),
@@@ -27,7 -27,6 +27,7 @@@
   */
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  #include "drmP.h"
  #include "radeon.h"
  #include "radeon_asic.h"
@@@ -917,12 -916,6 +917,6 @@@ int rv770_mc_init(struct radeon_device 
        return 0;
  }
  
- int rv770_gpu_reset(struct radeon_device *rdev)
- {
-       /* FIXME: implement any rv770 specific bits */
-       return r600_gpu_reset(rdev);
- }
  static int rv770_startup(struct radeon_device *rdev)
  {
        int r;