From c496fa1fff0248ef8cd637efb52b70dea7afaa9d Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 27 May 2010 17:26:45 -0400 Subject: [PATCH] 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: Adam Jackson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 56 +++++++++++++++------------------ 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2479be001e40..e9710a7005d4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1386,6 +1386,32 @@ int i915_driver_irq_postinstall(struct drm_device *dev) dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; + if (I915_HAS_HOTPLUG(dev)) { + /* Enable in IER... */ + enable_mask |= I915_DISPLAY_PORT_INTERRUPT; + /* and unmask in IMR */ + dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT; + } + + /* + * Enable some error detection, note the instruction error mask + * bit is reserved, so we leave it masked. + */ + if (IS_G4X(dev)) { + error_mask = ~(GM45_ERROR_PAGE_TABLE | + GM45_ERROR_MEM_PRIV | + GM45_ERROR_CP_PRIV | + I915_ERROR_MEMORY_REFRESH); + } else { + error_mask = ~(I915_ERROR_PAGE_TABLE | + I915_ERROR_MEMORY_REFRESH); + } + I915_WRITE(EMR, error_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); @@ -1405,38 +1431,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev) /* 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); } - /* - * Enable some error detection, note the instruction error mask - * bit is reserved, so we leave it masked. - */ - if (IS_G4X(dev)) { - error_mask = ~(GM45_ERROR_PAGE_TABLE | - GM45_ERROR_MEM_PRIV | - GM45_ERROR_CP_PRIV | - I915_ERROR_MEMORY_REFRESH); - } else { - error_mask = ~(I915_ERROR_PAGE_TABLE | - I915_ERROR_MEMORY_REFRESH); - } - 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); - (void) I915_READ(IER); - opregion_enable_asle(dev); return 0;