intel-gfx.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* FBC patchset
@ 2011-07-08 11:22 Chris Wilson
  2011-07-08 11:22 ` [PATCH 1/8] drm/i915: Only export the generic intel_disable_fbc() interface Chris Wilson
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

This is hopefully the culimination of yesterday's patches and review. I
pulled in Jesse's comments about needing to be sure that the tasklet was
not running on module unload and after several prods by Keith, we have
safely eliminated any potential blocking waits on vblank when changing
FBC configurations. As always further feedback is welcome. The one
remaining question I have is over the use of 50ms as the delay interval.
It was a value that was just sufficiently large enough to cover
page-flipping, but maybe we are better with a less agressive 100ms for
the purposes of "letting the display settle" before compressing the
scanout?
-Chris

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/8] drm/i915: Only export the generic intel_disable_fbc() interface
  2011-07-08 11:22 FBC patchset Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 2/8] drm/i915: Replace direct calls to vfunc.disable_fbc with intel_disable_fbc() Chris Wilson
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

As the enable/disable routines will be gain additional complexity in
future patches, it is necessary that all callers do not bypass the
generic interface by calling into the chipset routines directly. to do
this we make the chipset routines static, so there is no choice.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_dma.c      |    4 ++-
 drivers/gpu/drm/i915/i915_drv.h      |    6 +---
 drivers/gpu/drm/i915/i915_suspend.c  |    4 +--
 drivers/gpu/drm/i915/intel_display.c |   50 +++++++++++++++++-----------------
 4 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index e178702..1315a88 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1073,6 +1073,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
 	unsigned long cfb_base;
 	unsigned long ll_base = 0;
 
+	/* Just in case the BIOS is doing something questionable. */
+	intel_disable_fbc(dev);
+
 	compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
 	if (compressed_fb)
 		compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
@@ -1099,7 +1102,6 @@ static void i915_setup_compression(struct drm_device *dev, int size)
 
 	dev_priv->cfb_size = size;
 
-	intel_disable_fbc(dev);
 	dev_priv->compressed_fb = compressed_fb;
 	if (HAS_PCH_SPLIT(dev))
 		I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a15f2c0..56cb1c4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1289,12 +1289,8 @@ extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
-extern void i8xx_disable_fbc(struct drm_device *dev);
-extern void g4x_disable_fbc(struct drm_device *dev);
-extern void ironlake_disable_fbc(struct drm_device *dev);
-extern void intel_disable_fbc(struct drm_device *dev);
-extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
 extern bool intel_fbc_enabled(struct drm_device *dev);
+extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void ironlake_enable_rc6(struct drm_device *dev);
 extern void gen6_set_rps(struct drm_device *dev, u8 val);
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 8cd1c8b..2857586 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -760,15 +760,13 @@ static void i915_restore_display(struct drm_device *dev)
 	/* FIXME: restore TV & SDVO state */
 
 	/* only restore FBC info on the platform that supports FBC*/
+	intel_disable_fbc(dev);
 	if (I915_HAS_FBC(dev)) {
 		if (HAS_PCH_SPLIT(dev)) {
-			ironlake_disable_fbc(dev);
 			I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
 		} else if (IS_GM45(dev)) {
-			g4x_disable_fbc(dev);
 			I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
 		} else {
-			i8xx_disable_fbc(dev);
 			I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
 			I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
 			I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index af3e581..0923611 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1384,6 +1384,28 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
 	disable_pch_hdmi(dev_priv, pipe, HDMID);
 }
 
+static void i8xx_disable_fbc(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 fbc_ctl;
+
+	/* Disable compression */
+	fbc_ctl = I915_READ(FBC_CONTROL);
+	if ((fbc_ctl & FBC_CTL_EN) == 0)
+		return;
+
+	fbc_ctl &= ~FBC_CTL_EN;
+	I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+	/* Wait for compressing bit to clear */
+	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
+		DRM_DEBUG_KMS("FBC idle timed out\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("disabled FBC\n");
+}
+
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1439,28 +1461,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 		      dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
-void i8xx_disable_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 fbc_ctl;
-
-	/* Disable compression */
-	fbc_ctl = I915_READ(FBC_CONTROL);
-	if ((fbc_ctl & FBC_CTL_EN) == 0)
-		return;
-
-	fbc_ctl &= ~FBC_CTL_EN;
-	I915_WRITE(FBC_CONTROL, fbc_ctl);
-
-	/* Wait for compressing bit to clear */
-	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
-		DRM_DEBUG_KMS("FBC idle timed out\n");
-		return;
-	}
-
-	DRM_DEBUG_KMS("disabled FBC\n");
-}
-
 static bool i8xx_fbc_enabled(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1516,7 +1516,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
 
-void g4x_disable_fbc(struct drm_device *dev)
+static void g4x_disable_fbc(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpfc_ctl;
@@ -1616,7 +1616,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
 
-void ironlake_disable_fbc(struct drm_device *dev)
+static void ironlake_disable_fbc(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpfc_ctl;
@@ -1648,7 +1648,7 @@ bool intel_fbc_enabled(struct drm_device *dev)
 	return dev_priv->display.fbc_enabled(dev);
 }
 
-void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
 	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/8] drm/i915: Replace direct calls to vfunc.disable_fbc with intel_disable_fbc()
  2011-07-08 11:22 FBC patchset Chris Wilson
  2011-07-08 11:22 ` [PATCH 1/8] drm/i915: Only export the generic intel_disable_fbc() interface Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines Chris Wilson
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

...to ensure that any pending FBC enable tasklet is cancelled.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c |   13 +++++--------
 1 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0923611..ab78dfd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2820,9 +2820,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
 	intel_disable_plane(dev_priv, plane, pipe);
 
-	if (dev_priv->cfb_plane == plane &&
-	    dev_priv->display.disable_fbc)
-		dev_priv->display.disable_fbc(dev);
+	if (dev_priv->cfb_plane == plane)
+		intel_disable_fbc(dev);
 
 	intel_disable_pipe(dev_priv, pipe);
 
@@ -2986,9 +2985,8 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 	intel_crtc_dpms_overlay(intel_crtc, false);
 	intel_crtc_update_cursor(crtc, false);
 
-	if (dev_priv->cfb_plane == plane &&
-	    dev_priv->display.disable_fbc)
-		dev_priv->display.disable_fbc(dev);
+	if (dev_priv->cfb_plane == plane)
+		intel_disable_fbc(dev);
 
 	intel_disable_plane(dev_priv, plane, pipe);
 	intel_disable_pipe(dev_priv, pipe);
@@ -8217,8 +8215,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 		intel_increase_pllclock(crtc);
 	}
 
-	if (dev_priv->display.disable_fbc)
-		dev_priv->display.disable_fbc(dev);
+	intel_disable_fbc(dev);
 
 	if (IS_IRONLAKE_M(dev))
 		ironlake_disable_drps(dev);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines
  2011-07-08 11:22 FBC patchset Chris Wilson
  2011-07-08 11:22 ` [PATCH 1/8] drm/i915: Only export the generic intel_disable_fbc() interface Chris Wilson
  2011-07-08 11:22 ` [PATCH 2/8] drm/i915: Replace direct calls to vfunc.disable_fbc with intel_disable_fbc() Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 17:20   ` Keith Packard
  2011-07-08 11:22 ` [PATCH 4/8] drm/i915: Use of a CPU fence is mandatory to update FBC regions upon CPU writes Chris Wilson
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

The cfb_pitch was only used for 8xx_enable_fbc(), every later routine
was just overwriting the value with itself thanks to a copy'n'paste
error.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ab78dfd..5c359e5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1482,8 +1482,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
 	dpfc_ctl = I915_READ(DPFC_CONTROL);
 	if (dpfc_ctl & DPFC_CTL_EN) {
-		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
-		    dev_priv->cfb_fence == obj->fence_reg &&
+		if (dev_priv->cfb_fence == obj->fence_reg &&
 		    dev_priv->cfb_plane == intel_crtc->plane &&
 		    dev_priv->cfb_y == crtc->y)
 			return;
@@ -1492,7 +1491,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 		intel_wait_for_vblank(dev, intel_crtc->pipe);
 	}
 
-	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
 	dev_priv->cfb_y = crtc->y;
@@ -1572,8 +1570,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
 	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
 	if (dpfc_ctl & DPFC_CTL_EN) {
-		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
-		    dev_priv->cfb_fence == obj->fence_reg &&
+		if (dev_priv->cfb_fence == obj->fence_reg &&
 		    dev_priv->cfb_plane == intel_crtc->plane &&
 		    dev_priv->cfb_offset == obj->gtt_offset &&
 		    dev_priv->cfb_y == crtc->y)
@@ -1583,7 +1580,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 		intel_wait_for_vblank(dev, intel_crtc->pipe);
 	}
 
-	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
 	dev_priv->cfb_offset = obj->gtt_offset;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/8] drm/i915: Use of a CPU fence is mandatory to update FBC regions upon CPU writes
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (2 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 5/8] drm/i915: Set persistent-mode for ILK/SNB framebuffer compression Chris Wilson
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

...and this requirement is enforced by intel_update_fbc() so we can
remove the later check from g4x_enable_fbc() and ironlake_enable_fbc().

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |   33 ++++++++++++++-------------------
 1 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5c359e5..31c7526 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1441,9 +1441,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 		I915_WRITE(FBC_TAG + (i * 4), 0);
 
 	/* Set it up... */
-	fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane;
-	if (obj->tiling_mode != I915_TILING_NONE)
-		fbc_ctl2 |= FBC_CTL_CPU_FENCE;
+	fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
+	fbc_ctl2 |= plane;
 	I915_WRITE(FBC_CONTROL2, fbc_ctl2);
 	I915_WRITE(FBC_FENCE_OFF, crtc->y);
 
@@ -1453,8 +1452,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 		fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
 	fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
 	fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
-	if (obj->tiling_mode != I915_TILING_NONE)
-		fbc_ctl |= dev_priv->cfb_fence;
+	fbc_ctl |= dev_priv->cfb_fence;
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
 	DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
@@ -1496,12 +1494,8 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	dev_priv->cfb_y = crtc->y;
 
 	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
-	if (obj->tiling_mode != I915_TILING_NONE) {
-		dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
-		I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
-	} else {
-		I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
-	}
+	dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
+	I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
 
 	I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
@@ -1587,12 +1581,8 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
 	dpfc_ctl &= DPFC_RESERVED;
 	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
-	if (obj->tiling_mode != I915_TILING_NONE) {
-		dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
-		I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
-	} else {
-		I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
-	}
+	dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
+	I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 
 	I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
@@ -1760,8 +1750,13 @@ static void intel_update_fbc(struct drm_device *dev)
 		dev_priv->no_fbc_reason = FBC_BAD_PLANE;
 		goto out_disable;
 	}
-	if (obj->tiling_mode != I915_TILING_X) {
-		DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
+
+	/* The use of a CPU fence is mandatory in order to detect writes
+	 * by the CPU to the scanout and trigger updates to the FBC.
+	 */
+	if (obj->tiling_mode != I915_TILING_X ||
+	    obj->fence_reg == I915_FENCE_REG_NONE) {
+		DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
 		dev_priv->no_fbc_reason = FBC_NOT_TILED;
 		goto out_disable;
 	}
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/8] drm/i915: Set persistent-mode for ILK/SNB framebuffer compression
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (3 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 4/8] drm/i915: Use of a CPU fence is mandatory to update FBC regions upon CPU writes Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 6/8] drm/i915: Disable FBC across page-flipping Chris Wilson
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

Persistent mode is intended for use with front-buffer rendering, such as
X, where it is necessary to detect writes to the scanout either by the
GPU or through the CPU's fence, and recompress the dirty regions on the
fly. (By comparison to the back-buffer rendering, the scanout is always
recompressed after a page-flip.)

References: https://bugs.freedesktop.org/show_bug.cgi?id=33487
References: https://bugs.freedesktop.org/show_bug.cgi?id=31742
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_reg.h      |    1 +
 drivers/gpu/drm/i915/intel_display.c |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4a446b1..96fb0fa 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -579,6 +579,7 @@
 #define   DPFC_CTL_PLANEA	(0<<30)
 #define   DPFC_CTL_PLANEB	(1<<30)
 #define   DPFC_CTL_FENCE_EN	(1<<29)
+#define   DPFC_CTL_PERSISTENT_MODE	(1<<25)
 #define   DPFC_SR_EN		(1<<10)
 #define   DPFC_CTL_LIMIT_1X	(0<<6)
 #define   DPFC_CTL_LIMIT_2X	(1<<6)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 31c7526..9df96bd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1581,6 +1581,8 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
 	dpfc_ctl &= DPFC_RESERVED;
 	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
+	/* Set persistent mode for front-buffer rendering, ala X. */
+	dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
 	dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
 	I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/8] drm/i915: Disable FBC across page-flipping
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (4 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 5/8] drm/i915: Set persistent-mode for ILK/SNB framebuffer compression Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 7/8] drm/i915: Perform intel_enable_fbc() from a delayed task Chris Wilson
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

Page-flipping updates the scanout address, nukes the FBC compressed
image and so forces an FBC update so that the displayed image remains
consistent. However, page-flipping does not update the FBC registers
themselves, which remain pointing to both the old address and the old
CPU fence. Future updates to the new front-buffer (scanout) are then
undetected!

This first approach to demonstrate the issue and highlight the fix,
simply disables FBC upon page-flip (a recompression will be forced on
every flip so FBC becomes immaterial) and then re-enables FBC in the
page-flip finish work function, so that the FBC registers are now
pointing to the new framebuffer and front-buffer rendering works once
more.

Ideally, we want to only re-enable FBC after page-flipping is complete,
as otherwise we are just wasting cycles and power (with needless
recompression) whilst the page-flipping application is still running.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=33487
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9df96bd..f0788a9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6333,6 +6333,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	drm_gem_object_unreference(&work->pending_flip_obj->base);
 	drm_gem_object_unreference(&work->old_fb_obj->base);
 
+	intel_update_fbc(work->dev);
 	mutex_unlock(&work->dev->struct_mutex);
 	kfree(work);
 }
@@ -6697,6 +6698,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (ret)
 		goto cleanup_pending;
 
+	intel_disable_fbc(dev);
 	mutex_unlock(&dev->struct_mutex);
 
 	trace_i915_flip_request(intel_crtc->plane, obj);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 7/8] drm/i915: Perform intel_enable_fbc() from a delayed task
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (5 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 6/8] drm/i915: Disable FBC across page-flipping Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 11:22 ` [PATCH 8/8] drm/i915: Share the common work of disabling active FBC before updating Chris Wilson
  2011-07-08 19:43 ` FBC patchset Chris Wilson
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

In order to accommodate the requirements of re-enabling FBC after
page-flipping, but to avoid doing so and incurring the cost of a wait
for vblank in the middle of a page-flip sequence, we defer the actual
enablement by 50ms. If any request to disable FBC arrive within that
interval, the enablement is cancelled and we are saved from blocking on
the wait.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 +
 drivers/gpu/drm/i915/intel_display.c |   83 +++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h     |    7 +++
 3 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 56cb1c4..3154b3d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -266,6 +266,7 @@ enum intel_pch {
 #define QUIRK_PIPEA_FORCE (1<<0)
 
 struct intel_fbdev;
+struct intel_fbc_work;
 
 typedef struct drm_i915_private {
 	struct drm_device *dev;
@@ -335,6 +336,7 @@ typedef struct drm_i915_private {
 	int cfb_fence;
 	int cfb_plane;
 	int cfb_y;
+	struct intel_fbc_work *fbc_work;
 
 	struct intel_opregion opregion;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f0788a9..df2839c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1636,20 +1636,96 @@ bool intel_fbc_enabled(struct drm_device *dev)
 	return dev_priv->display.fbc_enabled(dev);
 }
 
+static void intel_fbc_work_fn(struct work_struct *__work)
+{
+	struct intel_fbc_work *work =
+		container_of(to_delayed_work(__work),
+			     struct intel_fbc_work, work);
+	struct drm_device *dev = work->crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev->struct_mutex);
+	if (work == dev_priv->fbc_work) {
+		/* Double check that we haven't switched fb without cancelling
+		 * the prior work.
+		 */
+		if (work->crtc->fb == work->fb)
+			dev_priv->display.enable_fbc(work->crtc,
+						     work->interval);
+
+		dev_priv->fbc_work = NULL;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(work);
+}
+
+static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
+{
+	if (dev_priv->fbc_work == NULL)
+		return;
+
+	DRM_DEBUG_KMS("cancelling pending FBC enable\n");
+
+	/* Synchronisation is provided by struct_mutex and checking of
+	 * dev_priv->fbc_work, so we can perform the cancellation
+	 * entirely asynchronously.
+	 */
+	if (cancel_delayed_work(&dev_priv->fbc_work->work))
+		/* tasklet was killed before being run, clean up */
+		kfree(dev_priv->fbc_work);
+
+	/* Mark the work as no longer wanted so that if it does
+	 * wake-up (because the work was already running and waiting
+	 * for our mutex), it will discover that is no longer
+	 * necessary to run.
+	 */
+	dev_priv->fbc_work = NULL;
+}
+
 static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
-	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	struct intel_fbc_work *work;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (!dev_priv->display.enable_fbc)
 		return;
 
-	dev_priv->display.enable_fbc(crtc, interval);
+	intel_cancel_fbc_work(dev_priv);
+
+	work = kzalloc(sizeof *work, GFP_KERNEL);
+	if (work == NULL) {
+		dev_priv->display.enable_fbc(crtc, interval);
+		return;
+	}
+
+	work->crtc = crtc;
+	work->fb = crtc->fb;
+	work->interval = interval;
+	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
+
+	dev_priv->fbc_work = work;
+
+	DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
+
+	/* Delay the actual enabling to let pageflipping cease and the
+	 * display to settle before starting the compression.
+	 *
+	 * A more complicated solution would involve tracking vblanks
+	 * following the termination of the page-flipping sequence
+	 * and indeed performing the enable as a co-routine and not
+	 * waiting synchronously upon the vblank.
+	 */
+	schedule_delayed_work(&work->work, msecs_to_jiffies(50));
 }
 
 void intel_disable_fbc(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	intel_cancel_fbc_work(dev_priv);
+
 	if (!dev_priv->display.disable_fbc)
 		return;
 
@@ -8227,6 +8303,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
 	drm_irq_uninstall(dev);
 	cancel_work_sync(&dev_priv->hotplug_work);
 
+	/* flush any delayed tasks or pending work */
+	flush_scheduled_work();
+
 	/* Shut off idle work before the crtcs get freed. */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		intel_crtc = to_intel_crtc(crtc);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7ec48d8..6e990f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -234,6 +234,13 @@ struct intel_unpin_work {
 	bool enable_stall_check;
 };
 
+struct intel_fbc_work {
+	struct delayed_work work;
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+	int interval;
+};
+
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 8/8] drm/i915: Share the common work of disabling active FBC before updating
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (6 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 7/8] drm/i915: Perform intel_enable_fbc() from a delayed task Chris Wilson
@ 2011-07-08 11:22 ` Chris Wilson
  2011-07-08 19:43 ` FBC patchset Chris Wilson
  8 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 11:22 UTC (permalink / raw)
  To: intel-gfx

Upon review, all path share the same dependencies for updating the
registers and so we can benefit from sharing the code and checking
early.

This removes the unsightly intel_wait_for_vblank() from the lowlevel
functions and upon further analysis the only path that will require a
wait is if we are performing an instantaneous transition between two
valid FBC configurations. The page-flip path itself will have disabled
FBC registers and will have waited for at least one vblank before
finishing the flip and attempting to re-enable FBC. This wait can be
accomplished simply by delaying the enable until after we are sure that
a vblank will have passed, which we are already doing to make sure that
the display is settled before enabling FBC.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Keith Packard <keithp@keithp.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |    6 +-
 drivers/gpu/drm/i915/intel_display.c |  118 ++++++++++++++++++----------------
 2 files changed, 64 insertions(+), 60 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3154b3d..00dc59a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -331,10 +331,8 @@ typedef struct drm_i915_private {
 	uint32_t last_instdone1;
 
 	unsigned long cfb_size;
-	unsigned long cfb_pitch;
-	unsigned long cfb_offset;
-	int cfb_fence;
-	int cfb_plane;
+	unsigned int cfb_fb;
+	enum plane cfb_plane;
 	int cfb_y;
 	struct intel_fbc_work *fbc_work;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index df2839c..b5b15bd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1414,27 +1414,17 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int cfb_pitch;
 	int plane, i;
 	u32 fbc_ctl, fbc_ctl2;
 
-	if (fb->pitch == dev_priv->cfb_pitch &&
-	    obj->fence_reg == dev_priv->cfb_fence &&
-	    intel_crtc->plane == dev_priv->cfb_plane &&
-	    I915_READ(FBC_CONTROL) & FBC_CTL_EN)
-		return;
-
-	i8xx_disable_fbc(dev);
-
-	dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
-
-	if (fb->pitch < dev_priv->cfb_pitch)
-		dev_priv->cfb_pitch = fb->pitch;
+	cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
+	if (fb->pitch < cfb_pitch)
+		cfb_pitch = fb->pitch;
 
 	/* FBC_CTL wants 64B units */
-	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
-	dev_priv->cfb_fence = obj->fence_reg;
-	dev_priv->cfb_plane = intel_crtc->plane;
-	plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
+	cfb_pitch = (cfb_pitch / 64) - 1;
+	plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
 
 	/* Clear old tags */
 	for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
@@ -1450,13 +1440,13 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
 	if (IS_I945GM(dev))
 		fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
-	fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
+	fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
 	fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
-	fbc_ctl |= dev_priv->cfb_fence;
+	fbc_ctl |= obj->fence_reg;
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
-	DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-		      dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
+		      cfb_pitch, crtc->y, intel_crtc->plane);
 }
 
 static bool i8xx_fbc_enabled(struct drm_device *dev)
@@ -1478,23 +1468,8 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	unsigned long stall_watermark = 200;
 	u32 dpfc_ctl;
 
-	dpfc_ctl = I915_READ(DPFC_CONTROL);
-	if (dpfc_ctl & DPFC_CTL_EN) {
-		if (dev_priv->cfb_fence == obj->fence_reg &&
-		    dev_priv->cfb_plane == intel_crtc->plane &&
-		    dev_priv->cfb_y == crtc->y)
-			return;
-
-		I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
-	}
-
-	dev_priv->cfb_fence = obj->fence_reg;
-	dev_priv->cfb_plane = intel_crtc->plane;
-	dev_priv->cfb_y = crtc->y;
-
 	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
-	dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
+	dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
 	I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
 
 	I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
@@ -1563,27 +1538,11 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	u32 dpfc_ctl;
 
 	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-	if (dpfc_ctl & DPFC_CTL_EN) {
-		if (dev_priv->cfb_fence == obj->fence_reg &&
-		    dev_priv->cfb_plane == intel_crtc->plane &&
-		    dev_priv->cfb_offset == obj->gtt_offset &&
-		    dev_priv->cfb_y == crtc->y)
-			return;
-
-		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
-	}
-
-	dev_priv->cfb_fence = obj->fence_reg;
-	dev_priv->cfb_plane = intel_crtc->plane;
-	dev_priv->cfb_offset = obj->gtt_offset;
-	dev_priv->cfb_y = crtc->y;
-
 	dpfc_ctl &= DPFC_RESERVED;
 	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
 	/* Set persistent mode for front-buffer rendering, ala X. */
 	dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
-	dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
+	dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
 	I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 
 	I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
@@ -1596,7 +1555,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
 	if (IS_GEN6(dev)) {
 		I915_WRITE(SNB_DPFC_CTL_SA,
-			   SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence);
+			   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
 		I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
 		sandybridge_blit_fbc_update(dev);
 	}
@@ -1649,10 +1608,15 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 		/* Double check that we haven't switched fb without cancelling
 		 * the prior work.
 		 */
-		if (work->crtc->fb == work->fb)
+		if (work->crtc->fb == work->fb) {
 			dev_priv->display.enable_fbc(work->crtc,
 						     work->interval);
 
+			dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
+			dev_priv->cfb_fb = work->crtc->fb->base.id;
+			dev_priv->cfb_y = work->crtc->y;
+		}
+
 		dev_priv->fbc_work = NULL;
 	}
 	mutex_unlock(&dev->struct_mutex);
@@ -1710,7 +1674,10 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
 
 	/* Delay the actual enabling to let pageflipping cease and the
-	 * display to settle before starting the compression.
+	 * display to settle before starting the compression. Note that
+	 * this delay also serves a second purpose: it allows for a
+	 * vblank to pass after disabling the FBC before we attempt
+	 * to modify the control registers.
 	 *
 	 * A more complicated solution would involve tracking vblanks
 	 * following the termination of the page-flipping sequence
@@ -1730,6 +1697,7 @@ void intel_disable_fbc(struct drm_device *dev)
 		return;
 
 	dev_priv->display.disable_fbc(dev);
+	dev_priv->cfb_plane = -1;
 }
 
 /**
@@ -1843,6 +1811,44 @@ static void intel_update_fbc(struct drm_device *dev)
 	if (in_dbg_master())
 		goto out_disable;
 
+	/* If the scanout has not changed, don't modify the FBC settings.
+	 * Note that we make the fundamental assumption that the fb->obj
+	 * cannot be unpinned (and have its GTT offset and fence revoked)
+	 * without first being decoupled from the scanout and FBC disabled.
+	 */
+	if (dev_priv->cfb_plane == intel_crtc->plane &&
+	    dev_priv->cfb_fb == fb->base.id &&
+	    dev_priv->cfb_y == crtc->y)
+		return;
+
+	if (intel_fbc_enabled(dev)) {
+		/* We update FBC along two paths, after changing fb/crtc
+		 * configuration (modeswitching) and after page-flipping
+		 * finishes. For the latter, we know that not only did
+		 * we disable the FBC at the start of the page-flip
+		 * sequence, but also more than one vblank has passed.
+		 *
+		 * For the former case of modeswitching, it is possible
+		 * to switch between two FBC valid configurations
+		 * instantaneously so we do need to disable the FBC
+		 * before we can modify its control registers. We also
+		 * have to wait for the next vblank for that to take
+		 * effect. However, since we delay enabling FBC we can
+		 * assume that a vblank has passed since disabling and
+		 * that we can safely alter the registers in the deferred
+		 * callback.
+		 *
+		 * In the scenario that we go from a valid to invalid
+		 * and then back to valid FBC configuration we have
+		 * no strict enforcement that a vblank occurred since
+		 * disabling the FBC. However, along all current pipe
+		 * disabling paths we do need to wait for a vblank at
+		 * some point. And we wait before enabling FBC anyway.
+		 */
+		DRM_DEBUG_KMS("disabling active FBC for update\n");
+		intel_disable_fbc(dev);
+	}
+
 	intel_enable_fbc(crtc, 500);
 	return;
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines
  2011-07-08 11:22 ` [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines Chris Wilson
@ 2011-07-08 17:20   ` Keith Packard
  0 siblings, 0 replies; 17+ messages in thread
From: Keith Packard @ 2011-07-08 17:20 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 227 bytes --]

On Fri,  8 Jul 2011 12:22:38 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:

> -		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&

That one was gonna be hard to satisfy...

-- 
keith.packard@intel.com

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 11:22 FBC patchset Chris Wilson
                   ` (7 preceding siblings ...)
  2011-07-08 11:22 ` [PATCH 8/8] drm/i915: Share the common work of disabling active FBC before updating Chris Wilson
@ 2011-07-08 19:43 ` Chris Wilson
  2011-07-08 20:00   ` Keith Packard
  2012-01-17 16:18   ` Daniel Vetter
  8 siblings, 2 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 19:43 UTC (permalink / raw)
  To: intel-gfx

Oh dear, it was all looking too good. Works fine with just one output.
Runs into a nasty race if you add a second and start unplugging things...

The issue is that when unplugging an output, userspace sees this and
appropriately reconfigures from an extended desktop to just using, for the
sake of argument, the LVDS. As the desktop is changing size this requires
a new framebuffer and so we begin to teardown the two crtcs and replace
with just the one with the new fb. The first thing we do is disable the
crtc connected to the unplugged display. This triggers an
intel_update_fbc() which spots that it can now enable FBC on the current
single crtc + old fb and promptly dispatches a delayed task to do so.

The mode reconfiguration continues apace and we disable the other crtc and
start to replace the plane's FB. This involves a couple of
wait-for-vblanks, and so is quite slow. During this time we avoid taking
the struct_mutex. Meanwhile, the delayed task kicks off on a second CPU
grabs the struct_mutex and reconfigures the FBC registers. Apparently
enabling FBC on a dead plane is an undefined operation. Hilarity ensues,
followed by a swift reboot.

Bumping to 250ms sufficiently delays the task to miss the race, but we
can not foretell just how long any given crtc modeset will take. So what
we need is to take the mode_config.lock in order to prevent concurrent
access to the FBC registers and also to prevent the fb from disappearing
beneath us:

---
 drivers/gpu/drm/i915/intel_display.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e375500..bec9e1d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1603,6 +1603,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 	struct drm_device *dev = work->crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	if (!mutex_trylock(&dev->mode_config.mutex)) {
+		schedule_delayed_work(&work->work, msecs_to_jiffies(100));
+		return;
+	}
+
 	mutex_lock(&dev->struct_mutex);
 	if (work == dev_priv->fbc_work) {
 		/* Double check that we haven't switched fb without cancelling
@@ -1620,6 +1625,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 		dev_priv->fbc_work = NULL;
 	}
 	mutex_unlock(&dev->struct_mutex);
+	mutex_unlock(&dev->mode_config.mutex);
 
 	kfree(work);
 }
@@ -1684,7 +1690,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 	 * and indeed performing the enable as a co-routine and not
 	 * waiting synchronously upon the vblank.
 	 */
-	schedule_delayed_work(&work->work, msecs_to_jiffies(50));
+	schedule_delayed_work(&work->work, msecs_to_jiffies(250));
 }
 
 void intel_disable_fbc(struct drm_device *dev)
-- 
1.7.6

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 19:43 ` FBC patchset Chris Wilson
@ 2011-07-08 20:00   ` Keith Packard
  2011-07-08 20:19     ` Chris Wilson
  2012-01-17 16:18   ` Daniel Vetter
  1 sibling, 1 reply; 17+ messages in thread
From: Keith Packard @ 2011-07-08 20:00 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 577 bytes --]

On Fri, 08 Jul 2011 20:43:47 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:

> Bumping to 250ms sufficiently delays the task to miss the race, but we
> can not foretell just how long any given crtc modeset will take. So what
> we need is to take the mode_config.lock in order to prevent concurrent
> access to the FBC registers and also to prevent the fb from disappearing
> beneath us:

Sounds like we also need to push out any FBC reconfiguration anytime
modesetting occurs to ensure that we've waited past a vblank interval?

-- 
keith.packard@intel.com

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 20:00   ` Keith Packard
@ 2011-07-08 20:19     ` Chris Wilson
  2011-07-08 21:28       ` Keith Packard
  0 siblings, 1 reply; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 20:19 UTC (permalink / raw)
  To: Keith Packard, intel-gfx

On Fri, 08 Jul 2011 13:00:09 -0700, Keith Packard <keithp@keithp.com> wrote:
> On Fri, 08 Jul 2011 20:43:47 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> 
> > Bumping to 250ms sufficiently delays the task to miss the race, but we
> > can not foretell just how long any given crtc modeset will take. So what
> > we need is to take the mode_config.lock in order to prevent concurrent
> > access to the FBC registers and also to prevent the fb from disappearing
> > beneath us:
> 
> Sounds like we also need to push out any FBC reconfiguration anytime
> modesetting occurs to ensure that we've waited past a vblank interval?

During intel_crtc_mode_set() and friends we only call into
intel_update_fbc() which just clears the FBC enabled bit and schedules a
delayed task to do the rest, if required. Fixing the mode_config locking
is sufficient to ensure that by the time the delayed task is run, the
modeset has finished, the pipe is running and at least 50ms, in the
original or 250ms in the update, has past since the final call to
intel_enable_fbc() which is at the end of *_crtc_enable().

If we are going from 2 crtcs to 1 with no swapping of the framebuffer,
then the single crtc that we want to enable FBC on, remains running for
the whole duration and the actual enabling is just deferred by 250ms.

If we are just moving the fb y-offset (e.g. panning the display), then the
pipe will remain running but we disable FBC and wait 250ms before
re-enabling.

So I think it just reduced into being an incorrect locking issue, but
we're still making the assumption that it is safe to touch the FBC just
because X ms have passed. :|
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 20:19     ` Chris Wilson
@ 2011-07-08 21:28       ` Keith Packard
  2011-07-08 22:08         ` Chris Wilson
  0 siblings, 1 reply; 17+ messages in thread
From: Keith Packard @ 2011-07-08 21:28 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 2201 bytes --]

On Fri, 08 Jul 2011 21:19:29 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> On Fri, 08 Jul 2011 13:00:09 -0700, Keith Packard <keithp@keithp.com> wrote:
> > On Fri, 08 Jul 2011 20:43:47 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > 
> > > Bumping to 250ms sufficiently delays the task to miss the race, but we
> > > can not foretell just how long any given crtc modeset will take. So what
> > > we need is to take the mode_config.lock in order to prevent concurrent
> > > access to the FBC registers and also to prevent the fb from disappearing
> > > beneath us:
> > 
> > Sounds like we also need to push out any FBC reconfiguration anytime
> > modesetting occurs to ensure that we've waited past a vblank interval?
> 
> During intel_crtc_mode_set() and friends we only call into
> intel_update_fbc() which just clears the FBC enabled bit and schedules a
> delayed task to do the rest, if required.

Does a further call into intel_crtc_mode_set push out the delayed task
so that it now occurs at least 50ms after the later call? That seems
useful, although it might not be necessary.

> If we are going from 2 crtcs to 1 with no swapping of the framebuffer,
> then the single crtc that we want to enable FBC on, remains running for
> the whole duration and the actual enabling is just deferred by 250ms.

Which is fine; mode setting doesn't happen often.

> If we are just moving the fb y-offset (e.g. panning the display), then the
> pipe will remain running but we disable FBC and wait 250ms before
> re-enabling.

That also seems fine; we certainly don't want to spend any time
optimizing for this case.

> So I think it just reduced into being an incorrect locking issue, but
> we're still making the assumption that it is safe to touch the FBC just
> because X ms have passed. :|

We could, of course, make sure that a certain number of vblank intervals
have passed instead of using a fixed timeout. Or we could compute the
vblank interval from the mode and then just make sure the timeout used
is sufficient. Or we could just use 100ms and assume that no-one will
ever set a mode of less than 10Hz.

-- 
keith.packard@intel.com

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 21:28       ` Keith Packard
@ 2011-07-08 22:08         ` Chris Wilson
  0 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2011-07-08 22:08 UTC (permalink / raw)
  To: Keith Packard, intel-gfx

On Fri, 08 Jul 2011 14:28:35 -0700, Keith Packard <keithp@keithp.com> wrote:
> On Fri, 08 Jul 2011 21:19:29 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > On Fri, 08 Jul 2011 13:00:09 -0700, Keith Packard <keithp@keithp.com> wrote:
> > > On Fri, 08 Jul 2011 20:43:47 +0100, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > During intel_crtc_mode_set() and friends we only call into
> > intel_update_fbc() which just clears the FBC enabled bit and schedules a
> > delayed task to do the rest, if required.
> 
> Does a further call into intel_crtc_mode_set push out the delayed task
> so that it now occurs at least 50ms after the later call? That seems
> useful, although it might not be necessary.

Yes, each call to intel_enable_fbc() resets the timer on the task,
delaying it further. The original purpose of this was to make sure that the
task did not kick off whilst the application was still page-flipping, and
it works equally well in the case of multiple calls during modeset or
very quick changes.

> We could, of course, make sure that a certain number of vblank intervals
> have passed instead of using a fixed timeout. Or we could compute the
> vblank interval from the mode and then just make sure the timeout used
> is sufficient. Or we could just use 100ms and assume that no-one will
> ever set a mode of less than 10Hz.

We already do make the assumption that 20Hz is the minimum refresh anybody
is likely to set, as a fallback for vblank timeouts. Maybe it is time we
formalized that assumption, #define VBLANK_TIMEOUT_MS 50, or
static inline int intel_get_vblank_timeout(dev, pipe) { return 50; }?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2011-07-08 19:43 ` FBC patchset Chris Wilson
  2011-07-08 20:00   ` Keith Packard
@ 2012-01-17 16:18   ` Daniel Vetter
  2012-01-17 16:57     ` Chris Wilson
  1 sibling, 1 reply; 17+ messages in thread
From: Daniel Vetter @ 2012-01-17 16:18 UTC (permalink / raw)
  To: Chris Wilson, Eugeni Dodonov; +Cc: intel-gfx

On Fri, Jul 08, 2011 at 08:43:47PM +0100, Chris Wilson wrote:
> Oh dear, it was all looking too good. Works fine with just one output.
> Runs into a nasty race if you add a second and start unplugging things...
> 
> The issue is that when unplugging an output, userspace sees this and
> appropriately reconfigures from an extended desktop to just using, for the
> sake of argument, the LVDS. As the desktop is changing size this requires
> a new framebuffer and so we begin to teardown the two crtcs and replace
> with just the one with the new fb. The first thing we do is disable the
> crtc connected to the unplugged display. This triggers an
> intel_update_fbc() which spots that it can now enable FBC on the current
> single crtc + old fb and promptly dispatches a delayed task to do so.
> 
> The mode reconfiguration continues apace and we disable the other crtc and
> start to replace the plane's FB. This involves a couple of
> wait-for-vblanks, and so is quite slow. During this time we avoid taking
> the struct_mutex. Meanwhile, the delayed task kicks off on a second CPU
> grabs the struct_mutex and reconfigures the FBC registers. Apparently
> enabling FBC on a dead plane is an undefined operation. Hilarity ensues,
> followed by a swift reboot.
> 
> Bumping to 250ms sufficiently delays the task to miss the race, but we
> can not foretell just how long any given crtc modeset will take. So what
> we need is to take the mode_config.lock in order to prevent concurrent
> access to the FBC registers and also to prevent the fb from disappearing
> beneath us:

I've just noticed that we seem to miss this plug to fix fbc issues. Care
to resend a proper patch in case we still need this?

Also, I we could try to also disable fbc when we detect frontbuffer
rendering (and generally abolish setting up the fence to detect such
writes), maybe that helps with our fbc troubles (if it's actually worth
it). Eugeni?
-Daniel
> 
> ---
>  drivers/gpu/drm/i915/intel_display.c |    8 +++++++-
>  1 files changed, 7 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e375500..bec9e1d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -1603,6 +1603,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
>  	struct drm_device *dev = work->crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> +	if (!mutex_trylock(&dev->mode_config.mutex)) {
> +		schedule_delayed_work(&work->work, msecs_to_jiffies(100));
> +		return;
> +	}
> +
>  	mutex_lock(&dev->struct_mutex);
>  	if (work == dev_priv->fbc_work) {
>  		/* Double check that we haven't switched fb without cancelling
> @@ -1620,6 +1625,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
>  		dev_priv->fbc_work = NULL;
>  	}
>  	mutex_unlock(&dev->struct_mutex);
> +	mutex_unlock(&dev->mode_config.mutex);
>  
>  	kfree(work);
>  }
> @@ -1684,7 +1690,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
>  	 * and indeed performing the enable as a co-routine and not
>  	 * waiting synchronously upon the vblank.
>  	 */
> -	schedule_delayed_work(&work->work, msecs_to_jiffies(50));
> +	schedule_delayed_work(&work->work, msecs_to_jiffies(250));
>  }
>  
>  void intel_disable_fbc(struct drm_device *dev)
> -- 
> 1.7.6
> 
> -- 
> Chris Wilson, Intel Open Source Technology Centre
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: FBC patchset
  2012-01-17 16:18   ` Daniel Vetter
@ 2012-01-17 16:57     ` Chris Wilson
  0 siblings, 0 replies; 17+ messages in thread
From: Chris Wilson @ 2012-01-17 16:57 UTC (permalink / raw)
  To: Daniel Vetter, Eugeni Dodonov; +Cc: intel-gfx

On Tue, 17 Jan 2012 17:18:17 +0100, Daniel Vetter <daniel@ffwll.ch> wrote:
> I've just noticed that we seem to miss this plug to fix fbc issues. Care
> to resend a proper patch in case we still need this?
> 
> Also, I we could try to also disable fbc when we detect frontbuffer
> rendering (and generally abolish setting up the fence to detect such
> writes), maybe that helps with our fbc troubles (if it's actually worth
> it). Eugeni?

I'm testing whether disabling fbc when fb is busy helps on my
troublesome SNB. But X can and will still access the scanout through a
fence, so we can't simply abolish setting up fences here. The other
recourse is to always used a shadow buffer so that we never access the
scanout directly, and perhaps restrict that to only use render as well.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2012-01-17 16:57 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-08 11:22 FBC patchset Chris Wilson
2011-07-08 11:22 ` [PATCH 1/8] drm/i915: Only export the generic intel_disable_fbc() interface Chris Wilson
2011-07-08 11:22 ` [PATCH 2/8] drm/i915: Replace direct calls to vfunc.disable_fbc with intel_disable_fbc() Chris Wilson
2011-07-08 11:22 ` [PATCH 3/8] drm/i915: Remove vestigial pitch from post-gen2 FBC control routines Chris Wilson
2011-07-08 17:20   ` Keith Packard
2011-07-08 11:22 ` [PATCH 4/8] drm/i915: Use of a CPU fence is mandatory to update FBC regions upon CPU writes Chris Wilson
2011-07-08 11:22 ` [PATCH 5/8] drm/i915: Set persistent-mode for ILK/SNB framebuffer compression Chris Wilson
2011-07-08 11:22 ` [PATCH 6/8] drm/i915: Disable FBC across page-flipping Chris Wilson
2011-07-08 11:22 ` [PATCH 7/8] drm/i915: Perform intel_enable_fbc() from a delayed task Chris Wilson
2011-07-08 11:22 ` [PATCH 8/8] drm/i915: Share the common work of disabling active FBC before updating Chris Wilson
2011-07-08 19:43 ` FBC patchset Chris Wilson
2011-07-08 20:00   ` Keith Packard
2011-07-08 20:19     ` Chris Wilson
2011-07-08 21:28       ` Keith Packard
2011-07-08 22:08         ` Chris Wilson
2012-01-17 16:18   ` Daniel Vetter
2012-01-17 16:57     ` Chris Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).