On Sat, 2020-07-11 at 11:03 +0300, Ville Syrjala wrote: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > Currently we're failing to recalculate the gen9 FBC w/a stride > unless something more drastic than just the modifier itself has > changed. This often leaves us with FBC enabled with the linear > fbdev framebuffer without the w/a stride enabled. That will cause > an immediate underrun and FBC will get promptly disabled. > > Fix the problem by checking if the w/a stride is about to change, > and go through the full dance if so. This part of the FBC code > is still pretty much a disaster and will need lots more work. > But this should at least fix the immediate issue. > > v2: Deactivate FBC when the modifier changes since that will > likely require resetting the w/a CFB stride Reviewed-by: José Roberto de Souza <jose.souza@xxxxxxxxx> > > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/display/intel_fbc.c | 33 +++++++++++++++++++----- > drivers/gpu/drm/i915/i915_drv.h | 1 + > 2 files changed, 27 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c > index ef2eb14f6157..85723fba6002 100644 > --- a/drivers/gpu/drm/i915/display/intel_fbc.c > +++ b/drivers/gpu/drm/i915/display/intel_fbc.c > @@ -742,6 +742,25 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv) > fbc->compressed_fb.size * fbc->threshold; > } > > +static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv) > +{ > + struct intel_fbc *fbc = &dev_priv->fbc; > + struct intel_fbc_state_cache *cache = &fbc->state_cache; > + > + if ((IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) && > + cache->fb.modifier != I915_FORMAT_MOD_X_TILED) > + return DIV_ROUND_UP(cache->plane.src_w, 32 * fbc->threshold) * 8; > + else > + return 0; > +} > + > +static bool intel_fbc_gen9_wa_cfb_stride_changed(struct drm_i915_private *dev_priv) > +{ > + struct intel_fbc *fbc = &dev_priv->fbc; > + > + return fbc->params.gen9_wa_cfb_stride != intel_fbc_gen9_wa_cfb_stride(dev_priv); > +} > + > static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv) > { > struct intel_fbc *fbc = &dev_priv->fbc; > @@ -902,6 +921,7 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, > params->crtc.i9xx_plane = to_intel_plane(crtc->base.primary)->i9xx_plane; > > params->fb.format = cache->fb.format; > + params->fb.modifier = cache->fb.modifier; > params->fb.stride = cache->fb.stride; > > params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); > @@ -931,6 +951,9 @@ static bool intel_fbc_can_flip_nuke(const struct intel_crtc_state *crtc_state) > if (params->fb.format != cache->fb.format) > return false; > > + if (params->fb.modifier != cache->fb.modifier) > + return false; > + > if (params->fb.stride != cache->fb.stride) > return false; > > @@ -1218,7 +1241,8 @@ void intel_fbc_enable(struct intel_atomic_state *state, > > if (fbc->crtc) { > if (fbc->crtc != crtc || > - !intel_fbc_cfb_size_changed(dev_priv)) > + (!intel_fbc_cfb_size_changed(dev_priv) && > + !intel_fbc_gen9_wa_cfb_stride_changed(dev_priv))) > goto out; > > __intel_fbc_disable(dev_priv); > @@ -1240,12 +1264,7 @@ void intel_fbc_enable(struct intel_atomic_state *state, > goto out; > } > > - if ((IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) && > - plane_state->hw.fb->modifier != I915_FORMAT_MOD_X_TILED) > - cache->gen9_wa_cfb_stride = > - DIV_ROUND_UP(cache->plane.src_w, 32 * fbc->threshold) * 8; > - else > - cache->gen9_wa_cfb_stride = 0; > + cache->gen9_wa_cfb_stride = intel_fbc_gen9_wa_cfb_stride(dev_priv); > > drm_dbg_kms(&dev_priv->drm, "Enabling FBC on pipe %c\n", > pipe_name(crtc->pipe)); > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 87973dedf8e7..14b095afab42 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -442,6 +442,7 @@ struct intel_fbc { > struct { > const struct drm_format_info *format; > unsigned int stride; > + u64 modifier; > } fb; > > int cfb_size;