drm/i915: Split PORT_HOTPLUG_STAT ack out from i9xx_hpd_irq_handler()
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 13 Apr 2016 18:19:54 +0000 (21:19 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 14 Apr 2016 11:45:37 +0000 (14:45 +0300)
Split the VLV/CHV hoplug irq handling to ack and handler phases. This
way we can move the actual irq handling outside the section where
we have disabled the interrupt sources.

For now, we leave things as is for pre-VLV GMCH platforms, but
eventually they could get the same treatment.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1460571598-24452-9-git-send-email-ville.syrjala@linux.intel.com
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/i915_irq.c

index e6dcc47..51830bd 100644 (file)
@@ -1723,21 +1723,20 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
                gmbus_irq_handler(dev);
 }
 
-static void i9xx_hpd_irq_handler(struct drm_device *dev)
+static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-       u32 pin_mask = 0, long_mask = 0;
 
-       if (!hotplug_status)
-               return;
+       if (hotplug_status)
+               I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 
-       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-       /*
-        * Make sure hotplug status is cleared before we clear IIR, or else we
-        * may miss hotplug events.
-        */
-       POSTING_READ(PORT_HOTPLUG_STAT);
+       return hotplug_status;
+}
+
+static void i9xx_hpd_irq_handler(struct drm_device *dev,
+                                u32 hotplug_status)
+{
+       u32 pin_mask = 0, long_mask = 0;
 
        if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
@@ -1778,6 +1777,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
        do {
                u32 iir, gt_iir, pm_iir;
+               u32 hotplug_status = 0;
                u32 ier = 0;
 
                gt_iir = I915_READ(GTIIR);
@@ -1817,7 +1817,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
 
                if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+                       hotplug_status = i9xx_hpd_irq_ack(dev_priv);
 
                /* Call regardless, as some status bits might not be
                 * signalled in iir */
@@ -1833,6 +1833,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                I915_WRITE(VLV_IER, ier);
                I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
                POSTING_READ(VLV_MASTER_IER);
+
+               if (hotplug_status)
+                       i9xx_hpd_irq_handler(dev, hotplug_status);
        } while (0);
 
        enable_rpm_wakeref_asserts(dev_priv);
@@ -1854,6 +1857,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 
        do {
                u32 master_ctl, iir;
+               u32 hotplug_status = 0;
                u32 ier = 0;
 
                master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
@@ -1884,7 +1888,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
                gen8_gt_irq_handler(dev_priv, master_ctl);
 
                if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+                       hotplug_status = i9xx_hpd_irq_ack(dev_priv);
 
                /* Call regardless, as some status bits might not be
                 * signalled in iir */
@@ -1900,6 +1904,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
                I915_WRITE(VLV_IER, ier);
                I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
                POSTING_READ(GEN8_MASTER_IRQ);
+
+               if (hotplug_status)
+                       i9xx_hpd_irq_handler(dev, hotplug_status);
        } while (0);
 
        enable_rpm_wakeref_asserts(dev_priv);
@@ -4240,8 +4247,11 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                /* Consume port.  Then clear IIR or we'll miss events */
                if (I915_HAS_HOTPLUG(dev) &&
-                   iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+                   iir & I915_DISPLAY_PORT_INTERRUPT) {
+                       u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
+                       if (hotplug_status)
+                               i9xx_hpd_irq_handler(dev, hotplug_status);
+               }
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -4470,8 +4480,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                ret = IRQ_HANDLED;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
+                       u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
+                       if (hotplug_status)
+                               i9xx_hpd_irq_handler(dev, hotplug_status);
+               }
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */