Commit 0428ab01 authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915: Recalculate FBC w/a stride when needed

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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200711080336.13423-1-ville.syrjala@linux.intel.comReviewed-by: default avatarJosé Roberto de Souza <jose.souza@intel.com>
parent a581483b
...@@ -742,6 +742,25 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv) ...@@ -742,6 +742,25 @@ static bool intel_fbc_cfb_size_changed(struct drm_i915_private *dev_priv)
fbc->compressed_fb.size * fbc->threshold; 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) static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv)
{ {
struct intel_fbc *fbc = &dev_priv->fbc; struct intel_fbc *fbc = &dev_priv->fbc;
...@@ -902,6 +921,7 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, ...@@ -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->crtc.i9xx_plane = to_intel_plane(crtc->base.primary)->i9xx_plane;
params->fb.format = cache->fb.format; params->fb.format = cache->fb.format;
params->fb.modifier = cache->fb.modifier;
params->fb.stride = cache->fb.stride; params->fb.stride = cache->fb.stride;
params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); 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) ...@@ -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) if (params->fb.format != cache->fb.format)
return false; return false;
if (params->fb.modifier != cache->fb.modifier)
return false;
if (params->fb.stride != cache->fb.stride) if (params->fb.stride != cache->fb.stride)
return false; return false;
...@@ -1218,7 +1241,8 @@ void intel_fbc_enable(struct intel_atomic_state *state, ...@@ -1218,7 +1241,8 @@ void intel_fbc_enable(struct intel_atomic_state *state,
if (fbc->crtc) { if (fbc->crtc) {
if (fbc->crtc != 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; goto out;
__intel_fbc_disable(dev_priv); __intel_fbc_disable(dev_priv);
...@@ -1240,12 +1264,7 @@ void intel_fbc_enable(struct intel_atomic_state *state, ...@@ -1240,12 +1264,7 @@ void intel_fbc_enable(struct intel_atomic_state *state,
goto out; goto out;
} }
if ((IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) && cache->gen9_wa_cfb_stride = intel_fbc_gen9_wa_cfb_stride(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;
drm_dbg_kms(&dev_priv->drm, "Enabling FBC on pipe %c\n", drm_dbg_kms(&dev_priv->drm, "Enabling FBC on pipe %c\n",
pipe_name(crtc->pipe)); pipe_name(crtc->pipe));
......
...@@ -442,6 +442,7 @@ struct intel_fbc { ...@@ -442,6 +442,7 @@ struct intel_fbc {
struct { struct {
const struct drm_format_info *format; const struct drm_format_info *format;
unsigned int stride; unsigned int stride;
u64 modifier;
} fb; } fb;
int cfb_size; int cfb_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment