diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9fde49a29999..6488249477db 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2284,8 +2284,11 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) drm_handle_vblank(dev, 0)) { if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 0); - intel_finish_page_flip(dev, 0); - flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + + if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) == 0) { + intel_finish_page_flip(dev, 0); + flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + } } } @@ -2293,8 +2296,11 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) drm_handle_vblank(dev, 1)) { if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 1); - intel_finish_page_flip(dev, 1); - flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + + if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) == 0) { + intel_finish_page_flip(dev, 1); + flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + } } } @@ -2491,8 +2497,17 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) drm_handle_vblank(dev, pipe)) { if (iir & flip[plane]) { intel_prepare_page_flip(dev, plane); - intel_finish_page_flip(dev, pipe); - flip_mask &= ~flip[plane]; + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise an + * interrupt per se, we watch for the change at vblank. + */ + if ((I915_READ(ISR) & flip[plane]) == 0) { + intel_finish_page_flip(dev, pipe); + flip_mask &= ~flip[plane]; + } } }