drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 iir, new_iir;
        u32 pipea_stats, pipeb_stats;
+       u32 vblank_status;
+       u32 vblank_enable;
        int vblank = 0;
        unsigned long irqflags;
+       int irq_received;
+       int ret = IRQ_NONE;
 
        atomic_inc(&dev_priv->irq_received);
 
        iir = I915_READ(IIR);
 
-       if (iir == 0)
-               return IRQ_NONE;
+       if (IS_I965G(dev)) {
+               vblank_status = I915_START_VBLANK_INTERRUPT_STATUS;
+               vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE;
+       } else {
+               vblank_status = I915_VBLANK_INTERRUPT_STATUS;
+               vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
+       }
 
-       do {
-               pipea_stats = 0;
-               pipeb_stats = 0;
+       for (;;) {
+               irq_received = iir != 0;
+
+               /* Can't rely on pipestat interrupt bit in iir as it might
+                * have been cleared after the pipestat interrupt was received.
+                * It doesn't set the bit in iir again, but it still produces
+                * interrupts (for non-MSI).
+                */
+               spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+               pipea_stats = I915_READ(PIPEASTAT);
+               pipeb_stats = I915_READ(PIPEBSTAT);
                /*
                 * Clear the PIPE(A|B)STAT regs before the IIR
                 */
-               if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
-                       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-                       pipea_stats = I915_READ(PIPEASTAT);
+               if (pipea_stats & 0x8000ffff) {
                        I915_WRITE(PIPEASTAT, pipea_stats);
-                       spin_unlock_irqrestore(&dev_priv->user_irq_lock,
-                                              irqflags);
+                       irq_received = 1;
                }
 
-               if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
-                       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-                       pipeb_stats = I915_READ(PIPEBSTAT);
+               if (pipeb_stats & 0x8000ffff) {
                        I915_WRITE(PIPEBSTAT, pipeb_stats);
-                       spin_unlock_irqrestore(&dev_priv->user_irq_lock,
-                                              irqflags);
+                       irq_received = 1;
                }
+               spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+
+               if (!irq_received)
+                       break;
+
+               ret = IRQ_HANDLED;
 
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
                        DRM_WAKEUP(&dev_priv->irq_queue);
                }
 
-               if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) {
+               if (pipea_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 0);
                }
 
-               if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) {
+               if (pipeb_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 1);
                }
                 * stray interrupts.
                 */
                iir = new_iir;
-       } while (iir != 0);
+       }
 
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static int i915_emit_irq(struct drm_device * dev)