drm/i915: Always read pipestat in irq_handler

Because we write pipestat before iir, it's possible that a pipestat
interrupt will occur between the pipestat write and the iir write. This
leaves pipestat with an interrupt status not visible in iir. This may cause
an interrupt flood as we never clear the pipestat event.

Signed-off-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by Keith Packard and committed by Dave Airlie 05eff845 2678d9d6

+36 -19
+36 -19
drivers/gpu/drm/i915/i915_irq.c
··· 170 170 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 171 171 u32 iir, new_iir; 172 172 u32 pipea_stats, pipeb_stats; 173 + u32 vblank_status; 174 + u32 vblank_enable; 173 175 int vblank = 0; 174 176 unsigned long irqflags; 177 + int irq_received; 178 + int ret = IRQ_NONE; 175 179 176 180 atomic_inc(&dev_priv->irq_received); 177 181 178 182 iir = I915_READ(IIR); 179 183 180 - if (iir == 0) 181 - return IRQ_NONE; 184 + if (IS_I965G(dev)) { 185 + vblank_status = I915_START_VBLANK_INTERRUPT_STATUS; 186 + vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE; 187 + } else { 188 + vblank_status = I915_VBLANK_INTERRUPT_STATUS; 189 + vblank_enable = I915_VBLANK_INTERRUPT_ENABLE; 190 + } 182 191 183 - do { 184 - pipea_stats = 0; 185 - pipeb_stats = 0; 192 + for (;;) { 193 + irq_received = iir != 0; 194 + 195 + /* Can't rely on pipestat interrupt bit in iir as it might 196 + * have been cleared after the pipestat interrupt was received. 197 + * It doesn't set the bit in iir again, but it still produces 198 + * interrupts (for non-MSI). 199 + */ 200 + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 201 + pipea_stats = I915_READ(PIPEASTAT); 202 + pipeb_stats = I915_READ(PIPEBSTAT); 186 203 /* 187 204 * Clear the PIPE(A|B)STAT regs before the IIR 188 205 */ 189 - if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { 190 - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 191 - pipea_stats = I915_READ(PIPEASTAT); 206 + if (pipea_stats & 0x8000ffff) { 192 207 I915_WRITE(PIPEASTAT, pipea_stats); 193 - spin_unlock_irqrestore(&dev_priv->user_irq_lock, 194 - irqflags); 208 + irq_received = 1; 195 209 } 196 210 197 - if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { 198 - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 199 - pipeb_stats = I915_READ(PIPEBSTAT); 211 + if (pipeb_stats & 0x8000ffff) { 200 212 I915_WRITE(PIPEBSTAT, pipeb_stats); 201 - spin_unlock_irqrestore(&dev_priv->user_irq_lock, 202 - irqflags); 213 + irq_received = 1; 203 214 } 215 + spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 216 + 217 + if (!irq_received) 218 + break; 219 + 220 + ret = IRQ_HANDLED; 204 221 205 222 I915_WRITE(IIR, iir); 206 223 new_iir = I915_READ(IIR); /* Flush posted writes */ ··· 231 214 DRM_WAKEUP(&dev_priv->irq_queue); 232 215 } 233 216 234 - if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) { 217 + if (pipea_stats & vblank_status) { 235 218 vblank++; 236 219 drm_handle_vblank(dev, 0); 237 220 } 238 221 239 - if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) { 222 + if (pipeb_stats & vblank_status) { 240 223 vblank++; 241 224 drm_handle_vblank(dev, 1); 242 225 } ··· 261 244 * stray interrupts. 262 245 */ 263 246 iir = new_iir; 264 - } while (iir != 0); 247 + } 265 248 266 - return IRQ_HANDLED; 249 + return ret; 267 250 } 268 251 269 252 static int i915_emit_irq(struct drm_device * dev)