wake_up_all(&ring->irq_queue);
        if (i915_enable_hangcheck) {
-               dev_priv->gpu_error.hangcheck_count = 0;
                mod_timer(&dev_priv->gpu_error.hangcheck_timer,
                          round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
        }
 
 /**
  * This is called when the chip hasn't reported back with completed
- * batchbuffers in a long time. The first time this is called we simply record
- * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
- * again, we assume the chip is wedged and try to fix it.
+ * batchbuffers in a long time. We keep track per ring seqno progress and
+ * if there are no progress, hangcheck score for that ring is increased.
+ * Further, acthd is inspected to see if the ring is stuck. On stuck case
+ * we kick the ring. If we see no progress on three subsequent calls
+ * we assume chip is wedged and try to fix it by resetting the chip.
  */
 void i915_hangcheck_elapsed(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
-       bool err = false, idle;
        int i;
-       u32 seqno[I915_NUM_RINGS];
-       bool work_done;
+       int busy_count = 0, rings_hung = 0;
+       bool stuck[I915_NUM_RINGS];
 
        if (!i915_enable_hangcheck)
                return;
 
-       idle = true;
        for_each_ring(ring, dev_priv, i) {
-               seqno[i] = ring->get_seqno(ring, false);
-               idle &= i915_hangcheck_ring_idle(ring, seqno[i], &err);
-       }
+               u32 seqno, acthd;
+               bool idle, err = false;
+
+               seqno = ring->get_seqno(ring, false);
+               acthd = intel_ring_get_active_head(ring);
+               idle = i915_hangcheck_ring_idle(ring, seqno, &err);
+               stuck[i] = ring->hangcheck.acthd == acthd;
+
+               if (idle) {
+                       if (err)
+                               ring->hangcheck.score += 2;
+                       else
+                               ring->hangcheck.score = 0;
+               } else {
+                       busy_count++;
 
-       /* If all work is done then ACTHD clearly hasn't advanced. */
-       if (idle) {
-               if (err) {
-                       if (i915_hangcheck_hung(dev))
-                               return;
+                       if (ring->hangcheck.seqno == seqno) {
+                               ring->hangcheck.score++;
 
-                       goto repeat;
+                               /* Kick ring if stuck*/
+                               if (stuck[i])
+                                       i915_hangcheck_ring_hung(ring);
+                       } else {
+                               ring->hangcheck.score = 0;
+                       }
                }
 
-               dev_priv->gpu_error.hangcheck_count = 0;
-               return;
+               ring->hangcheck.seqno = seqno;
+               ring->hangcheck.acthd = acthd;
        }
 
-       work_done = false;
        for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.seqno != seqno[i]) {
-                       work_done = true;
-                       ring->hangcheck.seqno = seqno[i];
+               if (ring->hangcheck.score > 2) {
+                       rings_hung++;
+                       DRM_ERROR("%s: %s on %s 0x%x\n", ring->name,
+                                 stuck[i] ? "stuck" : "no progress",
+                                 stuck[i] ? "addr" : "seqno",
+                                 stuck[i] ? ring->hangcheck.acthd & HEAD_ADDR :
+                                 ring->hangcheck.seqno);
                }
        }
 
-       if (!work_done) {
-               if (i915_hangcheck_hung(dev))
-                       return;
-       } else {
-               dev_priv->gpu_error.hangcheck_count = 0;
-       }
+       if (rings_hung)
+               return i915_handle_error(dev, true);
 
-repeat:
-       /* Reset timer case chip hangs without another request being added */
-       mod_timer(&dev_priv->gpu_error.hangcheck_timer,
-                 round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+       if (busy_count)
+               /* Reset timer case chip hangs without another request
+                * being added */
+               mod_timer(&dev_priv->gpu_error.hangcheck_timer,
+                         round_jiffies_up(jiffies +
+                                          DRM_I915_HANGCHECK_JIFFIES));
 }
 
 /* drm_dma.h hooks