From: Ville Syrjälä ville.syrjala@linux.intel.com
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.
Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fbc.c | 29 ++++++++++++++++++------ 1 file changed, 22 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..ff199374ed36 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; @@ -1218,7 +1237,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 +1260,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));
From: Ville Syrjälä ville.syrjala@linux.intel.com
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
Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- 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;
On Sat, 2020-07-11 at 11:03 +0300, Ville Syrjala wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
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@intel.com
Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
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;
} fb;u64 modifier;
int cfb_size;
linux-stable-mirror@lists.linaro.org