drm/i915: fix how we mask PMIMR when adding work to the queue
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index af5c335a69db65f5b8af5a9b88b3617e50e37ef1..e0c6f7d6189d7c5b21f344d33dc919eb88acbf4e 100644 (file)
@@ -142,14 +142,19 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
                              uint32_t interrupt_mask,
                              uint32_t enabled_irq_mask)
 {
-       uint32_t pmimr = I915_READ(GEN6_PMIMR);
-       pmimr &= ~interrupt_mask;
-       pmimr |= (~enabled_irq_mask & interrupt_mask);
+       uint32_t new_val;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       I915_WRITE(GEN6_PMIMR, pmimr);
-       POSTING_READ(GEN6_PMIMR);
+       new_val = dev_priv->pm_irq_mask;
+       new_val &= ~interrupt_mask;
+       new_val |= (~enabled_irq_mask & interrupt_mask);
+
+       if (new_val != dev_priv->pm_irq_mask) {
+               dev_priv->pm_irq_mask = new_val;
+               I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask);
+               POSTING_READ(GEN6_PMIMR);
+       }
 }
 
 void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
@@ -162,11 +167,6 @@ void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
        snb_update_pm_irq(dev_priv, mask, 0);
 }
 
-static void snb_set_pm_irq(struct drm_i915_private *dev_priv, uint32_t val)
-{
-       snb_update_pm_irq(dev_priv, 0xffffffff, ~val);
-}
-
 static bool ivb_can_enable_err_int(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -784,6 +784,9 @@ static void gen6_pm_rps_work(struct work_struct *work)
        snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS);
        spin_unlock_irq(&dev_priv->irq_lock);
 
+       /* Make sure we didn't queue anything we're not going to process. */
+       WARN_ON(pm_iir & ~GEN6_PM_RPS_EVENTS);
+
        if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
                return;
 
@@ -954,8 +957,8 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
         */
 
        spin_lock(&dev_priv->irq_lock);
-       dev_priv->rps.pm_iir |= pm_iir;
-       snb_set_pm_irq(dev_priv, dev_priv->rps.pm_iir);
+       dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
+       snb_disable_pm_irq(dev_priv, pm_iir & GEN6_PM_RPS_EVENTS);
        spin_unlock(&dev_priv->irq_lock);
 
        queue_work(dev_priv->wq, &dev_priv->rps.work);
@@ -1038,9 +1041,7 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
        if (pm_iir & GEN6_PM_RPS_EVENTS) {
                spin_lock(&dev_priv->irq_lock);
                dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
-               snb_set_pm_irq(dev_priv, dev_priv->rps.pm_iir);
-               /* never want to mask useful interrupts. */
-               WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+               snb_disable_pm_irq(dev_priv, pm_iir & GEN6_PM_RPS_EVENTS);
                spin_unlock(&dev_priv->irq_lock);
 
                queue_work(dev_priv->wq, &dev_priv->rps.work);
@@ -1123,7 +1124,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
                        gmbus_irq_handler(dev);
 
-               if (pm_iir & GEN6_PM_RPS_EVENTS)
+               if (pm_iir)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
 
                I915_WRITE(GTIIR, gt_iir);
@@ -1368,6 +1369,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
+       bool err_int_reenable = false;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -1396,7 +1398,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
         * handler. */
        if (IS_HASWELL(dev)) {
                spin_lock(&dev_priv->irq_lock);
-               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+               err_int_reenable = ~dev_priv->irq_mask & DE_ERR_INT_IVB;
+               if (err_int_reenable)
+                       ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
                spin_unlock(&dev_priv->irq_lock);
        }
 
@@ -1425,14 +1429,14 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
                if (pm_iir) {
                        if (IS_HASWELL(dev))
                                hsw_pm_irq_handler(dev_priv, pm_iir);
-                       else if (pm_iir & GEN6_PM_RPS_EVENTS)
+                       else
                                gen6_rps_irq_handler(dev_priv, pm_iir);
                        I915_WRITE(GEN6_PMIIR, pm_iir);
                        ret = IRQ_HANDLED;
                }
        }
 
-       if (IS_HASWELL(dev)) {
+       if (err_int_reenable) {
                spin_lock(&dev_priv->irq_lock);
                if (ivb_can_enable_err_int(dev))
                        ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
@@ -2213,8 +2217,9 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
                if (HAS_VEBOX(dev))
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
+               dev_priv->pm_irq_mask = 0xffffffff;
                I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-               I915_WRITE(GEN6_PMIMR, 0xffffffff);
+               I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask);
                I915_WRITE(GEN6_PMIER, pm_irqs);
                POSTING_READ(GEN6_PMIER);
        }
This page took 0.026428 seconds and 5 git commands to generate.