drm/i915: Refactor the deferred PM_IIR handling into a single function
Chris Wilson [Sun, 15 Apr 2012 10:56:03 +0000 (11:56 +0100)]
commit fc6826d1dcd65f3d1e9a5377678882e4e08f02be upstream.

This function, along with the registers and deferred work hander, are
all shared with SandyBridge, IvyBridge and their variants. So remove the
duplicate code into a single function.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
[bwh: Backported to 3.2: adjust context; drop changes for Valley View]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

drivers/gpu/drm/i915/i915_irq.c

index f57e5cf..7e5a965 100644 (file)
@@ -424,6 +424,31 @@ static void gen6_pm_rps_work(struct work_struct *work)
        mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
+static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
+                               u32 pm_iir)
+{
+       unsigned long flags;
+
+       /*
+        * IIR bits should never already be set because IMR should
+        * prevent an interrupt from being shown in IIR. The warning
+        * displays a case where we've unsafely cleared
+        * dev_priv->pm_iir. Although missing an interrupt of the same
+        * type is not a problem, it displays a problem in the logic.
+        *
+        * The mask bit in IMR is cleared by rps_work.
+        */
+
+       spin_lock_irqsave(&dev_priv->rps_lock, flags);
+       WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+       dev_priv->pm_iir |= pm_iir;
+       I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
+       POSTING_READ(GEN6_PMIMR);
+       spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+
+       queue_work(dev_priv->wq, &dev_priv->rps_work);
+}
+
 static void pch_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -529,16 +554,8 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
                pch_irq_handler(dev, pch_iir);
        }
 
-       if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
-               unsigned long flags;
-               spin_lock_irqsave(&dev_priv->rps_lock, flags);
-               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
-               dev_priv->pm_iir |= pm_iir;
-               I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
-               POSTING_READ(GEN6_PMIMR);
-               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
-               queue_work(dev_priv->wq, &dev_priv->rps_work);
-       }
+       if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               gen6_queue_rps_work(dev_priv, pm_iir);
 
        /* should clear PCH hotplug event before clear CPU irq */
        I915_WRITE(SDEIIR, pch_iir);
@@ -634,25 +651,8 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
                i915_handle_rps_change(dev);
        }
 
-       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
-               /*
-                * IIR bits should never already be set because IMR should
-                * prevent an interrupt from being shown in IIR. The warning
-                * displays a case where we've unsafely cleared
-                * dev_priv->pm_iir. Although missing an interrupt of the same
-                * type is not a problem, it displays a problem in the logic.
-                *
-                * The mask bit in IMR is cleared by rps_work.
-                */
-               unsigned long flags;
-               spin_lock_irqsave(&dev_priv->rps_lock, flags);
-               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
-               dev_priv->pm_iir |= pm_iir;
-               I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
-               POSTING_READ(GEN6_PMIMR);
-               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
-               queue_work(dev_priv->wq, &dev_priv->rps_work);
-       }
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
+               gen6_queue_rps_work(dev_priv, pm_iir);
 
        /* should clear PCH hotplug event before clear CPU irq */
        I915_WRITE(SDEIIR, pch_iir);