aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c55
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
252static int i915_emit_irq(struct drm_device * dev) 269static int i915_emit_irq(struct drm_device * dev)