Revert "drm/i915/ringbuffer: Ignore failure to setup the ring on Sandybridge"
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index 8acdd6d857d368304e9c9cc9637d798582bc7a16..4a0664ea49b9e310dcceacf782e5ba51a536ed75 100644 (file)
@@ -298,7 +298,7 @@ static void notify_ring(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 seqno = ring->get_seqno(ring);
-       ring->irq_gem_seqno = seqno;
+       ring->irq_seqno = seqno;
        trace_i915_gem_request_complete(dev, seqno);
        wake_up_all(&ring->irq_queue);
        dev_priv->hangcheck_count = 0;
@@ -592,13 +592,27 @@ static void i915_capture_error_state(struct drm_device *dev)
        error->pipeastat = I915_READ(PIPEASTAT);
        error->pipebstat = I915_READ(PIPEBSTAT);
        error->instpm = I915_READ(INSTPM);
-       if (INTEL_INFO(dev)->gen < 4) {
-               error->ipeir = I915_READ(IPEIR);
-               error->ipehr = I915_READ(IPEHR);
-               error->instdone = I915_READ(INSTDONE);
-               error->acthd = I915_READ(ACTHD);
-               error->bbaddr = 0;
-       } else {
+       error->error = 0;
+       if (INTEL_INFO(dev)->gen >= 6) {
+               error->error = I915_READ(ERROR_GEN6);
+
+               error->bcs_acthd = I915_READ(BCS_ACTHD);
+               error->bcs_ipehr = I915_READ(BCS_IPEHR);
+               error->bcs_ipeir = I915_READ(BCS_IPEIR);
+               error->bcs_instdone = I915_READ(BCS_INSTDONE);
+               error->bcs_seqno = 0;
+               if (dev_priv->blt_ring.get_seqno)
+                       error->bcs_seqno = dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring);
+
+               error->vcs_acthd = I915_READ(VCS_ACTHD);
+               error->vcs_ipehr = I915_READ(VCS_IPEHR);
+               error->vcs_ipeir = I915_READ(VCS_IPEIR);
+               error->vcs_instdone = I915_READ(VCS_INSTDONE);
+               error->vcs_seqno = 0;
+               if (dev_priv->bsd_ring.get_seqno)
+                       error->vcs_seqno = dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring);
+       }
+       if (INTEL_INFO(dev)->gen >= 4) {
                error->ipeir = I915_READ(IPEIR_I965);
                error->ipehr = I915_READ(IPEHR_I965);
                error->instdone = I915_READ(INSTDONE_I965);
@@ -606,6 +620,12 @@ static void i915_capture_error_state(struct drm_device *dev)
                error->instdone1 = I915_READ(INSTDONE1);
                error->acthd = I915_READ(ACTHD_I965);
                error->bbaddr = I915_READ64(BB_ADDR);
+       } else {
+               error->ipeir = I915_READ(IPEIR);
+               error->ipehr = I915_READ(IPEHR);
+               error->instdone = I915_READ(INSTDONE);
+               error->acthd = I915_READ(ACTHD);
+               error->bbaddr = 0;
        }
 
        bbaddr = i915_ringbuffer_last_batch(dev);
@@ -708,6 +728,7 @@ static void i915_capture_error_state(struct drm_device *dev)
                        error->active_bo[i].tiling = obj_priv->tiling_mode;
                        error->active_bo[i].dirty = obj_priv->dirty;
                        error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
+                       error->active_bo[i].ring = obj_priv->ring->id;
 
                        if (++i == count)
                                break;
@@ -870,7 +891,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-static void i915_handle_error(struct drm_device *dev, bool wedged)
+void i915_handle_error(struct drm_device *dev, bool wedged)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -1307,12 +1328,29 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        return -EINVAL;
 }
 
-static struct drm_i915_gem_request *
-i915_get_tail_request(struct drm_device *dev)
+static u32
+ring_last_seqno(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return list_entry(dev_priv->render_ring.request_list.prev,
-                       struct drm_i915_gem_request, list);
+       return list_entry(ring->request_list.prev,
+                         struct drm_i915_gem_request, list)->seqno;
+}
+
+static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+{
+       if (list_empty(&ring->request_list) ||
+           i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
+               /* Issue a wake-up to catch stuck h/w. */
+               if (ring->waiting_seqno && waitqueue_active(&ring->irq_queue)) {
+                       DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
+                                 ring->name,
+                                 ring->waiting_seqno,
+                                 ring->get_seqno(ring));
+                       wake_up_all(&ring->irq_queue);
+                       *err = true;
+               }
+               return true;
+       }
+       return false;
 }
 
 /**
@@ -1326,6 +1364,17 @@ void i915_hangcheck_elapsed(unsigned long data)
        struct drm_device *dev = (struct drm_device *)data;
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t acthd, instdone, instdone1;
+       bool err = false;
+
+       /* If all work is done then ACTHD clearly hasn't advanced. */
+       if (i915_hangcheck_ring_idle(&dev_priv->render_ring, &err) &&
+           i915_hangcheck_ring_idle(&dev_priv->bsd_ring, &err) &&
+           i915_hangcheck_ring_idle(&dev_priv->blt_ring, &err)) {
+               dev_priv->hangcheck_count = 0;
+               if (err)
+                       goto repeat;
+               return;
+       }
 
        if (INTEL_INFO(dev)->gen < 4) {
                acthd = I915_READ(ACTHD);
@@ -1337,38 +1386,6 @@ void i915_hangcheck_elapsed(unsigned long data)
                instdone1 = I915_READ(INSTDONE1);
        }
 
-       /* If all work is done then ACTHD clearly hasn't advanced. */
-       if (list_empty(&dev_priv->render_ring.request_list) ||
-               i915_seqno_passed(dev_priv->render_ring.get_seqno(&dev_priv->render_ring),
-                                 i915_get_tail_request(dev)->seqno)) {
-               bool missed_wakeup = false;
-
-               dev_priv->hangcheck_count = 0;
-
-               /* Issue a wake-up to catch stuck h/w. */
-               if (dev_priv->render_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->render_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (dev_priv->bsd_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (dev_priv->blt_ring.waiting_gem_seqno &&
-                   waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
-                       wake_up_all(&dev_priv->blt_ring.irq_queue);
-                       missed_wakeup = true;
-               }
-
-               if (missed_wakeup)
-                       DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n");
-               return;
-       }
-
        if (dev_priv->last_acthd == acthd &&
            dev_priv->last_instdone == instdone &&
            dev_priv->last_instdone1 == instdone1) {
@@ -1385,7 +1402,7 @@ void i915_hangcheck_elapsed(unsigned long data)
                                if (tmp & RING_WAIT) {
                                        I915_WRITE(PRB0_CTL, tmp);
                                        POSTING_READ(PRB0_CTL);
-                                       goto out;
+                                       goto repeat;
                                }
                        }
 
@@ -1400,7 +1417,7 @@ void i915_hangcheck_elapsed(unsigned long data)
                dev_priv->last_instdone1 = instdone1;
        }
 
-out:
+repeat:
        /* Reset timer case chip hangs without another request being added */
        mod_timer(&dev_priv->hangcheck_timer,
                  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
This page took 0.061762 seconds and 5 git commands to generate.