drm/i915: Set invert bit for hpd based on VBT
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index fa8afa7860ae175753b501622d9295f1475a6c96..5bec13844800368f82868b2326163131eb994464 100644 (file)
@@ -994,14 +994,14 @@ static void ironlake_rps_change_irq_handler(struct drm_device *dev)
        return;
 }
 
-static void notify_ring(struct intel_engine_cs *ring)
+static void notify_ring(struct intel_engine_cs *engine)
 {
-       if (!intel_ring_initialized(ring))
+       if (!intel_engine_initialized(engine))
                return;
 
-       trace_i915_gem_request_notify(ring);
+       trace_i915_gem_request_notify(engine);
 
-       wake_up_all(&ring->irq_queue);
+       wake_up_all(&engine->irq_queue);
 }
 
 static void vlv_c0_read(struct drm_i915_private *dev_priv,
@@ -1079,11 +1079,10 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
 
 static bool any_waiters(struct drm_i915_private *dev_priv)
 {
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
 
-       for_each_ring(ring, dev_priv, i)
-               if (ring->irq_refcount)
+       for_each_engine(engine, dev_priv)
+               if (engine->irq_refcount)
                        return true;
 
        return false;
@@ -1291,9 +1290,9 @@ static void ilk_gt_irq_handler(struct drm_device *dev,
 {
        if (gt_iir &
            (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
-               notify_ring(&dev_priv->ring[RCS]);
+               notify_ring(&dev_priv->engine[RCS]);
        if (gt_iir & ILK_BSD_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[VCS]);
+               notify_ring(&dev_priv->engine[VCS]);
 }
 
 static void snb_gt_irq_handler(struct drm_device *dev,
@@ -1303,11 +1302,11 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 
        if (gt_iir &
            (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
-               notify_ring(&dev_priv->ring[RCS]);
+               notify_ring(&dev_priv->engine[RCS]);
        if (gt_iir & GT_BSD_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[VCS]);
+               notify_ring(&dev_priv->engine[VCS]);
        if (gt_iir & GT_BLT_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[BCS]);
+               notify_ring(&dev_priv->engine[BCS]);
 
        if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
                      GT_BSD_CS_ERROR_INTERRUPT |
@@ -1319,12 +1318,12 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 }
 
 static __always_inline void
-gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
+gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
 {
        if (iir & (GT_RENDER_USER_INTERRUPT << test_shift))
-               notify_ring(ring);
+               notify_ring(engine);
        if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
-               intel_lrc_irq_handler(ring);
+               tasklet_schedule(&engine->irq_tasklet);
 }
 
 static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
@@ -1338,11 +1337,11 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
                        I915_WRITE_FW(GEN8_GT_IIR(0), iir);
                        ret = IRQ_HANDLED;
 
-                       gen8_cs_irq_handler(&dev_priv->ring[RCS],
-                                       iir, GEN8_RCS_IRQ_SHIFT);
+                       gen8_cs_irq_handler(&dev_priv->engine[RCS],
+                                           iir, GEN8_RCS_IRQ_SHIFT);
 
-                       gen8_cs_irq_handler(&dev_priv->ring[BCS],
-                                       iir, GEN8_BCS_IRQ_SHIFT);
+                       gen8_cs_irq_handler(&dev_priv->engine[BCS],
+                                           iir, GEN8_BCS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
@@ -1353,11 +1352,11 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
                        I915_WRITE_FW(GEN8_GT_IIR(1), iir);
                        ret = IRQ_HANDLED;
 
-                       gen8_cs_irq_handler(&dev_priv->ring[VCS],
-                                       iir, GEN8_VCS1_IRQ_SHIFT);
+                       gen8_cs_irq_handler(&dev_priv->engine[VCS],
+                                           iir, GEN8_VCS1_IRQ_SHIFT);
 
-                       gen8_cs_irq_handler(&dev_priv->ring[VCS2],
-                                       iir, GEN8_VCS2_IRQ_SHIFT);
+                       gen8_cs_irq_handler(&dev_priv->engine[VCS2],
+                                           iir, GEN8_VCS2_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
@@ -1368,8 +1367,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
                        I915_WRITE_FW(GEN8_GT_IIR(3), iir);
                        ret = IRQ_HANDLED;
 
-                       gen8_cs_irq_handler(&dev_priv->ring[VECS],
-                                       iir, GEN8_VECS_IRQ_SHIFT);
+                       gen8_cs_irq_handler(&dev_priv->engine[VECS],
+                                           iir, GEN8_VECS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@ -1629,7 +1628,7 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 
        if (HAS_VEBOX(dev_priv->dev)) {
                if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[VECS]);
+                       notify_ring(&dev_priv->engine[VECS]);
 
                if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
                        DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
@@ -1651,6 +1650,12 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
        int pipe;
 
        spin_lock(&dev_priv->irq_lock);
+
+       if (!dev_priv->display_irqs_enabled) {
+               spin_unlock(&dev_priv->irq_lock);
+               return;
+       }
+
        for_each_pipe(dev_priv, pipe) {
                i915_reg_t reg;
                u32 mask, iir_bit = 0;
@@ -1823,7 +1828,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        disable_rpm_wakeref_asserts(dev_priv);
 
-       for (;;) {
+       do {
                master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
                iir = I915_READ(VLV_IIR);
 
@@ -1851,7 +1856,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 
                I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
                POSTING_READ(GEN8_MASTER_IRQ);
-       }
+       } while (0);
 
        enable_rpm_wakeref_asserts(dev_priv);
 
@@ -2188,10 +2193,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        disable_rpm_wakeref_asserts(dev_priv);
 
-       /* We get interrupts on unclaimed registers, so check for this before we
-        * do any I915_{READ,WRITE}. */
-       intel_uncore_check_errors(dev);
-
        /* disable master interrupt before clearing iir  */
        de_ier = I915_READ(DEIER);
        I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
@@ -2268,43 +2269,20 @@ static void bxt_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
        intel_hpd_irq_handler(dev, pin_mask, long_mask);
 }
 
-static irqreturn_t gen8_irq_handler(int irq, void *arg)
+static irqreturn_t
+gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 {
-       struct drm_device *dev = arg;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 master_ctl;
+       struct drm_device *dev = dev_priv->dev;
        irqreturn_t ret = IRQ_NONE;
-       uint32_t tmp = 0;
+       u32 iir;
        enum pipe pipe;
-       u32 aux_mask = GEN8_AUX_CHANNEL_A;
-
-       if (!intel_irqs_enabled(dev_priv))
-               return IRQ_NONE;
-
-       /* IRQs are synced during runtime_suspend, we don't require a wakeref */
-       disable_rpm_wakeref_asserts(dev_priv);
-
-       if (INTEL_INFO(dev_priv)->gen >= 9)
-               aux_mask |=  GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
-                       GEN9_AUX_CHANNEL_D;
-
-       master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
-       master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
-       if (!master_ctl)
-               goto out;
-
-       I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
-
-       /* Find, clear, then process each source of interrupt */
-
-       ret = gen8_gt_irq_handler(dev_priv, master_ctl);
 
        if (master_ctl & GEN8_DE_MISC_IRQ) {
-               tmp = I915_READ(GEN8_DE_MISC_IIR);
-               if (tmp) {
-                       I915_WRITE(GEN8_DE_MISC_IIR, tmp);
+               iir = I915_READ(GEN8_DE_MISC_IIR);
+               if (iir) {
+                       I915_WRITE(GEN8_DE_MISC_IIR, iir);
                        ret = IRQ_HANDLED;
-                       if (tmp & GEN8_DE_MISC_GSE)
+                       if (iir & GEN8_DE_MISC_GSE)
                                intel_opregion_asle_intr(dev);
                        else
                                DRM_ERROR("Unexpected DE Misc interrupt\n");
@@ -2314,33 +2292,40 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        }
 
        if (master_ctl & GEN8_DE_PORT_IRQ) {
-               tmp = I915_READ(GEN8_DE_PORT_IIR);
-               if (tmp) {
+               iir = I915_READ(GEN8_DE_PORT_IIR);
+               if (iir) {
+                       u32 tmp_mask;
                        bool found = false;
-                       u32 hotplug_trigger = 0;
-
-                       if (IS_BROXTON(dev_priv))
-                               hotplug_trigger = tmp & BXT_DE_PORT_HOTPLUG_MASK;
-                       else if (IS_BROADWELL(dev_priv))
-                               hotplug_trigger = tmp & GEN8_PORT_DP_A_HOTPLUG;
 
-                       I915_WRITE(GEN8_DE_PORT_IIR, tmp);
+                       I915_WRITE(GEN8_DE_PORT_IIR, iir);
                        ret = IRQ_HANDLED;
 
-                       if (tmp & aux_mask) {
+                       tmp_mask = GEN8_AUX_CHANNEL_A;
+                       if (INTEL_INFO(dev_priv)->gen >= 9)
+                               tmp_mask |= GEN9_AUX_CHANNEL_B |
+                                           GEN9_AUX_CHANNEL_C |
+                                           GEN9_AUX_CHANNEL_D;
+
+                       if (iir & tmp_mask) {
                                dp_aux_irq_handler(dev);
                                found = true;
                        }
 
-                       if (hotplug_trigger) {
-                               if (IS_BROXTON(dev))
-                                       bxt_hpd_irq_handler(dev, hotplug_trigger, hpd_bxt);
-                               else
-                                       ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_bdw);
-                               found = true;
+                       if (IS_BROXTON(dev_priv)) {
+                               tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
+                               if (tmp_mask) {
+                                       bxt_hpd_irq_handler(dev, tmp_mask, hpd_bxt);
+                                       found = true;
+                               }
+                       } else if (IS_BROADWELL(dev_priv)) {
+                               tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
+                               if (tmp_mask) {
+                                       ilk_hpd_irq_handler(dev, tmp_mask, hpd_bdw);
+                                       found = true;
+                               }
                        }
 
-                       if (IS_BROXTON(dev) && (tmp & BXT_DE_PORT_GMBUS)) {
+                       if (IS_BROXTON(dev) && (iir & BXT_DE_PORT_GMBUS)) {
                                gmbus_irq_handler(dev);
                                found = true;
                        }
@@ -2353,49 +2338,51 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        }
 
        for_each_pipe(dev_priv, pipe) {
-               uint32_t pipe_iir, flip_done = 0, fault_errors = 0;
+               u32 flip_done, fault_errors;
 
                if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
                        continue;
 
-               pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
-               if (pipe_iir) {
-                       ret = IRQ_HANDLED;
-                       I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
+               iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
+               if (!iir) {
+                       DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
+                       continue;
+               }
 
-                       if (pipe_iir & GEN8_PIPE_VBLANK &&
-                           intel_pipe_handle_vblank(dev, pipe))
-                               intel_check_page_flip(dev, pipe);
+               ret = IRQ_HANDLED;
+               I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
 
-                       if (INTEL_INFO(dev_priv)->gen >= 9)
-                               flip_done = pipe_iir & GEN9_PIPE_PLANE1_FLIP_DONE;
-                       else
-                               flip_done = pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE;
+               if (iir & GEN8_PIPE_VBLANK &&
+                   intel_pipe_handle_vblank(dev, pipe))
+                       intel_check_page_flip(dev, pipe);
 
-                       if (flip_done) {
-                               intel_prepare_page_flip(dev, pipe);
-                               intel_finish_page_flip_plane(dev, pipe);
-                       }
+               flip_done = iir;
+               if (INTEL_INFO(dev_priv)->gen >= 9)
+                       flip_done &= GEN9_PIPE_PLANE1_FLIP_DONE;
+               else
+                       flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE;
 
-                       if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
-                               hsw_pipe_crc_irq_handler(dev, pipe);
+               if (flip_done) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
+               }
 
-                       if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN)
-                               intel_cpu_fifo_underrun_irq_handler(dev_priv,
-                                                                   pipe);
+               if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
+                       hsw_pipe_crc_irq_handler(dev, pipe);
 
+               if (iir & GEN8_PIPE_FIFO_UNDERRUN)
+                       intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
 
-                       if (INTEL_INFO(dev_priv)->gen >= 9)
-                               fault_errors = pipe_iir & GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
-                       else
-                               fault_errors = pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+               fault_errors = iir;
+               if (INTEL_INFO(dev_priv)->gen >= 9)
+                       fault_errors &= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
+               else
+                       fault_errors &= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
 
-                       if (fault_errors)
-                               DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
-                                         pipe_name(pipe),
-                                         pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
-               } else
-                       DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
+               if (fault_errors)
+                       DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
+                                 pipe_name(pipe),
+                                 fault_errors);
        }
 
        if (HAS_PCH_SPLIT(dev) && !HAS_PCH_NOP(dev) &&
@@ -2405,15 +2392,15 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                 * scheme also closed the SDE interrupt handling race we've seen
                 * on older pch-split platforms. But this needs testing.
                 */
-               u32 pch_iir = I915_READ(SDEIIR);
-               if (pch_iir) {
-                       I915_WRITE(SDEIIR, pch_iir);
+               iir = I915_READ(SDEIIR);
+               if (iir) {
+                       I915_WRITE(SDEIIR, iir);
                        ret = IRQ_HANDLED;
 
                        if (HAS_PCH_SPT(dev_priv))
-                               spt_irq_handler(dev, pch_iir);
+                               spt_irq_handler(dev, iir);
                        else
-                               cpt_irq_handler(dev, pch_iir);
+                               cpt_irq_handler(dev, iir);
                } else {
                        /*
                         * Like on previous PCH there seems to be something
@@ -2423,10 +2410,36 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                }
        }
 
+       return ret;
+}
+
+static irqreturn_t gen8_irq_handler(int irq, void *arg)
+{
+       struct drm_device *dev = arg;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 master_ctl;
+       irqreturn_t ret;
+
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
+       master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
+       master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
+       if (!master_ctl)
+               return IRQ_NONE;
+
+       I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
+
+       /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+       disable_rpm_wakeref_asserts(dev_priv);
+
+       /* Find, clear, then process each source of interrupt */
+       ret = gen8_gt_irq_handler(dev_priv, master_ctl);
+       ret |= gen8_de_irq_handler(dev_priv, master_ctl);
+
        I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
        POSTING_READ_FW(GEN8_MASTER_IRQ);
 
-out:
        enable_rpm_wakeref_asserts(dev_priv);
 
        return ret;
@@ -2435,8 +2448,7 @@ out:
 static void i915_error_wake_up(struct drm_i915_private *dev_priv,
                               bool reset_completed)
 {
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
 
        /*
         * Notify all waiters for GPU completion events that reset state has
@@ -2446,8 +2458,8 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
         */
 
        /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
-       for_each_ring(ring, dev_priv, i)
-               wake_up_all(&ring->irq_queue);
+       for_each_engine(engine, dev_priv)
+               wake_up_all(&engine->irq_queue);
 
        /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
        wake_up_all(&dev_priv->pending_flip_queue);
@@ -2639,14 +2651,14 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 /**
  * i915_handle_error - handle a gpu error
  * @dev: drm device
- *
+ * @engine_mask: mask representing engines that are hung
  * Do some basic checking of register state at error time and
  * dump it to the syslog.  Also call i915_capture_error_state() to make
  * sure we get a record and make it available in debugfs.  Fire a uevent
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-void i915_handle_error(struct drm_device *dev, bool wedged,
+void i915_handle_error(struct drm_device *dev, u32 engine_mask,
                       const char *fmt, ...)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2657,10 +2669,10 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
        vscnprintf(error_msg, sizeof(error_msg), fmt, args);
        va_end(args);
 
-       i915_capture_error_state(dev, wedged, error_msg);
+       i915_capture_error_state(dev, engine_mask, error_msg);
        i915_report_and_clear_eir(dev);
 
-       if (wedged) {
+       if (engine_mask) {
                atomic_or(I915_RESET_IN_PROGRESS_FLAG,
                                &dev_priv->gpu_error.reset_counter);
 
@@ -2791,10 +2803,10 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static bool
-ring_idle(struct intel_engine_cs *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *engine, u32 seqno)
 {
-       return (list_empty(&ring->request_list) ||
-               i915_seqno_passed(seqno, ring->last_submitted_seqno));
+       return (list_empty(&engine->request_list) ||
+               i915_seqno_passed(seqno, engine->last_submitted_seqno));
 }
 
 static bool
@@ -2810,42 +2822,42 @@ ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr)
 }
 
 static struct intel_engine_cs *
-semaphore_wait_to_signaller_ring(struct intel_engine_cs *ring, u32 ipehr, u64 offset)
+semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr,
+                                u64 offset)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->dev->dev_private;
        struct intel_engine_cs *signaller;
-       int i;
 
        if (INTEL_INFO(dev_priv->dev)->gen >= 8) {
-               for_each_ring(signaller, dev_priv, i) {
-                       if (ring == signaller)
+               for_each_engine(signaller, dev_priv) {
+                       if (engine == signaller)
                                continue;
 
-                       if (offset == signaller->semaphore.signal_ggtt[ring->id])
+                       if (offset == signaller->semaphore.signal_ggtt[engine->id])
                                return signaller;
                }
        } else {
                u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK;
 
-               for_each_ring(signaller, dev_priv, i) {
-                       if(ring == signaller)
+               for_each_engine(signaller, dev_priv) {
+                       if(engine == signaller)
                                continue;
 
-                       if (sync_bits == signaller->semaphore.mbox.wait[ring->id])
+                       if (sync_bits == signaller->semaphore.mbox.wait[engine->id])
                                return signaller;
                }
        }
 
        DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n",
-                 ring->id, ipehr, offset);
+                 engine->id, ipehr, offset);
 
        return NULL;
 }
 
 static struct intel_engine_cs *
-semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
+semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->dev->dev_private;
        u32 cmd, ipehr, head;
        u64 offset = 0;
        int i, backwards;
@@ -2867,11 +2879,11 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
         * Therefore, this function does not support execlist mode in its
         * current form. Just return NULL and move on.
         */
-       if (ring->buffer == NULL)
+       if (engine->buffer == NULL)
                return NULL;
 
-       ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
-       if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
+       ipehr = I915_READ(RING_IPEHR(engine->mmio_base));
+       if (!ipehr_is_semaphore_wait(engine->dev, ipehr))
                return NULL;
 
        /*
@@ -2882,8 +2894,8 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
         * point at at batch, and semaphores are always emitted into the
         * ringbuffer itself.
         */
-       head = I915_READ_HEAD(ring) & HEAD_ADDR;
-       backwards = (INTEL_INFO(ring->dev)->gen >= 8) ? 5 : 4;
+       head = I915_READ_HEAD(engine) & HEAD_ADDR;
+       backwards = (INTEL_INFO(engine->dev)->gen >= 8) ? 5 : 4;
 
        for (i = backwards; i; --i) {
                /*
@@ -2891,10 +2903,10 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
                 * our ring is smaller than what the hardware (and hence
                 * HEAD_ADDR) allows. Also handles wrap-around.
                 */
-               head &= ring->buffer->size - 1;
+               head &= engine->buffer->size - 1;
 
                /* This here seems to blow up */
-               cmd = ioread32(ring->buffer->virtual_start + head);
+               cmd = ioread32(engine->buffer->virtual_start + head);
                if (cmd == ipehr)
                        break;
 
@@ -2904,29 +2916,29 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
        if (!i)
                return NULL;
 
-       *seqno = ioread32(ring->buffer->virtual_start + head + 4) + 1;
-       if (INTEL_INFO(ring->dev)->gen >= 8) {
-               offset = ioread32(ring->buffer->virtual_start + head + 12);
+       *seqno = ioread32(engine->buffer->virtual_start + head + 4) + 1;
+       if (INTEL_INFO(engine->dev)->gen >= 8) {
+               offset = ioread32(engine->buffer->virtual_start + head + 12);
                offset <<= 32;
-               offset = ioread32(ring->buffer->virtual_start + head + 8);
+               offset = ioread32(engine->buffer->virtual_start + head + 8);
        }
-       return semaphore_wait_to_signaller_ring(ring, ipehr, offset);
+       return semaphore_wait_to_signaller_ring(engine, ipehr, offset);
 }
 
-static int semaphore_passed(struct intel_engine_cs *ring)
+static int semaphore_passed(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->dev->dev_private;
        struct intel_engine_cs *signaller;
        u32 seqno;
 
-       ring->hangcheck.deadlock++;
+       engine->hangcheck.deadlock++;
 
-       signaller = semaphore_waits_for(ring, &seqno);
+       signaller = semaphore_waits_for(engine, &seqno);
        if (signaller == NULL)
                return -1;
 
        /* Prevent pathological recursion due to driver bugs */
-       if (signaller->hangcheck.deadlock >= I915_NUM_RINGS)
+       if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES)
                return -1;
 
        if (i915_seqno_passed(signaller->get_seqno(signaller, false), seqno))
@@ -2942,29 +2954,71 @@ static int semaphore_passed(struct intel_engine_cs *ring)
 
 static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
 {
-       struct intel_engine_cs *ring;
+       struct intel_engine_cs *engine;
+
+       for_each_engine(engine, dev_priv)
+               engine->hangcheck.deadlock = 0;
+}
+
+static bool subunits_stuck(struct intel_engine_cs *engine)
+{
+       u32 instdone[I915_NUM_INSTDONE_REG];
+       bool stuck;
        int i;
 
-       for_each_ring(ring, dev_priv, i)
-               ring->hangcheck.deadlock = 0;
+       if (engine->id != RCS)
+               return true;
+
+       i915_get_extra_instdone(engine->dev, instdone);
+
+       /* There might be unstable subunit states even when
+        * actual head is not moving. Filter out the unstable ones by
+        * accumulating the undone -> done transitions and only
+        * consider those as progress.
+        */
+       stuck = true;
+       for (i = 0; i < I915_NUM_INSTDONE_REG; i++) {
+               const u32 tmp = instdone[i] | engine->hangcheck.instdone[i];
+
+               if (tmp != engine->hangcheck.instdone[i])
+                       stuck = false;
+
+               engine->hangcheck.instdone[i] |= tmp;
+       }
+
+       return stuck;
 }
 
 static enum intel_ring_hangcheck_action
-ring_stuck(struct intel_engine_cs *ring, u64 acthd)
+head_stuck(struct intel_engine_cs *engine, u64 acthd)
 {
-       struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 tmp;
+       if (acthd != engine->hangcheck.acthd) {
 
-       if (acthd != ring->hangcheck.acthd) {
-               if (acthd > ring->hangcheck.max_acthd) {
-                       ring->hangcheck.max_acthd = acthd;
-                       return HANGCHECK_ACTIVE;
-               }
+               /* Clear subunit states on head movement */
+               memset(engine->hangcheck.instdone, 0,
+                      sizeof(engine->hangcheck.instdone));
 
-               return HANGCHECK_ACTIVE_LOOP;
+               return HANGCHECK_ACTIVE;
        }
 
+       if (!subunits_stuck(engine))
+               return HANGCHECK_ACTIVE;
+
+       return HANGCHECK_HUNG;
+}
+
+static enum intel_ring_hangcheck_action
+ring_stuck(struct intel_engine_cs *engine, u64 acthd)
+{
+       struct drm_device *dev = engine->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_ring_hangcheck_action ha;
+       u32 tmp;
+
+       ha = head_stuck(engine, acthd);
+       if (ha != HANGCHECK_HUNG)
+               return ha;
+
        if (IS_GEN2(dev))
                return HANGCHECK_HUNG;
 
@@ -2973,24 +3027,24 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
         * and break the hang. This should work on
         * all but the second generation chipsets.
         */
-       tmp = I915_READ_CTL(ring);
+       tmp = I915_READ_CTL(engine);
        if (tmp & RING_WAIT) {
-               i915_handle_error(dev, false,
+               i915_handle_error(dev, 0,
                                  "Kicking stuck wait on %s",
-                                 ring->name);
-               I915_WRITE_CTL(ring, tmp);
+                                 engine->name);
+               I915_WRITE_CTL(engine, tmp);
                return HANGCHECK_KICK;
        }
 
        if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) {
-               switch (semaphore_passed(ring)) {
+               switch (semaphore_passed(engine)) {
                default:
                        return HANGCHECK_HUNG;
                case 1:
-                       i915_handle_error(dev, false,
+                       i915_handle_error(dev, 0,
                                          "Kicking stuck semaphore on %s",
-                                         ring->name);
-                       I915_WRITE_CTL(ring, tmp);
+                                         engine->name);
+                       I915_WRITE_CTL(engine, tmp);
                        return HANGCHECK_KICK;
                case 0:
                        return HANGCHECK_WAIT;
@@ -3014,13 +3068,14 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                container_of(work, typeof(*dev_priv),
                             gpu_error.hangcheck_work.work);
        struct drm_device *dev = dev_priv->dev;
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        int busy_count = 0, rings_hung = 0;
-       bool stuck[I915_NUM_RINGS] = { 0 };
+       bool stuck[I915_NUM_ENGINES] = { 0 };
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
+#define ACTIVE_DECAY 15
 
        if (!i915.enable_hangcheck)
                return;
@@ -3032,33 +3087,39 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
         */
        DISABLE_RPM_WAKEREF_ASSERTS(dev_priv);
 
-       for_each_ring(ring, dev_priv, i) {
+       /* As enabling the GPU requires fairly extensive mmio access,
+        * periodically arm the mmio checker to see if we are triggering
+        * any invalid access.
+        */
+       intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
+
+       for_each_engine_id(engine, dev_priv, id) {
                u64 acthd;
                u32 seqno;
                bool busy = true;
 
                semaphore_clear_deadlocks(dev_priv);
 
-               seqno = ring->get_seqno(ring, false);
-               acthd = intel_ring_get_active_head(ring);
+               seqno = engine->get_seqno(engine, false);
+               acthd = intel_ring_get_active_head(engine);
 
-               if (ring->hangcheck.seqno == seqno) {
-                       if (ring_idle(ring, seqno)) {
-                               ring->hangcheck.action = HANGCHECK_IDLE;
+               if (engine->hangcheck.seqno == seqno) {
+                       if (ring_idle(engine, seqno)) {
+                               engine->hangcheck.action = HANGCHECK_IDLE;
 
-                               if (waitqueue_active(&ring->irq_queue)) {
+                               if (waitqueue_active(&engine->irq_queue)) {
                                        /* Issue a wake-up to catch stuck h/w. */
-                                       if (!test_and_set_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings)) {
-                                               if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)))
+                                       if (!test_and_set_bit(engine->id, &dev_priv->gpu_error.missed_irq_rings)) {
+                                               if (!(dev_priv->gpu_error.test_irq_rings & intel_engine_flag(engine)))
                                                        DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                                                 ring->name);
+                                                                 engine->name);
                                                else
                                                        DRM_INFO("Fake missed irq on %s\n",
-                                                                ring->name);
-                                               wake_up_all(&ring->irq_queue);
+                                                                engine->name);
+                                               wake_up_all(&engine->irq_queue);
                                        }
                                        /* Safeguard against driver failure */
-                                       ring->hangcheck.score += BUSY;
+                                       engine->hangcheck.score += BUSY;
                                } else
                                        busy = false;
                        } else {
@@ -3077,54 +3138,59 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                                 * being repeatedly kicked and so responsible
                                 * for stalling the machine.
                                 */
-                               ring->hangcheck.action = ring_stuck(ring,
-                                                                   acthd);
+                               engine->hangcheck.action = ring_stuck(engine,
+                                                                     acthd);
 
-                               switch (ring->hangcheck.action) {
+                               switch (engine->hangcheck.action) {
                                case HANGCHECK_IDLE:
                                case HANGCHECK_WAIT:
-                               case HANGCHECK_ACTIVE:
                                        break;
-                               case HANGCHECK_ACTIVE_LOOP:
-                                       ring->hangcheck.score += BUSY;
+                               case HANGCHECK_ACTIVE:
+                                       engine->hangcheck.score += BUSY;
                                        break;
                                case HANGCHECK_KICK:
-                                       ring->hangcheck.score += KICK;
+                                       engine->hangcheck.score += KICK;
                                        break;
                                case HANGCHECK_HUNG:
-                                       ring->hangcheck.score += HUNG;
-                                       stuck[i] = true;
+                                       engine->hangcheck.score += HUNG;
+                                       stuck[id] = true;
                                        break;
                                }
                        }
                } else {
-                       ring->hangcheck.action = HANGCHECK_ACTIVE;
+                       engine->hangcheck.action = HANGCHECK_ACTIVE;
 
                        /* Gradually reduce the count so that we catch DoS
                         * attempts across multiple batches.
                         */
-                       if (ring->hangcheck.score > 0)
-                               ring->hangcheck.score--;
+                       if (engine->hangcheck.score > 0)
+                               engine->hangcheck.score -= ACTIVE_DECAY;
+                       if (engine->hangcheck.score < 0)
+                               engine->hangcheck.score = 0;
+
+                       /* Clear head and subunit states on seqno movement */
+                       engine->hangcheck.acthd = 0;
 
-                       ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0;
+                       memset(engine->hangcheck.instdone, 0,
+                              sizeof(engine->hangcheck.instdone));
                }
 
-               ring->hangcheck.seqno = seqno;
-               ring->hangcheck.acthd = acthd;
+               engine->hangcheck.seqno = seqno;
+               engine->hangcheck.acthd = acthd;
                busy_count += busy;
        }
 
-       for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
+       for_each_engine_id(engine, dev_priv, id) {
+               if (engine->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
-                                stuck[i] ? "stuck" : "no progress",
-                                ring->name);
-                       rings_hung++;
+                                stuck[id] ? "stuck" : "no progress",
+                                engine->name);
+                       rings_hung |= intel_engine_flag(engine);
                }
        }
 
        if (rings_hung) {
-               i915_handle_error(dev, true, "Ring hung");
+               i915_handle_error(dev, rings_hung, "Engine(s) hung");
                goto out;
        }
 
@@ -3277,21 +3343,28 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
                                     unsigned int pipe_mask)
 {
        uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
+       enum pipe pipe;
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       for_each_pipe_masked(dev_priv, pipe, pipe_mask)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
+                                 dev_priv->de_irq_mask[pipe],
+                                 ~dev_priv->de_irq_mask[pipe] | extra_ier);
+       spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
+                                    unsigned int pipe_mask)
+{
+       enum pipe pipe;
 
        spin_lock_irq(&dev_priv->irq_lock);
-       if (pipe_mask & 1 << PIPE_A)
-               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_A,
-                                 dev_priv->de_irq_mask[PIPE_A],
-                                 ~dev_priv->de_irq_mask[PIPE_A] | extra_ier);
-       if (pipe_mask & 1 << PIPE_B)
-               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B,
-                                 dev_priv->de_irq_mask[PIPE_B],
-                                 ~dev_priv->de_irq_mask[PIPE_B] | extra_ier);
-       if (pipe_mask & 1 << PIPE_C)
-               GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C,
-                                 dev_priv->de_irq_mask[PIPE_C],
-                                 ~dev_priv->de_irq_mask[PIPE_C] | extra_ier);
+       for_each_pipe_masked(dev_priv, pipe, pipe_mask)
+               GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
        spin_unlock_irq(&dev_priv->irq_lock);
+
+       /* make sure we're done processing display irqs */
+       synchronize_irq(dev_priv->dev->irq);
 }
 
 static void cherryview_irq_preinstall(struct drm_device *dev)
@@ -3427,6 +3500,26 @@ static void bxt_hpd_irq_setup(struct drm_device *dev)
        hotplug = I915_READ(PCH_PORT_HOTPLUG);
        hotplug |= PORTC_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE |
                PORTA_HOTPLUG_ENABLE;
+
+       DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x\n",
+                     hotplug, enabled_irqs);
+       hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
+
+       /*
+        * For BXT invert bit has to be set based on AOB design
+        * for HPD detection logic, update it based on VBT fields.
+        */
+
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
+               hotplug |= BXT_DDIA_HPD_INVERT;
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
+               hotplug |= BXT_DDIB_HPD_INVERT;
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
+               hotplug |= BXT_DDIC_HPD_INVERT;
+
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 }
 
@@ -3965,7 +4058,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                new_iir = I915_READ16(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
@@ -4161,7 +4254,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
@@ -4391,9 +4484,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
                if (iir & I915_BSD_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[VCS]);
+                       notify_ring(&dev_priv->engine[VCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
@@ -4488,8 +4581,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
                          i915_hangcheck_elapsed);
 
-       pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
-
        if (IS_GEN2(dev_priv)) {
                dev->max_vblank_count = 0;
                dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
This page took 0.05276 seconds and 5 git commands to generate.