[Intel-gfx] [PATCH 1/2] drm/i915: Fix vblank timestamp/frame counter jumps on gen2

Ville Syrjälä ville.syrjala at linux.intel.com
Mon Nov 13 21:32:24 UTC 2017


On Mon, Nov 13, 2017 at 09:03:34PM +0000, Chris Wilson wrote:
> Quoting Ville Syrjala (2017-11-13 15:32:14)
> > From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> > 
> > Previously I was under the impression that the scanline counter
> > reads 0 when the pipe is off. Turns out that's not correct, and
> > instead the scanline counter simply stops when the pipe stops, and
> > it retains it's last value until the pipe starts up again, at which
> > point the scanline counter jumps to vblank start.
> > 
> > These jumps can cause the timestamp to jump backwards by one frame.
> > Since we use the timestamps to guesstimage also the frame counter
> > value on gen2, that would cause the frame counter to also jump
> > backwards, which leads to a massice difference from the previous value.
> > The end result is that flips/vblank events don't appear to complete as
> > they're stuck waiting for the frame counter to catch up to that massive
> > difference.
> > 
> > Fix the problem properly by actually making sure the scanline counter
> > has started to move before we assume that it's safe to enable vblank
> > processing.
> > 
> > Cc: stable at vger.kernel.org
> > Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
> > Fixes: b7792d8b54cc ("drm/i915: Wait for pipe to start before sampling vblank timestamps on gen2")
> > Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++++++++++++++------------
> >  1 file changed, 22 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 0ebf3f283b87..810b1147a0ac 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -998,7 +998,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
> >         return crtc->config->cpu_transcoder;
> >  }
> >  
> > -static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe)
> > +static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv,
> > +                            enum pipe pipe, bool stopped)
> >  {
> >         i915_reg_t reg = PIPEDSL(pipe);
> >         u32 line1, line2;
> > @@ -1013,7 +1014,7 @@ static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe)
> >         msleep(5);
> >         line2 = I915_READ(reg) & line_mask;
> >  
> > -       return line1 == line2;
> > +       return (line1 == line2) == stopped;
> >  }
> >  
> >  /*
> > @@ -1048,11 +1049,21 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
> >                         WARN(1, "pipe_off wait timed out\n");
> >         } else {
> >                 /* Wait for the display line to settle */
> > -               if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100))
> > +               if (wait_for(pipe_dsl_stopped(dev_priv, pipe, true), 100))
> >                         WARN(1, "pipe_off wait timed out\n");
> >         }
> >  }
> >  
> > +static void intel_wait_for_pipe_on(struct intel_crtc *crtc)
> > +{
> > +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +       enum pipe pipe = crtc->pipe;
> > +
> > +       /* Wait for the display line to start moving */
> > +       if (wait_for(pipe_dsl_stopped(dev_priv, pipe, false), 100))
> > +               WARN(1, "pipe_on wait timed out\n");
> 
> 3 wait_for(pipe_dsl_stopped()), please make a function to only have one
> expansion of that macro :)
> 
> > +}
> > +
> >  /* Only for pre-ILK configs */
> >  void assert_pll(struct drm_i915_private *dev_priv,
> >                 enum pipe pipe, bool state)
> > @@ -1935,15 +1946,14 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
> >         POSTING_READ(reg);
> >  
> >         /*
> > -        * Until the pipe starts DSL will read as 0, which would cause
> > -        * an apparent vblank timestamp jump, which messes up also the
> > -        * frame count when it's derived from the timestamps. So let's
> > -        * wait for the pipe to start properly before we call
> > -        * drm_crtc_vblank_on()
> > +        * Until the pipe starts DSL can give a bogus value, which cause
> > +        * an apparent vblank timestamp jump when the DSL resets to its
> > +        * proper value, which messes up also the frame count when it's
> > +        * derived from the timestamps. So let's wait for the pipe to
> > +        * start properly before we call drm_crtc_vblank_on()
> >          */
> > -       if (dev->max_vblank_count == 0 &&
> > -           wait_for(intel_get_crtc_scanline(crtc) != crtc->scanline_offset, 50))
> > -               DRM_ERROR("pipe %c didn't start\n", pipe_name(pipe));
> > +       if (dev->max_vblank_count == 0)
> > +               intel_wait_for_pipe_on(crtc);
> >  }
> >  
> >  /**
> > @@ -14707,7 +14717,7 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
> >         I915_WRITE(PIPECONF(pipe), 0);
> >         POSTING_READ(PIPECONF(pipe));
> >  
> > -       if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100))
> > +       if (wait_for(pipe_dsl_stopped(dev_priv, pipe, true), 100))
> >                 DRM_ERROR("pipe %c off wait timed out\n", pipe_name(pipe));
> 
> Is there a reason why we couldn't use intel_wait_for_pipe_off() here, it
> gives the clearer symmetry to intel_wait_for_pipe_on()?

In theory we could. However if we're being pedantic wait_for_pipe_off()
should be passed a crtc state since it wants to get at the
cpu_transcoder. It's not actually a problem on gen2 since we would
never take that codepath. However it feels a bit ugly.

What I could do is try to refactor these into a nicer form for the
case where we don't have the crtc state, and then handle the
cpu_transcoder case somewhere a bit higher up.

> 
> Other than nitpicks, the code does what it says on the tin, and it's
> pretty convincing in its argument,
> Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
> -Chris

-- 
Ville Syrjälä
Intel OTC


More information about the Intel-gfx mailing list