diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 654d42fabec8..c3673581db58 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -170,37 +170,54 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
170 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 170 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
171 | u32 iir, new_iir; | 171 | u32 iir, new_iir; |
172 | u32 pipea_stats, pipeb_stats; | 172 | u32 pipea_stats, pipeb_stats; |
173 | u32 vblank_status; | ||
174 | u32 vblank_enable; | ||
173 | int vblank = 0; | 175 | int vblank = 0; |
174 | unsigned long irqflags; | 176 | unsigned long irqflags; |
177 | int irq_received; | ||
178 | int ret = IRQ_NONE; | ||
175 | 179 | ||
176 | atomic_inc(&dev_priv->irq_received); | 180 | atomic_inc(&dev_priv->irq_received); |
177 | 181 | ||
178 | iir = I915_READ(IIR); | 182 | iir = I915_READ(IIR); |
179 | 183 | ||
180 | if (iir == 0) | 184 | if (IS_I965G(dev)) { |
181 | return IRQ_NONE; | 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 { | 192 | for (;;) { |
184 | pipea_stats = 0; | 193 | irq_received = iir != 0; |
185 | pipeb_stats = 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 | * Clear the PIPE(A|B)STAT regs before the IIR | 204 | * Clear the PIPE(A|B)STAT regs before the IIR |
188 | */ | 205 | */ |
189 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { | 206 | if (pipea_stats & 0x8000ffff) { |
190 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
191 | pipea_stats = I915_READ(PIPEASTAT); | ||
192 | I915_WRITE(PIPEASTAT, pipea_stats); | 207 | I915_WRITE(PIPEASTAT, pipea_stats); |
193 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, | 208 | irq_received = 1; |
194 | irqflags); | ||
195 | } | 209 | } |
196 | 210 | ||
197 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | 211 | if (pipeb_stats & 0x8000ffff) { |
198 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
199 | pipeb_stats = I915_READ(PIPEBSTAT); | ||
200 | I915_WRITE(PIPEBSTAT, pipeb_stats); | 212 | I915_WRITE(PIPEBSTAT, pipeb_stats); |
201 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, | 213 | irq_received = 1; |
202 | irqflags); | ||
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 | I915_WRITE(IIR, iir); | 222 | I915_WRITE(IIR, iir); |
206 | new_iir = I915_READ(IIR); /* Flush posted writes */ | 223 | new_iir = I915_READ(IIR); /* Flush posted writes */ |
@@ -214,12 +231,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
214 | DRM_WAKEUP(&dev_priv->irq_queue); | 231 | DRM_WAKEUP(&dev_priv->irq_queue); |
215 | } | 232 | } |
216 | 233 | ||
217 | if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) { | 234 | if (pipea_stats & vblank_status) { |
218 | vblank++; | 235 | vblank++; |
219 | drm_handle_vblank(dev, 0); | 236 | drm_handle_vblank(dev, 0); |
220 | } | 237 | } |
221 | 238 | ||
222 | if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) { | 239 | if (pipeb_stats & vblank_status) { |
223 | vblank++; | 240 | vblank++; |
224 | drm_handle_vblank(dev, 1); | 241 | drm_handle_vblank(dev, 1); |
225 | } | 242 | } |
@@ -244,9 +261,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
244 | * stray interrupts. | 261 | * stray interrupts. |
245 | */ | 262 | */ |
246 | iir = new_iir; | 263 | iir = new_iir; |
247 | } while (iir != 0); | 264 | } |
248 | 265 | ||
249 | return IRQ_HANDLED; | 266 | return ret; |
250 | } | 267 | } |
251 | 268 | ||
252 | static int i915_emit_irq(struct drm_device * dev) | 269 | static int i915_emit_irq(struct drm_device * dev) |