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

Chris Wilson chris at chris-wilson.co.uk
Mon Nov 13 21:03:34 UTC 2017


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()?

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


More information about the Intel-gfx mailing list