On Mon, Feb 18, 2013 at 01:07:53PM +0100, Paul Menzel wrote: > Am Montag, den 18.02.2013, 13:57 +0200 schrieb ville.syrjala at linux.intel.com: > > From: Ville Syrj?l? <ville.syrjala at linux.intel.com> > > > > If the interrupt handler were to process a previous vblank interrupt and > > the following flip pending interrupt at the same time, the page flip > > would be complete too soon. > > ?would complete? or ?would be complete*d*? The second on is what I meant. Will fix. > > > To eliminate this race check the live pending flip status from the ISR > > register before finishing the page flip. > > Could this be tested somehow? Could a test case be written for this? It shouldn't be too difficult to force it from within the kernel. Just turn off interrupts before vblank start, wait until vblank start is passed, execute the MI_DISPLAY_FLIP, and finally turn the interrupts back on again. Given the timing constraints I'm not sure we can come up with anything that would realiably hit it otherwise. > > > Signed-off-by: Ville Syrj?l? <ville.syrjala at linux.intel.com> > > --- > > drivers/gpu/drm/i915/i915_irq.c | 21 +++++++++++++++------ > > 1 file changed, 15 insertions(+), 6 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > > index 9fde49a..3de570c 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,11 @@ 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]; > > + > > + if ((I915_READ(ISR) & flip[plane]) == 0) { > > Why not `I915_READ16`? It matches the rest if i915_irq_handler(). I suppose the interrupt registers were 16 bit on gen2 and 32 bit on gen3+. > > > + intel_finish_page_flip(dev, pipe); > > + flip_mask &= ~flip[plane]; > > + } > > } > > } > > > Thanks, > > Paul -- Ville Syrj?l? Intel OTC