Commit c496fa1f authored by Adam Jackson's avatar Adam Jackson Committed by Eric Anholt

drm/i915/gen4: Fix interrupt setup ordering

Unmask, then enable interrupts, then enable interrupt sources; matches
PCH ordering.  The old way (sources, enable, unmask) gives a window
during which interrupt conditions would appear in ISR but would never
reach IIR and thus never raise an IRQ.  Since interrupts only trigger
on rising edges in ISR, this would lead to conditions where (for
example) output hotplugging would never fire an interrupt because it
was already stuck on in ISR.

Also, since we know IIR and PIPExSTAT have been cleared during
irq_preinstall, don't clear them again during irq_postinstall, nothing
good can come of that.
Signed-off-by: default avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent f458823b
...@@ -1387,29 +1387,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev) ...@@ -1387,29 +1387,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
dev_priv->pipestat[1] = 0; dev_priv->pipestat[1] = 0;
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
/* Note HDMI and DP share bits */
if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
hotplug_en |= HDMID_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS)
hotplug_en |= CRT_HOTPLUG_INT_EN;
/* Ignore TV since it's buggy */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
/* Enable in IER... */ /* Enable in IER... */
enable_mask |= I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */ /* and unmask in IMR */
i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT;
} }
/* /*
...@@ -1427,16 +1408,31 @@ int i915_driver_irq_postinstall(struct drm_device *dev) ...@@ -1427,16 +1408,31 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
} }
I915_WRITE(EMR, error_mask); I915_WRITE(EMR, error_mask);
/* Disable pipe interrupt enables, clear pending pipe status */
I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
/* Clear pending interrupt status */
I915_WRITE(IIR, I915_READ(IIR));
I915_WRITE(IER, enable_mask);
I915_WRITE(IMR, dev_priv->irq_mask_reg); I915_WRITE(IMR, dev_priv->irq_mask_reg);
I915_WRITE(IER, enable_mask);
(void) I915_READ(IER); (void) I915_READ(IER);
if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
/* Note HDMI and DP share bits */
if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
hotplug_en |= HDMID_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS)
hotplug_en |= CRT_HOTPLUG_INT_EN;
/* Ignore TV since it's buggy */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
}
opregion_enable_asle(dev); opregion_enable_asle(dev);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment