Skip to content

Commit

Permalink
drm/i915/gen4: Fix interrupt setup ordering
Browse files Browse the repository at this point in the history
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: Adam Jackson <ajax@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
  • Loading branch information
Adam Jackson authored and Eric Anholt committed Jun 5, 2010
1 parent f458823 commit c496fa1
Showing 1 changed file with 23 additions and 27 deletions.
50 changes: 23 additions & 27 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1387,29 +1387,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
dev_priv->pipestat[1] = 0;

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_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */
i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT;
}

/*
Expand All @@ -1427,16 +1408,31 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
}
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(IER, enable_mask);
(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);

return 0;
Expand Down

0 comments on commit c496fa1

Please sign in to comment.