Revert "drm/i915/ringbuffer: Ignore failure to setup the ring on Sandybridge"
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index 1e30c250140b51e12573a69fa3173b8cb81cf3ef..4a0664ea49b9e310dcceacf782e5ba51a536ed75 100644 (file)
@@ -293,6 +293,19 @@ static void i915_handle_rps_change(struct drm_device *dev)
        return;
 }
 
+static void notify_ring(struct drm_device *dev,
+                       struct intel_ring_buffer *ring)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 seqno = ring->get_seqno(ring);
+       ring->irq_seqno = seqno;
+       trace_i915_gem_request_complete(dev, seqno);
+       wake_up_all(&ring->irq_queue);
+       dev_priv->hangcheck_count = 0;
+       mod_timer(&dev_priv->hangcheck_timer,
+                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+}
+
 static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -300,7 +313,6 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        u32 de_iir, gt_iir, de_ier, pch_iir;
        u32 hotplug_mask;
        struct drm_i915_master_private *master_priv;
-       struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
        u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
 
        if (IS_GEN6(dev))
@@ -332,17 +344,12 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                                READ_BREADCRUMB(dev_priv);
        }
 
-       if (gt_iir & GT_PIPE_NOTIFY) {
-               u32 seqno = render_ring->get_seqno(dev, render_ring);
-               render_ring->irq_gem_seqno = seqno;
-               trace_i915_gem_request_complete(dev, seqno);
-               wake_up_all(&dev_priv->render_ring.irq_queue);
-               dev_priv->hangcheck_count = 0;
-               mod_timer(&dev_priv->hangcheck_timer,
-                         jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
-       }
+       if (gt_iir & GT_PIPE_NOTIFY)
+               notify_ring(dev, &dev_priv->render_ring);
        if (gt_iir & bsd_usr_interrupt)
-               wake_up_all(&dev_priv->bsd_ring.irq_queue);
+               notify_ring(dev, &dev_priv->bsd_ring);
+       if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->blt_ring);
 
        if (de_iir & DE_GSE)
                intel_opregion_gse_intr(dev);
@@ -449,10 +456,9 @@ i915_error_object_create(struct drm_device *dev,
 
                local_irq_save(flags);
                s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-                                            reloc_offset,
-                                            KM_IRQ0);
+                                            reloc_offset);
                memcpy_fromio(d, s, PAGE_SIZE);
-               io_mapping_unmap_atomic(s, KM_IRQ0);
+               io_mapping_unmap_atomic(s);
                local_irq_restore(flags);
 
                dst->pages[page] = d;
@@ -580,19 +586,33 @@ static void i915_capture_error_state(struct drm_device *dev)
        DRM_DEBUG_DRIVER("generating error event\n");
 
        error->seqno =
-               dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
+               dev_priv->render_ring.get_seqno(&dev_priv->render_ring);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
        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);
@@ -600,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);
@@ -608,9 +634,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        batchbuffer[0] = NULL;
        batchbuffer[1] = NULL;
        count = 0;
-       list_for_each_entry(obj_priv,
-                       &dev_priv->render_ring.active_list, list) {
-
+       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                struct drm_gem_object *obj = &obj_priv->base;
 
                if (batchbuffer[0] == NULL &&
@@ -627,7 +651,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        }
        /* Scan the other lists for completeness for those bizarre errors. */
        if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-               list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        if (batchbuffer[0] == NULL &&
@@ -645,7 +669,7 @@ static void i915_capture_error_state(struct drm_device *dev)
                }
        }
        if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-               list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        if (batchbuffer[0] == NULL &&
@@ -686,8 +710,7 @@ static void i915_capture_error_state(struct drm_device *dev)
 
        if (error->active_bo) {
                int i = 0;
-               list_for_each_entry(obj_priv,
-                               &dev_priv->render_ring.active_list, list) {
+               list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
                        struct drm_gem_object *obj = &obj_priv->base;
 
                        error->active_bo[i].size = obj->size;
@@ -705,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;
@@ -867,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;
 
@@ -884,6 +908,8 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
                wake_up_all(&dev_priv->render_ring.irq_queue);
                if (HAS_BSD(dev))
                        wake_up_all(&dev_priv->bsd_ring.irq_queue);
+               if (HAS_BLT(dev))
+                       wake_up_all(&dev_priv->blt_ring.irq_queue);
        }
 
        queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -944,7 +970,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
        unsigned long irqflags;
        int irq_received;
        int ret = IRQ_NONE;
-       struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -1021,18 +1046,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                        READ_BREADCRUMB(dev_priv);
                }
 
-               if (iir & I915_USER_INTERRUPT) {
-                       u32 seqno = render_ring->get_seqno(dev, render_ring);
-                       render_ring->irq_gem_seqno = seqno;
-                       trace_i915_gem_request_complete(dev, seqno);
-                       wake_up_all(&dev_priv->render_ring.irq_queue);
-                       dev_priv->hangcheck_count = 0;
-                       mod_timer(&dev_priv->hangcheck_timer,
-                                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
-               }
-
+               if (iir & I915_USER_INTERRUPT)
+                       notify_ring(dev, &dev_priv->render_ring);
                if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
-                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
+                       notify_ring(dev, &dev_priv->bsd_ring);
 
                if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
                        intel_prepare_page_flip(dev, 0);
@@ -1105,12 +1122,13 @@ static int i915_emit_irq(struct drm_device * dev)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
-       BEGIN_LP_RING(4);
-       OUT_RING(MI_STORE_DWORD_INDEX);
-       OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-       OUT_RING(dev_priv->counter);
-       OUT_RING(MI_USER_INTERRUPT);
-       ADVANCE_LP_RING();
+       if (BEGIN_LP_RING(4) == 0) {
+               OUT_RING(MI_STORE_DWORD_INDEX);
+               OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+               OUT_RING(dev_priv->counter);
+               OUT_RING(MI_USER_INTERRUPT);
+               ADVANCE_LP_RING();
+       }
 
        return dev_priv->counter;
 }
@@ -1121,7 +1139,7 @@ void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
        struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
 
        if (dev_priv->trace_irq_seqno == 0)
-               render_ring->user_irq_get(dev, render_ring);
+               render_ring->user_irq_get(render_ring);
 
        dev_priv->trace_irq_seqno = seqno;
 }
@@ -1145,10 +1163,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
        if (master_priv->sarea_priv)
                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
-       render_ring->user_irq_get(dev, render_ring);
+       render_ring->user_irq_get(render_ring);
        DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ,
                    READ_BREADCRUMB(dev_priv) >= irq_nr);
-       render_ring->user_irq_put(dev, render_ring);
+       render_ring->user_irq_put(render_ring);
 
        if (ret == -EBUSY) {
                DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
@@ -1310,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;
 }
 
 /**
@@ -1329,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);
@@ -1340,32 +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, &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 (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) {
@@ -1382,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;
                                }
                        }
 
@@ -1397,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));
@@ -1446,8 +1466,12 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
        (void) I915_READ(DEIER);
 
-       if (IS_GEN6(dev))
-               render_mask = GT_PIPE_NOTIFY | GT_GEN6_BSD_USER_INTERRUPT;
+       if (IS_GEN6(dev)) {
+               render_mask =
+                       GT_PIPE_NOTIFY |
+                       GT_GEN6_BSD_USER_INTERRUPT |
+                       GT_BLT_USER_INTERRUPT;
+       }
 
        dev_priv->gt_irq_mask_reg = ~render_mask;
        dev_priv->gt_irq_enable_reg = render_mask;
@@ -1457,6 +1481,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        if (IS_GEN6(dev)) {
                I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
                I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+               I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT);
        }
 
        I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
@@ -1526,9 +1551,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        u32 error_mask;
 
        DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
-
        if (HAS_BSD(dev))
                DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue);
 
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
This page took 0.037779 seconds and 5 git commands to generate.