drm/i915/vlv: WA to fix Voltage not getting dropped to Vmin when Gfx is power gated.
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index 01a8686362d6277e3ac2d653435236fcda2670ca..56edff3bbbb9177784da4249a4daa76133a89a98 100644 (file)
@@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        return true;
 }
 
+static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+       POSTING_READ(reg);
+}
+
 static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
                                                 enum pipe pipe, bool enable)
 {
@@ -393,7 +405,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev))
+       if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
+               i9xx_clear_fifo_underrun(dev, pipe);
+       else if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
@@ -972,6 +986,43 @@ static void notify_ring(struct drm_device *dev,
        i915_queue_hangcheck(dev);
 }
 
+void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
+                            u32 pm_iir, int new_delay)
+{
+       if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
+               if (new_delay >= dev_priv->rps.max_delay) {
+                       /* Mask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = true;
+               }
+               if (dev_priv->rps.rp_down_masked) {
+                       /* UnMask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = false;
+               }
+       } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
+               if (new_delay <= dev_priv->rps.min_delay) {
+                       /* Mask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = true;
+               }
+
+               if (dev_priv->rps.rp_up_masked) {
+                       /* UnMask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = false;
+               }
+       }
+}
+
 static void gen6_pm_rps_work(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
@@ -1029,6 +1080,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
         */
        new_delay = clamp_t(int, new_delay,
                            dev_priv->rps.min_delay, dev_priv->rps.max_delay);
+
+       gen6_set_pm_mask(dev_priv, pm_iir, new_delay);
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
 
        if (IS_VALLEYVIEW(dev_priv->dev))
@@ -1454,12 +1507,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -1474,6 +1523,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                /* Consume port.  Then clear IIR or we'll miss events */
@@ -1550,12 +1603,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        if (pch_iir & SDE_TRANSA_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (pch_iir & SDE_TRANSB_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 }
 
 static void ivb_err_int_handler(struct drm_device *dev)
@@ -1571,8 +1624,8 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
@@ -1597,17 +1650,17 @@ static void cpt_serr_int_handler(struct drm_device *dev)
        if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder C FIFO underrun\n");
 
        I915_WRITE(SERR_INT, serr_int);
 }
@@ -1669,8 +1722,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
 
                if (de_iir & DE_PIPE_CRC_DONE(pipe))
                        i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -1871,8 +1924,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
@@ -2479,9 +2532,8 @@ static void i915_hangcheck_elapsed(unsigned long data)
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
-#define FIRE 30
 
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        for_each_ring(ring, dev_priv, i) {
@@ -2563,7 +2615,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score > FIRE) {
+               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
                                 stuck[i] ? "stuck" : "no progress",
                                 ring->name);
@@ -2583,7 +2635,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 void i915_queue_hangcheck(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        mod_timer(&dev_priv->gpu_error.hangcheck_timer,
@@ -3198,12 +3250,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -3226,6 +3274,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                iir = new_iir;
@@ -3379,9 +3431,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        /* Clear the PIPE*STAT regs before the IIR */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
                                irq_received = true;
                        }
@@ -3423,6 +3472,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -3617,9 +3670,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                         * Clear the PIPE*STAT regs before the IIR
                         */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
                                irq_received = true;
                        }
@@ -3667,8 +3717,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
 
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+               }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
This page took 0.031251 seconds and 5 git commands to generate.