[v2] drm/i915: Recalculate FBC w/a stride when needed
diff mbox series

Message ID 20200711080336.13423-1-ville.syrjala@linux.intel.com
State New
Headers show
Series
  • [v2] drm/i915: Recalculate FBC w/a stride when needed
Related show

Commit Message

Ville Syrjälä July 11, 2020, 8:03 a.m. UTC
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(-)

Comments

Souza, Jose July 13, 2020, 9:15 p.m. UTC | #1
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;
> +			u64 modifier;
>  		} fb;
>  
>  		int cfb_size;

Patch
diff mbox series

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;