All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2
@ 2014-05-22 14:48 ville.syrjala
  2014-05-22 14:48 ` [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes ville.syrjala
                   ` (15 more replies)
  0 siblings, 16 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Here's a rebased and slightly polished version of the two part
watermark update series. Several patches already got merged, so
we're down to 16 now.

Also the drm vblank series got merged as did the atomic sprite series,
so there's nothing else blocking this stuff anymore.

Previouse version was here:
http://lists.freedesktop.org/archives/intel-gfx/2014-March/041302.html

Ville Syrjälä (16):
  drm/i915: Keep vblank interrupts enabled while enabling/disabling
    planes
  drm/i915: Leave interrupts enabled while disabling crtcs during
    suspend
  drm/i915: Check hw vs. sw watermark state after programming
  drm/i915: Refactor ilk_validate_pipe_wm()
  drm/i915: Refactor ilk_update_wm
  drm/i915: Add dev_priv->wm.mutex
  drm/i915: Add vblank based delayed watermark update mechanism
  drm/i915: Split watermark programming into pre and post steps
  drm/i915: Actually perform the watermark update in two phases
  drm/i915: Wait for watermark updates to finish before disabling a pipe
  drm/i915: Refactor get_other_active_crtc()
  drm/i915: Disable LP1+ watermarks while changing the number of active
    pipes
  drm/i915: Keep track of who disabled LP1+ watermarks
  drm/i915: Prefer the 5/6 DDB split when primary is disabled
  drm/i915: Add a workaround for sprite only <-> primary only switching
  drm/i915: Don't disable LP1+ watermarks for every frame when scaled

 drivers/gpu/drm/i915/i915_drv.c      |   3 +-
 drivers/gpu/drm/i915/i915_drv.h      |  39 +-
 drivers/gpu/drm/i915/i915_irq.c      |  12 +-
 drivers/gpu/drm/i915/intel_display.c | 152 ++++++--
 drivers/gpu/drm/i915/intel_drv.h     |  82 +++-
 drivers/gpu/drm/i915/intel_pm.c      | 733 ++++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_sprite.c  | 119 ++++--
 7 files changed, 964 insertions(+), 176 deletions(-)

-- 
1.8.5.5

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

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

* [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-26 13:56   ` Daniel Vetter
  2014-05-22 14:48 ` [PATCH 02/16] drm/i915: Leave interrupts enabled while disabling crtcs during suspend ville.syrjala
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Because of the upcoming vblank interrupt driven watermark update
mechanism we will have use for vblank interrupts during plane
enabling/disabling. So don't call drm_vblank_off() until planes
are off, and call drm_vblank_on() just before we start to enable
the planes.

v2: Pimp commit message (Paulo)

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 019e9e1..a11bd78 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3885,6 +3885,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc)
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
 
+	drm_vblank_on(dev, pipe);
+
 	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
 	intel_enable_planes(crtc);
 	/* The fixup needs to happen before cursor is enabled */
@@ -3910,7 +3912,6 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
 	int plane = intel_crtc->plane;
 
 	intel_crtc_wait_for_pending_flips(crtc);
-	drm_crtc_vblank_off(crtc);
 
 	if (dev_priv->fbc.plane == plane)
 		intel_disable_fbc(dev);
@@ -3921,6 +3922,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
 	intel_crtc_update_cursor(crtc, false);
 	intel_disable_planes(crtc);
 	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
+
+	drm_vblank_off(dev, pipe);
 }
 
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
@@ -3999,8 +4002,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 		cpt_verify_modeset(dev, intel_crtc->pipe);
 
 	intel_crtc_enable_planes(crtc);
-
-	drm_crtc_vblank_on(crtc);
 }
 
 /* IPS only exists on ULT machines and is tied to pipe A. */
@@ -4114,8 +4115,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 	 * to change the workaround. */
 	haswell_mode_set_planes_workaround(intel_crtc);
 	intel_crtc_enable_planes(crtc);
-
-	drm_crtc_vblank_on(crtc);
 }
 
 static void ironlake_pfit_disable(struct intel_crtc *crtc)
@@ -4625,8 +4624,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
 	intel_crtc_enable_planes(crtc);
 
-	drm_crtc_vblank_on(crtc);
-
 	/* Underruns don't raise interrupts, so check manually. */
 	i9xx_check_fifo_underruns(dev);
 }
@@ -4719,8 +4716,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 	if (IS_GEN2(dev))
 		intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 
-	drm_crtc_vblank_on(crtc);
-
 	/* Underruns don't raise interrupts, so check manually. */
 	i9xx_check_fifo_underruns(dev);
 }
-- 
1.8.5.5

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

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

* [PATCH 02/16] drm/i915: Leave interrupts enabled while disabling crtcs during suspend
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
  2014-05-22 14:48 ` [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-22 14:48 ` [PATCH 03/16] drm/i915: Check hw vs. sw watermark state after programming ville.syrjala
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The new watermaek update mechanism requires interrupts to work
correctly. Because of this we need interrupts while disabling crtcs
during suspend. So move the irq disable to happen a bit later.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index c83c83b..5fc49a9 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -525,7 +525,6 @@ static int i915_drm_freeze(struct drm_device *dev)
 
 		cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
 
-		drm_irq_uninstall(dev);
 		dev_priv->enable_hotplug_processing = false;
 		/*
 		 * Disable CRTCs directly since we want to preserve sw state
@@ -539,6 +538,8 @@ static int i915_drm_freeze(struct drm_device *dev)
 		}
 		mutex_unlock(&dev->mode_config.mutex);
 
+		drm_irq_uninstall(dev);
+
 		intel_modeset_suspend_hw(dev);
 	}
 
-- 
1.8.5.5

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

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

* [PATCH 03/16] drm/i915: Check hw vs. sw watermark state after programming
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
  2014-05-22 14:48 ` [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes ville.syrjala
  2014-05-22 14:48 ` [PATCH 02/16] drm/i915: Leave interrupts enabled while disabling crtcs during suspend ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-22 14:48 ` [PATCH 04/16] drm/i915: Refactor ilk_validate_pipe_wm() ville.syrjala
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make sure we programmed the watermarks correctly, by reading out the
hardware state again after programming and comparing it with the
state we supposedly programmed into hardware. Dump the watermark
registers after a mismatch, very much like we for the pipe config.
The only difference is that we don't dump the entire watermark
software tracking state since that's spread around a bit.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 117 ++++++++++++++++++++++++++++------------
 1 file changed, 83 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index bd9568e..5b54bf6 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2575,15 +2575,84 @@ static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
 	return changed;
 }
 
+static void _ilk_pipe_wm_get_hw_state(struct drm_device *dev,
+				      enum pipe pipe,
+				      struct ilk_wm_values *hw)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	static const unsigned int wm0_pipe_reg[] = {
+		[PIPE_A] = WM0_PIPEA_ILK,
+		[PIPE_B] = WM0_PIPEB_ILK,
+		[PIPE_C] = WM0_PIPEC_IVB,
+	};
+
+	hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]);
+
+	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+		hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
+}
+
+static void _ilk_wm_get_hw_state(struct drm_device *dev,
+				 struct ilk_wm_values *hw)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum pipe pipe;
+
+	for_each_pipe(pipe)
+		_ilk_pipe_wm_get_hw_state(dev, pipe, hw);
+
+	hw->wm_lp[0] = I915_READ(WM1_LP_ILK);
+	hw->wm_lp[1] = I915_READ(WM2_LP_ILK);
+	hw->wm_lp[2] = I915_READ(WM3_LP_ILK);
+
+	hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
+	if (INTEL_INFO(dev)->gen >= 7) {
+		hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
+		hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
+	}
+
+	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+		hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
+			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
+	else if (IS_IVYBRIDGE(dev))
+		hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ?
+			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
+
+	hw->enable_fbc_wm =
+		!(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
+}
+
+static void ilk_dump_wm_values(const struct ilk_wm_values *hw,
+			       const char *context)
+{
+	DRM_DEBUG_KMS("%s watermark values\n", context);
+	DRM_DEBUG_KMS("WM_PIPE_A = 0x%08x\n",  hw->wm_pipe[PIPE_A]);
+	DRM_DEBUG_KMS("WM_PIPE_B = 0x%08x\n",  hw->wm_pipe[PIPE_B]);
+	DRM_DEBUG_KMS("WM_PIPE_C = 0x%08x\n",  hw->wm_pipe[PIPE_C]);
+	DRM_DEBUG_KMS("WM_LP_1 = 0x%08x\n", hw->wm_lp[0]);
+	DRM_DEBUG_KMS("WM_LP_2 = 0x%08x\n", hw->wm_lp[1]);
+	DRM_DEBUG_KMS("WM_LP_3 = 0x%08x\n", hw->wm_lp[2]);
+	DRM_DEBUG_KMS("WM_LP_SPR_1 = 0x%08x\n", hw->wm_lp_spr[0]);
+	DRM_DEBUG_KMS("WM_LP_SPR_2 = 0x%08x\n", hw->wm_lp_spr[1]);
+	DRM_DEBUG_KMS("WM_LP_SPR_3 = 0x%08x\n", hw->wm_lp_spr[2]);
+	DRM_DEBUG_KMS("WM_LINETIME_A = 0x%08x\n", hw->wm_linetime[PIPE_A]);
+	DRM_DEBUG_KMS("WM_LINETIME_B = 0x%08x\n", hw->wm_linetime[PIPE_B]);
+	DRM_DEBUG_KMS("WM_LINETIME_C = 0x%08x\n", hw->wm_linetime[PIPE_C]);
+	DRM_DEBUG_KMS("enable FBC watermark = %d\n", hw->enable_fbc_wm);
+	DRM_DEBUG_KMS("DDB partitioning = %s\n",
+		      hw->partitioning == INTEL_DDB_PART_1_2 ? "1/2" : "5/6");
+}
+
 /*
  * The spec says we shouldn't write when we don't need, because every write
  * causes WMs to be re-evaluated, expending some power.
  */
 static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
-				struct ilk_wm_values *results)
+				const struct ilk_wm_values *results)
 {
 	struct drm_device *dev = dev_priv->dev;
 	struct ilk_wm_values *previous = &dev_priv->wm.hw;
+	struct ilk_wm_values hw = {};
 	unsigned int dirty;
 	uint32_t val;
 
@@ -2653,6 +2722,14 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
 		I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
 
 	dev_priv->wm.hw = *results;
+
+	_ilk_wm_get_hw_state(dev, &hw);
+
+	if (memcmp(results, &hw, sizeof(hw))) {
+		WARN(1, "watermark state doesn't match!\n");
+		ilk_dump_wm_values(&hw, "[hw state]");
+		ilk_dump_wm_values(results, "[sw state]");
+	}
 }
 
 static bool ilk_disable_lp_wm(struct drm_device *dev)
@@ -2734,23 +2811,14 @@ static void ilk_update_sprite_wm(struct drm_plane *plane,
 	ilk_update_wm(crtc);
 }
 
-static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
+static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct ilk_wm_values *hw = &dev_priv->wm.hw;
+	const struct ilk_wm_values *hw = &dev_priv->wm.hw;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_pipe_wm *active = &intel_crtc->wm.active;
 	enum pipe pipe = intel_crtc->pipe;
-	static const unsigned int wm0_pipe_reg[] = {
-		[PIPE_A] = WM0_PIPEA_ILK,
-		[PIPE_B] = WM0_PIPEB_ILK,
-		[PIPE_C] = WM0_PIPEC_IVB,
-	};
-
-	hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]);
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-		hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
 
 	active->pipe_enabled = intel_crtc_active(crtc);
 
@@ -2784,31 +2852,12 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 void ilk_wm_get_hw_state(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct ilk_wm_values *hw = &dev_priv->wm.hw;
 	struct drm_crtc *crtc;
 
-	for_each_crtc(dev, crtc)
-		ilk_pipe_wm_get_hw_state(crtc);
-
-	hw->wm_lp[0] = I915_READ(WM1_LP_ILK);
-	hw->wm_lp[1] = I915_READ(WM2_LP_ILK);
-	hw->wm_lp[2] = I915_READ(WM3_LP_ILK);
-
-	hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
-	if (INTEL_INFO(dev)->gen >= 7) {
-		hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
-		hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
-	}
+	_ilk_wm_get_hw_state(dev, &dev_priv->wm.hw);
 
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-		hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
-			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
-	else if (IS_IVYBRIDGE(dev))
-		hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ?
-			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
-
-	hw->enable_fbc_wm =
-		!(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
+	for_each_crtc(dev, crtc)
+		_ilk_pipe_wm_hw_to_sw(crtc);
 }
 
 /**
-- 
1.8.5.5

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

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

* [PATCH 04/16] drm/i915: Refactor ilk_validate_pipe_wm()
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (2 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 03/16] drm/i915: Check hw vs. sw watermark state after programming ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-22 14:48 ` [PATCH v2 05/16] drm/i915: Refactor ilk_update_wm ville.syrjala
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pull the LP0 validate out from intel_compute_pipe_wm() into a separate
function. We will have further need for such a function to validate
both the final watermarks and the intermediate watermarks we will be
using while the plane(s) transition between different configurations.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 5b54bf6..55ce660 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2222,6 +2222,24 @@ static void ilk_compute_wm_config(struct drm_device *dev,
 	}
 }
 
+static bool ilk_validate_pipe_wm(struct drm_device *dev,
+				 struct intel_pipe_wm *pipe_wm)
+{
+	/* LP0 watermark maximums depend on this pipe alone */
+	const struct intel_wm_config config = {
+		.num_pipes_active = 1,
+		.sprites_enabled = pipe_wm->sprites_enabled,
+		.sprites_scaled = pipe_wm->sprites_scaled,
+	};
+	struct ilk_wm_maximums max;
+
+	/* LP0 watermarks always use 1/2 DDB partitioning */
+	ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
+
+	/* At least LP0 must be valid */
+	return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]);
+}
+
 /* Compute new watermarks for the pipe */
 static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 				  const struct ilk_pipe_wm_parameters *params,
@@ -2230,12 +2248,6 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	const struct drm_i915_private *dev_priv = dev->dev_private;
 	int level, max_level = ilk_wm_max_level(dev);
-	/* LP0 watermark maximums depend on this pipe alone */
-	struct intel_wm_config config = {
-		.num_pipes_active = 1,
-		.sprites_enabled = params->spr.enabled,
-		.sprites_scaled = params->spr.scaled,
-	};
 	struct ilk_wm_maximums max;
 
 	pipe_wm->pipe_enabled = params->active;
@@ -2255,11 +2267,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 		pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
 
-	/* LP0 watermarks always use 1/2 DDB partitioning */
-	ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
-
-	/* At least LP0 must be valid */
-	if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
+	if (!ilk_validate_pipe_wm(dev, pipe_wm))
 		return false;
 
 	ilk_compute_wm_reg_maximums(dev, 1, &max);
-- 
1.8.5.5

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

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

* [PATCH v2 05/16] drm/i915: Refactor ilk_update_wm
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (3 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 04/16] drm/i915: Refactor ilk_validate_pipe_wm() ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-22 14:48 ` [PATCH 06/16] drm/i915: Add dev_priv->wm.mutex ville.syrjala
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Split ilk_update_wm() into two parts; one doing the programming
and the other the calculations.

v2: Fix typo in commit message

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 55ce660..2185553 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2747,27 +2747,14 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
 	return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
 }
 
-static void ilk_update_wm(struct drm_crtc *crtc)
+static void ilk_program_watermarks(struct drm_device *dev)
 {
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
 	struct ilk_wm_maximums max;
-	struct ilk_pipe_wm_parameters params = {};
+	struct intel_wm_config config = {};
 	struct ilk_wm_values results = {};
 	enum intel_ddb_partitioning partitioning;
-	struct intel_pipe_wm pipe_wm = {};
-	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
-	struct intel_wm_config config = {};
-
-	ilk_compute_wm_parameters(crtc, &params);
-
-	intel_compute_pipe_wm(crtc, &params, &pipe_wm);
-
-	if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
-		return;
-
-	intel_crtc->wm.active = pipe_wm;
 
 	ilk_compute_wm_config(dev, &config);
 
@@ -2793,6 +2780,25 @@ static void ilk_update_wm(struct drm_crtc *crtc)
 	ilk_write_wm_values(dev_priv, &results);
 }
 
+static void ilk_update_wm(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct ilk_pipe_wm_parameters params = {};
+	struct intel_pipe_wm pipe_wm = {};
+
+	ilk_compute_wm_parameters(crtc, &params);
+
+	intel_compute_pipe_wm(crtc, &params, &pipe_wm);
+
+	if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
+		return;
+
+	intel_crtc->wm.active = pipe_wm;
+
+	ilk_program_watermarks(dev);
+}
+
 static void ilk_update_sprite_wm(struct drm_plane *plane,
 				     struct drm_crtc *crtc,
 				     uint32_t sprite_width, int pixel_size,
-- 
1.8.5.5

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

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

* [PATCH 06/16] drm/i915: Add dev_priv->wm.mutex
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (4 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 05/16] drm/i915: Refactor ilk_update_wm ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-05-22 14:48 ` [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism ville.syrjala
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add a mutex to protect most of the watermark state. Will be useful when
we start to update watermarks asynchronously from plane updates, or
when we get finer grained locking for planes.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h  | 11 ++++++++++-
 drivers/gpu/drm/i915/intel_drv.h |  5 ++++-
 drivers/gpu/drm/i915/intel_pm.c  | 21 +++++++++++++++++++--
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 459b02a..a2302a7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1530,8 +1530,17 @@ struct drm_i915_private {
 		/* cursor */
 		uint16_t cur_latency[5];
 
-		/* current hardware state */
+		/*
+		 * current hardware state
+		 * protected by dev_priv->wm.mutex
+		 */
 		struct ilk_wm_values hw;
+
+		/*
+		 * protects some dev_priv->wm and intel_crtc->wm
+		 * state as well as the actual hardware registers
+		 */
+		struct mutex mutex;
 	} wm;
 
 	struct i915_runtime_pm pm;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d7c52b2..d75cc2b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -404,7 +404,10 @@ struct intel_crtc {
 
 	/* per-pipe watermark state */
 	struct {
-		/* watermarks currently being used  */
+		/*
+		 * watermarks currently being used
+		 * protected by dev_priv->wm.mutex
+		 */
 		struct intel_pipe_wm active;
 	} wm;
 
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 2185553..2a63418 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2743,8 +2743,13 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
 static bool ilk_disable_lp_wm(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool changed;
+
+	mutex_lock(&dev_priv->wm.mutex);
+	changed = _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
+	mutex_unlock(&dev_priv->wm.mutex);
 
-	return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
+	return changed;
 }
 
 static void ilk_program_watermarks(struct drm_device *dev)
@@ -2784,6 +2789,7 @@ static void ilk_update_wm(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct ilk_pipe_wm_parameters params = {};
 	struct intel_pipe_wm pipe_wm = {};
 
@@ -2791,12 +2797,17 @@ static void ilk_update_wm(struct drm_crtc *crtc)
 
 	intel_compute_pipe_wm(crtc, &params, &pipe_wm);
 
+	mutex_lock(&dev_priv->wm.mutex);
+
 	if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
-		return;
+		goto unlock;
 
 	intel_crtc->wm.active = pipe_wm;
 
 	ilk_program_watermarks(dev);
+
+ unlock:
+	mutex_unlock(&dev_priv->wm.mutex);
 }
 
 static void ilk_update_sprite_wm(struct drm_plane *plane,
@@ -2868,10 +2879,14 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 
+	mutex_lock(&dev_priv->wm.mutex);
+
 	_ilk_wm_get_hw_state(dev, &dev_priv->wm.hw);
 
 	for_each_crtc(dev, crtc)
 		_ilk_pipe_wm_hw_to_sw(crtc);
+
+	mutex_unlock(&dev_priv->wm.mutex);
 }
 
 /**
@@ -6369,6 +6384,8 @@ void intel_init_pm(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	mutex_init(&dev_priv->wm.mutex);
+
 	if (HAS_FBC(dev)) {
 		if (INTEL_INFO(dev)->gen >= 7) {
 			dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
-- 
1.8.5.5

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

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

* [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (5 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 06/16] drm/i915: Add dev_priv->wm.mutex ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-03 18:50   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps ville.syrjala
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add a mechanism by which you can queue up watermark update to happen
after the vblank counter has reached a certain value. The vblank
interrupt handler will schedule a work which will do the actual
watermark programming in process context.

v2: Rebase and s/intel_crtc/crtc/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   2 +
 drivers/gpu/drm/i915/i915_irq.c      |  12 ++-
 drivers/gpu/drm/i915/intel_display.c |   1 +
 drivers/gpu/drm/i915/intel_drv.h     |  27 +++++++
 drivers/gpu/drm/i915/intel_pm.c      | 144 +++++++++++++++++++++++++++++++++++
 5 files changed, 183 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a2302a7..c90d5ac 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1541,6 +1541,8 @@ struct drm_i915_private {
 		 * state as well as the actual hardware registers
 		 */
 		struct mutex mutex;
+
+		struct work_struct work;
 	} wm;
 
 	struct i915_runtime_pm pm;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 304f86a..c680020 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2067,8 +2067,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 		DRM_ERROR("Poison interrupt\n");
 
 	for_each_pipe(pipe) {
-		if (de_iir & DE_PIPE_VBLANK(pipe))
+		if (de_iir & DE_PIPE_VBLANK(pipe)) {
 			intel_pipe_handle_vblank(dev, pipe);
+			ilk_update_pipe_wm(dev, pipe);
+		}
 
 		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
 			if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
@@ -2117,8 +2119,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 		intel_opregion_asle_intr(dev);
 
 	for_each_pipe(pipe) {
-		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
+		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) {
 			intel_pipe_handle_vblank(dev, pipe);
+			ilk_update_pipe_wm(dev, pipe);
+		}
 
 		/* plane/pipes map 1:1 on ilk+ */
 		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
@@ -2260,8 +2264,10 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 			continue;
 
 		pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
-		if (pipe_iir & GEN8_PIPE_VBLANK)
+		if (pipe_iir & GEN8_PIPE_VBLANK) {
 			intel_pipe_handle_vblank(dev, pipe);
+			ilk_update_pipe_wm(dev, pipe);
+		}
 
 		if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
 			intel_prepare_page_flip(dev, pipe);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a11bd78..408b238 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10961,6 +10961,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 		intel_crtc->plane = !pipe;
 	}
 
+	spin_lock_init(&intel_crtc->wm.lock);
 	init_waitqueue_head(&intel_crtc->vbl_wait);
 
 	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d75cc2b..72f01b1 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -409,6 +409,32 @@ struct intel_crtc {
 		 * protected by dev_priv->wm.mutex
 		 */
 		struct intel_pipe_wm active;
+		/*
+		 * watermarks queued for next vblank
+		 * protected by dev_priv->wm.mutex
+		 */
+		struct intel_pipe_wm pending;
+
+		/*
+		 * the vblank count after which we can switch over to 'pending'
+		 * protected by intel_crtc->wm.lock
+		 */
+		u32 pending_vbl_count;
+		/*
+		 * indicates that 'pending' contains changed watermarks
+		 * protected by intel_crtc->wm.lock
+		 */
+		bool dirty;
+		/*
+		 * watermark update has a vblank reference?
+		 * protected by intel_crtc->wm.lock
+		 */
+		bool vblank;
+
+		/*
+		 * protects some intel_crtc->wm state
+		 */
+		spinlock_t lock;
 	} wm;
 
 	wait_queue_head_t vbl_wait;
@@ -974,6 +1000,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
 void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
 void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
 void ilk_wm_get_hw_state(struct drm_device *dev);
+void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
 
 
 /* intel_sdvo.c */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 2a63418..6fc6416 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2752,6 +2752,65 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
 	return changed;
 }
 
+static bool vbl_count_after_eq(struct drm_device *dev, u32 a, u32 b)
+{
+	u32 mask = dev->max_vblank_count;
+
+	/* just the msb please */
+	mask &= ~(mask >> 1);
+
+	return !((a - b) & mask);
+}
+
+static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	u32 vbl_count;
+
+	assert_spin_locked(&crtc->wm.lock);
+
+	if (!crtc->wm.dirty)
+		return false;
+
+	vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
+
+	if (!vbl_count_after_eq(dev, vbl_count, crtc->wm.pending_vbl_count))
+		return false;
+
+	if (crtc->wm.vblank) {
+		drm_vblank_put(dev, crtc->pipe);
+		crtc->wm.vblank = false;
+	}
+
+	return true;
+}
+
+static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
+{
+	struct intel_crtc *crtc;
+	bool changed = false;
+
+	for_each_intel_crtc(dev, crtc) {
+		bool ready;
+
+		spin_lock_irq(&crtc->wm.lock);
+
+		ready = ilk_pending_watermarks_ready(crtc);
+		if (ready)
+			crtc->wm.dirty = false;
+
+		spin_unlock_irq(&crtc->wm.lock);
+
+		if (!ready)
+			continue;
+
+		crtc->wm.active = crtc->wm.pending;
+		changed = true;
+	}
+
+	return changed;
+}
+
 static void ilk_program_watermarks(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2810,6 +2869,87 @@ static void ilk_update_wm(struct drm_crtc *crtc)
 	mutex_unlock(&dev_priv->wm.mutex);
 }
 
+static void ilk_update_watermarks(struct drm_device *dev)
+{
+	bool changed;
+
+	changed = ilk_refresh_pending_watermarks(dev);
+
+	if (changed)
+		ilk_program_watermarks(dev);
+}
+
+static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
+					 const struct intel_pipe_wm *pipe_wm,
+					 u32 vbl_count)
+{
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	WARN(!crtc->active, "pipe %c should be enabled\n",
+	     pipe_name(pipe));
+
+	/* do the watermarks actually need changing? */
+	if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
+		return;
+
+	crtc->wm.pending = *pipe_wm;
+
+	spin_lock_irq(&crtc->wm.lock);
+	crtc->wm.pending_vbl_count = (vbl_count + 1) & dev->max_vblank_count;
+	crtc->wm.dirty = true;
+	spin_unlock_irq(&crtc->wm.lock);
+
+	/* try to update immediately */
+	ilk_update_watermarks(dev);
+
+	spin_lock_irq(&crtc->wm.lock);
+
+	/* did the immediate update succeed? */
+	if (!crtc->wm.dirty)
+		goto unlock;
+
+	/*
+	 * We might already have a pending watermark update, in
+	 * which case we shouldn't grab another vblank reference.
+	 */
+	if (!crtc->wm.vblank && drm_vblank_get(dev, pipe) == 0)
+		crtc->wm.vblank = true;
+
+	WARN(!crtc->wm.vblank,
+	     "unable to set up watermarks for pipe %c\n", pipe_name(pipe));
+
+ unlock:
+	spin_unlock_irq(&crtc->wm.lock);
+}
+
+static void ilk_watermark_work(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(work, struct drm_i915_private, wm.work);
+
+	mutex_lock(&dev_priv->wm.mutex);
+
+	ilk_update_watermarks(dev_priv->dev);
+
+	mutex_unlock(&dev_priv->wm.mutex);
+}
+
+/* Called from vblank irq */
+void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc =
+		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+	spin_lock(&crtc->wm.lock);
+
+	if (ilk_pending_watermarks_ready(crtc))
+		schedule_work(&dev_priv->wm.work);
+
+	spin_unlock(&crtc->wm.lock);
+}
+
 static void ilk_update_sprite_wm(struct drm_plane *plane,
 				     struct drm_crtc *crtc,
 				     uint32_t sprite_width, int pixel_size,
@@ -2872,6 +3012,9 @@ static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
 		for (level = 0; level <= max_level; level++)
 			active->wm[level].enable = true;
 	}
+
+	/* no update pending */
+	intel_crtc->wm.pending = intel_crtc->wm.active;
 }
 
 void ilk_wm_get_hw_state(struct drm_device *dev)
@@ -6385,6 +6528,7 @@ void intel_init_pm(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	mutex_init(&dev_priv->wm.mutex);
+	INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);
 
 	if (HAS_FBC(dev)) {
 		if (INTEL_INFO(dev)->gen >= 7) {
-- 
1.8.5.5

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

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

* [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (6 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-03 20:51   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases ville.syrjala
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We need to perform watermark programming before and after changing the
plane configuration. Add two new vfuncs to do that. The pre phase is
supposed to switch over to the intermediate watermarks which are
computed so that they can deal with both the old and new plane
configurations. The post phase will arm the vblank based update
systems to switch over to the optimal target watermarks after the
plane configuration has for sure changed.

v2: Pass around intel_crtc and s/intel_crtc/crtc/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h  |  5 +++
 drivers/gpu/drm/i915/intel_drv.h | 11 +++++
 drivers/gpu/drm/i915/intel_pm.c  | 88 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c90d5ac..d4f8ae8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -407,6 +407,7 @@ struct intel_plane_config;
 struct intel_crtc;
 struct intel_limit;
 struct dpll;
+struct intel_crtc_wm_config;
 
 struct drm_i915_display_funcs {
 	bool (*fbc_enabled)(struct drm_device *dev);
@@ -437,6 +438,10 @@ struct drm_i915_display_funcs {
 				 struct drm_crtc *crtc,
 				 uint32_t sprite_width, int pixel_size,
 				 bool enable, bool scaled);
+	void (*program_wm_pre)(struct intel_crtc *crtc,
+			       const struct intel_crtc_wm_config *config);
+	void (*program_wm_post)(struct intel_crtc *crtc,
+				const struct intel_crtc_wm_config *config);
 	void (*modeset_global_resources)(struct drm_device *dev);
 	/* Returns the active state of the crtc, and if the crtc is active,
 	 * fills out the pipe-config with the hw state. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 72f01b1..4b59be3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -358,6 +358,13 @@ struct intel_pipe_wm {
 	bool sprites_scaled;
 };
 
+struct intel_crtc_wm_config {
+	/* target watermarks for the pipe */
+	struct intel_pipe_wm target;
+	/* intermediate watermarks for pending/active->target transition */
+	struct intel_pipe_wm intm;
+};
+
 struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
@@ -1001,6 +1008,10 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
 void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
 void ilk_wm_get_hw_state(struct drm_device *dev);
 void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
+void intel_program_watermarks_pre(struct intel_crtc *crtc,
+				  const struct intel_crtc_wm_config *config);
+void intel_program_watermarks_post(struct intel_crtc *crtc,
+				   const struct intel_crtc_wm_config *config);
 
 
 /* intel_sdvo.c */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 6fc6416..ccf920a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2950,6 +2950,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
 	spin_unlock(&crtc->wm.lock);
 }
 
+static void ilk_wm_cancel(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+
+	assert_spin_locked(&crtc->wm.lock);
+
+	crtc->wm.dirty = false;
+
+	if (crtc->wm.vblank) {
+		drm_vblank_put(dev, crtc->pipe);
+		crtc->wm.vblank = false;
+	}
+}
+
 static void ilk_update_sprite_wm(struct drm_plane *plane,
 				     struct drm_crtc *crtc,
 				     uint32_t sprite_width, int pixel_size,
@@ -3084,6 +3098,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
 						   pixel_size, enabled, scaled);
 }
 
+void intel_program_watermarks_pre(struct intel_crtc *crtc,
+				  const struct intel_crtc_wm_config *config)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+	if (dev_priv->display.program_wm_pre)
+		dev_priv->display.program_wm_pre(crtc, config);
+}
+
+void intel_program_watermarks_post(struct intel_crtc *crtc,
+				   const struct intel_crtc_wm_config *config)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+	if (dev_priv->display.program_wm_post)
+		dev_priv->display.program_wm_post(crtc, config);
+}
+
 static struct drm_i915_gem_object *
 intel_alloc_context_page(struct drm_device *dev)
 {
@@ -6522,6 +6554,60 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
 	pm_runtime_disable(device);
 }
 
+static void ilk_program_wm_pre(struct intel_crtc *crtc,
+			       const struct intel_crtc_wm_config *config)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev_priv->wm.mutex);
+
+	spin_lock_irq(&crtc->wm.lock);
+	ilk_wm_cancel(crtc);
+	spin_unlock_irq(&crtc->wm.lock);
+
+	/* pending update (if any) got cancelled */
+	crtc->wm.pending = crtc->wm.active;
+
+	if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
+		goto unlock;
+
+	crtc->wm.active = config->intm;
+
+	/* use the most up to date watermarks for other pipes */
+	ilk_refresh_pending_watermarks(dev);
+
+	/* switch over to the intermediate watermarks */
+	ilk_program_watermarks(dev);
+
+ unlock:
+	mutex_unlock(&dev_priv->wm.mutex);
+}
+
+static void ilk_program_wm_post(struct intel_crtc *crtc,
+				const struct intel_crtc_wm_config *config)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 vbl_count;
+
+	/*
+	 * FIXME sample this inside the atomic section to avoid
+	 * needlessly long periods w/ sub-par watermarks
+	 */
+	vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
+
+	mutex_lock(&dev_priv->wm.mutex);
+
+	/*
+	 * We can switch over to the target
+	 * watermarks after the next vblank.
+	 */
+	ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
+
+	mutex_unlock(&dev_priv->wm.mutex);
+}
+
 /* Set up chip specific power management-related functions */
 void intel_init_pm(struct drm_device *dev)
 {
@@ -6569,6 +6655,8 @@ void intel_init_pm(struct drm_device *dev)
 		     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
 			dev_priv->display.update_wm = ilk_update_wm;
 			dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
+			dev_priv->display.program_wm_pre = ilk_program_wm_pre;
+			dev_priv->display.program_wm_post = ilk_program_wm_post;
 		} else {
 			DRM_DEBUG_KMS("Failed to read display plane latency. "
 				      "Disable CxSR\n");
-- 
1.8.5.5

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

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

* [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (7 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-03 22:47   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe ville.syrjala
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Switch the code over to using the two phase watermark update. The steps
generally follow this pattern:

1. Calculate new plane parameters for changed planes
2. Calculate new target and intermediate watermarks
3. Check that both the target and intermediate watermarks are valid
4. Program the hardware with the intermediate watermarks
5. Program the plane registers
6. Arm the vblank watermark update machinery for the next vblank
7. Program the hardware with the target watermarks (after vblank)

v2: Rebased, pass intel_crtc around, s/intel_crtc/crtc/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |  14 ++-
 drivers/gpu/drm/i915/intel_display.c |  58 ++++++++-
 drivers/gpu/drm/i915/intel_drv.h     |  35 ++++--
 drivers/gpu/drm/i915/intel_pm.c      | 229 +++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_sprite.c  | 119 ++++++++++++------
 5 files changed, 347 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d4f8ae8..5b1404e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -405,9 +405,12 @@ struct intel_connector;
 struct intel_crtc_config;
 struct intel_plane_config;
 struct intel_crtc;
+struct intel_plane;
 struct intel_limit;
 struct dpll;
 struct intel_crtc_wm_config;
+struct intel_plane_wm_parameters;
+struct intel_crtc_wm_config;
 
 struct drm_i915_display_funcs {
 	bool (*fbc_enabled)(struct drm_device *dev);
@@ -434,10 +437,13 @@ struct drm_i915_display_funcs {
 			  struct dpll *match_clock,
 			  struct dpll *best_clock);
 	void (*update_wm)(struct drm_crtc *crtc);
-	void (*update_sprite_wm)(struct drm_plane *plane,
-				 struct drm_crtc *crtc,
-				 uint32_t sprite_width, int pixel_size,
-				 bool enable, bool scaled);
+	int (*update_primary_wm)(struct intel_crtc *crtc,
+				 struct intel_crtc_wm_config *config);
+	int (*update_cursor_wm)(struct intel_crtc *crtc,
+				struct intel_crtc_wm_config *config);
+	int (*update_sprite_wm)(struct intel_plane *plane,
+				struct intel_crtc *crtc,
+				struct intel_crtc_wm_config *config);
 	void (*program_wm_pre)(struct intel_crtc *crtc,
 			       const struct intel_crtc_wm_config *config);
 	void (*program_wm_post)(struct intel_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 408b238..5bf1633 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2078,6 +2078,19 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
 	POSTING_READ(reg);
 }
 
+static void update_pri_params(struct intel_crtc *crtc,
+			      struct intel_plane_wm_parameters *params,
+			      bool primary_enabled)
+{
+	if (!crtc->active || !primary_enabled)
+		return;
+
+	params->horiz_pixels = crtc->config.pipe_src_w;
+	params->bytes_per_pixel =
+		drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
+	params->enabled = true;
+}
+
 /**
  * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
  * @dev_priv: i915 private structure
@@ -2091,6 +2104,8 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
 {
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+	struct intel_crtc_wm_config config = {};
+	int ret;
 	int reg;
 	u32 val;
 
@@ -2100,14 +2115,24 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
 	if (intel_crtc->primary_enabled)
 		return;
 
+	update_pri_params(intel_crtc, &config.pri, true);
+
+	ret = intel_update_primary_watermarks(intel_crtc, &config);
+	WARN(ret, "primary watermarks invalid\n");
+
 	intel_crtc->primary_enabled = true;
 
 	reg = DSPCNTR(plane);
 	val = I915_READ(reg);
 	WARN_ON(val & DISPLAY_PLANE_ENABLE);
 
+	intel_crtc->pri_wm = config.pri;
+	intel_program_watermarks_pre(intel_crtc, &config);
+
 	I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
 	intel_flush_primary_plane(dev_priv, plane);
+
+	intel_program_watermarks_post(intel_crtc, &config);
 }
 
 /**
@@ -2123,20 +2148,32 @@ static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
 {
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+	struct intel_crtc_wm_config config = {};
+	int ret;
 	int reg;
 	u32 val;
 
 	if (!intel_crtc->primary_enabled)
 		return;
 
+	update_pri_params(intel_crtc, &config.pri, false);
+
+	ret = intel_update_primary_watermarks(intel_crtc, &config);
+	WARN(ret, "primary watermarks invalid\n");
+
 	intel_crtc->primary_enabled = false;
 
 	reg = DSPCNTR(plane);
 	val = I915_READ(reg);
 	WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0);
 
+	intel_crtc->pri_wm = config.pri;
+	intel_program_watermarks_pre(intel_crtc, &config);
+
 	I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
 	intel_flush_primary_plane(dev_priv, plane);
+
+	intel_program_watermarks_post(intel_crtc, &config);
 }
 
 static bool need_vtd_wa(struct drm_device *dev)
@@ -3989,7 +4026,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	 */
 	intel_crtc_load_lut(crtc);
 
-	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
 	if (intel_crtc->config.has_pch_encoder)
@@ -4100,7 +4136,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 	intel_ddi_set_pipe_settings(crtc);
 	intel_ddi_enable_transcoder_func(crtc);
 
-	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
 	if (intel_crtc->config.has_pch_encoder)
@@ -4188,7 +4223,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 	}
 
 	intel_crtc->active = false;
-	intel_update_watermarks(crtc);
 
 	mutex_lock(&dev->struct_mutex);
 	intel_update_fbc(dev);
@@ -4236,7 +4270,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 	}
 
 	intel_crtc->active = false;
-	intel_update_watermarks(crtc);
 
 	mutex_lock(&dev->struct_mutex);
 	intel_update_fbc(dev);
@@ -7985,11 +8018,13 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_wm_config config = {};
 	int pipe = intel_crtc->pipe;
 	int x = intel_crtc->cursor_x;
 	int y = intel_crtc->cursor_y;
 	u32 base = 0, pos = 0;
 	bool visible;
+	int ret;
 
 	if (on)
 		base = intel_crtc->cursor_addr;
@@ -8022,6 +8057,19 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 	if (!visible && !intel_crtc->cursor_visible)
 		return;
 
+	if (visible) {
+		/* FIXME should we use the clipped width? */
+		config.cur.horiz_pixels = intel_crtc->cursor_width;
+		config.cur.bytes_per_pixel = 4;
+		config.cur.enabled = true;
+	}
+
+	ret = intel_update_cursor_watermarks(intel_crtc, &config);
+	WARN(ret, "cursor watermarks invalid\n");
+
+	intel_crtc->cur_wm = config.cur;
+	intel_program_watermarks_pre(intel_crtc, &config);
+
 	I915_WRITE(CURPOS(pipe), pos);
 
 	if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
@@ -8030,6 +8078,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 		i845_update_cursor(crtc, base);
 	else
 		i9xx_update_cursor(crtc, base);
+
+	intel_program_watermarks_post(intel_crtc, &config);
 }
 
 static int intel_crtc_cursor_set(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4b59be3..1ec4379 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -358,7 +358,15 @@ struct intel_pipe_wm {
 	bool sprites_scaled;
 };
 
+struct intel_plane_wm_parameters {
+	uint32_t horiz_pixels;
+	uint8_t bytes_per_pixel;
+	bool enabled;
+	bool scaled;
+};
+
 struct intel_crtc_wm_config {
+	struct intel_plane_wm_parameters pri, spr, cur;
 	/* target watermarks for the pipe */
 	struct intel_pipe_wm target;
 	/* intermediate watermarks for pending/active->target transition */
@@ -444,18 +452,14 @@ struct intel_crtc {
 		spinlock_t lock;
 	} wm;
 
+	struct intel_plane_wm_parameters pri_wm;
+	struct intel_plane_wm_parameters cur_wm;
+
 	wait_queue_head_t vbl_wait;
 
 	int scanline_offset;
 };
 
-struct intel_plane_wm_parameters {
-	uint32_t horiz_pixels;
-	uint8_t bytes_per_pixel;
-	bool enabled;
-	bool scaled;
-};
-
 struct intel_plane {
 	struct drm_plane base;
 	int plane;
@@ -483,9 +487,11 @@ struct intel_plane {
 			     int crtc_x, int crtc_y,
 			     unsigned int crtc_w, unsigned int crtc_h,
 			     uint32_t x, uint32_t y,
-			     uint32_t src_w, uint32_t src_h);
+			     uint32_t src_w, uint32_t src_h,
+			     const struct intel_crtc_wm_config *config);
 	void (*disable_plane)(struct drm_plane *plane,
-			      struct drm_crtc *crtc);
+			      struct drm_crtc *crtc,
+			      const struct intel_crtc_wm_config *config);
 	int (*update_colorkey)(struct drm_plane *plane,
 			       struct drm_intel_sprite_colorkey *key);
 	void (*get_colorkey)(struct drm_plane *plane,
@@ -969,10 +975,13 @@ void intel_init_clock_gating(struct drm_device *dev);
 void intel_suspend_hw(struct drm_device *dev);
 int ilk_wm_max_level(const struct drm_device *dev);
 void intel_update_watermarks(struct drm_crtc *crtc);
-void intel_update_sprite_watermarks(struct drm_plane *plane,
-				    struct drm_crtc *crtc,
-				    uint32_t sprite_width, int pixel_size,
-				    bool enabled, bool scaled);
+int intel_update_cursor_watermarks(struct intel_crtc *crtc,
+				   struct intel_crtc_wm_config *config);
+int intel_update_primary_watermarks(struct intel_crtc *crtc,
+				   struct intel_crtc_wm_config *config);
+int intel_update_sprite_watermarks(struct intel_plane *plane,
+				   struct intel_crtc *crtc,
+				   struct intel_crtc_wm_config *config);
 void intel_init_pm(struct drm_device *dev);
 void intel_pm_setup(struct drm_device *dev);
 bool intel_fbc_enabled(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index ccf920a..13366b7 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2186,13 +2186,9 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
 	p->active = true;
 	p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
 	p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
-	p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
-	p->cur.bytes_per_pixel = 4;
-	p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
-	p->cur.horiz_pixels = intel_crtc->cursor_width;
-	/* TODO: for now, assume primary and cursor planes are always enabled. */
-	p->pri.enabled = true;
-	p->cur.enabled = true;
+
+	p->pri = intel_crtc->pri_wm;
+	p->cur = intel_crtc->cur_wm;
 
 	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
 		struct intel_plane *intel_plane = to_intel_plane(plane);
@@ -2292,6 +2288,35 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 }
 
 /*
+ * Merge two pipe watermark sets.
+ * Used for computing intermediate watermark levels
+ * for transitioning between two different configurations.
+ */
+static void ilk_wm_merge_intermediate(struct drm_device *dev,
+				      struct intel_pipe_wm *a,
+				      const struct intel_pipe_wm *b)
+{
+	int level, max_level = ilk_wm_max_level(dev);
+
+	a->pipe_enabled |= b->pipe_enabled;
+	a->sprites_enabled |= b->sprites_enabled;
+	a->sprites_scaled |= b->sprites_scaled;
+
+	/* Merge _all_ levels including 0 */
+	for (level = 0; level <= max_level; level++) {
+		struct intel_wm_level *a_wm = &a->wm[level];
+		const struct intel_wm_level *b_wm = &b->wm[level];
+
+		a_wm->enable &= b_wm->enable;
+
+		a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
+		a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
+		a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
+		a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
+	}
+}
+
+/*
  * Merge the watermarks from all active pipes for a specific level.
  */
 static void ilk_merge_wm_level(struct drm_device *dev,
@@ -2844,31 +2869,6 @@ static void ilk_program_watermarks(struct drm_device *dev)
 	ilk_write_wm_values(dev_priv, &results);
 }
 
-static void ilk_update_wm(struct drm_crtc *crtc)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct ilk_pipe_wm_parameters params = {};
-	struct intel_pipe_wm pipe_wm = {};
-
-	ilk_compute_wm_parameters(crtc, &params);
-
-	intel_compute_pipe_wm(crtc, &params, &pipe_wm);
-
-	mutex_lock(&dev_priv->wm.mutex);
-
-	if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
-		goto unlock;
-
-	intel_crtc->wm.active = pipe_wm;
-
-	ilk_program_watermarks(dev);
-
- unlock:
-	mutex_unlock(&dev_priv->wm.mutex);
-}
-
 static void ilk_update_watermarks(struct drm_device *dev)
 {
 	bool changed;
@@ -2923,6 +2923,71 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
 	spin_unlock_irq(&crtc->wm.lock);
 }
 
+static int ilk_pipe_compute_watermarks(struct intel_crtc *crtc,
+				       struct intel_pipe_wm *target,
+				       struct intel_pipe_wm *intm)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_pipe_wm intm_pending;
+	bool dirty;
+
+	/* are the target watermarks valid at all? */
+	if (!ilk_validate_pipe_wm(dev, target))
+		return -EINVAL;
+
+	/*
+	 * We need to come up with intermediate watermark levels
+	 * that will support both the old and new plane configuration
+	 * since we can't flip over to the final watermarks until
+	 * the plane configuration has been latched at some future vblank.
+	 *
+	 * Additionally if there's already an update pending, we can't
+	 * yet be sure which plane configuration will be active at the
+	 * time we apply the intermediate watermarks, so we must account
+	 * for both possibilities.
+	 */
+	mutex_lock(&dev_priv->wm.mutex);
+
+	intm_pending = crtc->wm.pending;
+	*intm = crtc->wm.active;
+
+	spin_lock_irq(&crtc->wm.lock);
+	dirty = crtc->wm.dirty;
+	spin_unlock_irq(&crtc->wm.lock);
+
+	mutex_unlock(&dev_priv->wm.mutex);
+
+	/*
+	 * If the intermediate watermarks aren't valid, we must tell the user to
+	 * try something a bit different. There are two cases to be considered.
+	 * 1) there is no pending update:
+	 *    If the intermediate watermarks for transitioning from the currently
+	 *    active configuration to the new configuration aren't valid, the
+	 *    user must choose another configuration as there is no safe way to
+	 *    transition from the currently active config to the new config.
+	 * 2) there is a pending update:
+	 *    If the intermediate watermarks for transitioning from the ccurrently
+	 *    pending configuration to the new configuration are valid, we can
+	 *    simply tell the user to try again after a while.
+	 */
+	if (dirty) {
+		ilk_wm_merge_intermediate(dev, &intm_pending, target);
+		if (!ilk_validate_pipe_wm(dev, &intm_pending))
+			return -EINVAL;
+
+		ilk_wm_merge_intermediate(dev, intm, &intm_pending);
+		if (!ilk_validate_pipe_wm(dev, intm))
+			return -EAGAIN;
+	} else {
+		ilk_wm_merge_intermediate(dev, intm, target);
+		if (!ilk_validate_pipe_wm(dev, intm))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void ilk_watermark_work(struct work_struct *work)
 {
 	struct drm_i915_private *dev_priv =
@@ -2964,18 +3029,46 @@ static void ilk_wm_cancel(struct intel_crtc *crtc)
 	}
 }
 
-static void ilk_update_sprite_wm(struct drm_plane *plane,
-				     struct drm_crtc *crtc,
-				     uint32_t sprite_width, int pixel_size,
-				     bool enabled, bool scaled)
+static int ilk_update_primary_wm(struct intel_crtc *crtc,
+				 struct intel_crtc_wm_config *config)
+{
+	struct ilk_pipe_wm_parameters params = {};
+
+	ilk_compute_wm_parameters(&crtc->base, &params);
+
+	params.pri = config->pri;
+
+	intel_compute_pipe_wm(&crtc->base, &params, &config->target);
+
+	return ilk_pipe_compute_watermarks(crtc,
+					   &config->target,
+					   &config->intm);
+}
+
+static int ilk_update_cursor_wm(struct intel_crtc *crtc,
+				struct intel_crtc_wm_config *config)
+{
+	struct ilk_pipe_wm_parameters params = {};
+
+	ilk_compute_wm_parameters(&crtc->base, &params);
+
+	params.cur = config->cur;
+
+	intel_compute_pipe_wm(&crtc->base, &params, &config->target);
+
+	return ilk_pipe_compute_watermarks(crtc,
+					   &config->target,
+					   &config->intm);
+}
+
+static int ilk_update_sprite_wm(struct intel_plane *plane,
+				struct intel_crtc *crtc,
+				struct intel_crtc_wm_config *config)
 {
-	struct drm_device *dev = plane->dev;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_device *dev = crtc->base.dev;
+	struct ilk_pipe_wm_parameters params = {};
 
-	intel_plane->wm.enabled = enabled;
-	intel_plane->wm.scaled = scaled;
-	intel_plane->wm.horiz_pixels = sprite_width;
-	intel_plane->wm.bytes_per_pixel = pixel_size;
+	ilk_compute_wm_parameters(&crtc->base, &params);
 
 	/*
 	 * IVB workaround: must disable low power watermarks for at least
@@ -2984,10 +3077,17 @@ static void ilk_update_sprite_wm(struct drm_plane *plane,
 	 *
 	 * WaCxSRDisabledForSpriteScaling:ivb
 	 */
-	if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
-		intel_wait_for_vblank(dev, intel_plane->pipe);
+	if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
+		intel_wait_for_vblank(dev, plane->pipe);
+
+	params.pri = config->pri;
+	params.spr = config->spr;
+
+	intel_compute_pipe_wm(&crtc->base, &params, &config->target);
 
-	ilk_update_wm(crtc);
+	return ilk_pipe_compute_watermarks(crtc,
+					   &config->target,
+					   &config->intm);
 }
 
 static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
@@ -3086,16 +3186,38 @@ void intel_update_watermarks(struct drm_crtc *crtc)
 		dev_priv->display.update_wm(crtc);
 }
 
-void intel_update_sprite_watermarks(struct drm_plane *plane,
-				    struct drm_crtc *crtc,
-				    uint32_t sprite_width, int pixel_size,
-				    bool enabled, bool scaled)
+int intel_update_primary_watermarks(struct intel_crtc *crtc,
+				    struct intel_crtc_wm_config *config)
 {
-	struct drm_i915_private *dev_priv = plane->dev->dev_private;
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+	if (dev_priv->display.update_primary_wm)
+		return dev_priv->display.update_primary_wm(crtc, config);
+
+	return 0;
+}
+
+int intel_update_cursor_watermarks(struct intel_crtc *crtc,
+				   struct intel_crtc_wm_config *config)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+	if (dev_priv->display.update_cursor_wm)
+		return dev_priv->display.update_cursor_wm(crtc, config);
+
+	return 0;
+}
+
+int intel_update_sprite_watermarks(struct intel_plane *plane,
+				   struct intel_crtc *crtc,
+				   struct intel_crtc_wm_config *config)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 
 	if (dev_priv->display.update_sprite_wm)
-		dev_priv->display.update_sprite_wm(plane, crtc, sprite_width,
-						   pixel_size, enabled, scaled);
+		return dev_priv->display.update_sprite_wm(plane, crtc, config);
+
+	return 0;
 }
 
 void intel_program_watermarks_pre(struct intel_crtc *crtc,
@@ -6653,7 +6775,8 @@ void intel_init_pm(struct drm_device *dev)
 		     dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
 		    (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
 		     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
-			dev_priv->display.update_wm = ilk_update_wm;
+			dev_priv->display.update_primary_wm = ilk_update_primary_wm;
+			dev_priv->display.update_cursor_wm = ilk_update_cursor_wm;
 			dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
 			dev_priv->display.program_wm_pre = ilk_program_wm_pre;
 			dev_priv->display.program_wm_post = ilk_program_wm_post;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index d6acd6b..c9b1750 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -131,7 +131,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	int reg = DSPCNTR(crtc->plane);
 
-	if (crtc->primary_enabled)
+	if (crtc->pri_wm.enabled)
 		I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
 	else
 		I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
@@ -143,7 +143,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
 		 unsigned int crtc_w, unsigned int crtc_h,
 		 uint32_t x, uint32_t y,
-		 uint32_t src_w, uint32_t src_h)
+		 uint32_t src_w, uint32_t src_h,
+		 const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = dplane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -218,9 +219,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 
 	sprctl |= SP_ENABLE;
 
-	intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -234,6 +232,10 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 							fb->pitches[0]);
 	linear_offset -= sprsurf_offset;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -255,10 +257,13 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static void
-vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
+vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
+		  const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = dplane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -269,6 +274,10 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
 	u32 start_vbl_count;
 	bool atomic_update;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -283,7 +292,7 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
 
-	intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static int
@@ -343,7 +352,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
 		 unsigned int crtc_w, unsigned int crtc_h,
 		 uint32_t x, uint32_t y,
-		 uint32_t src_w, uint32_t src_h)
+		 uint32_t src_w, uint32_t src_h,
+		 const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -406,9 +416,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
 
-	intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -424,6 +431,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 					       pixel_size, fb->pitches[0]);
 	linear_offset -= sprsurf_offset;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -451,10 +462,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static void
-ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
+ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+		  const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -464,6 +478,10 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 	u32 start_vbl_count;
 	bool atomic_update;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -480,13 +498,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
 
-	/*
-	 * Avoid underruns when disabling the sprite.
-	 * FIXME remove once watermark updates are done properly.
-	 */
-	intel_wait_for_vblank(dev, pipe);
-
-	intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static int
@@ -549,7 +561,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
 		 unsigned int crtc_w, unsigned int crtc_h,
 		 uint32_t x, uint32_t y,
-		 uint32_t src_w, uint32_t src_h)
+		 uint32_t src_w, uint32_t src_h,
+		 const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -606,9 +619,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
 	dvscntr |= DVS_ENABLE;
 
-	intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -625,6 +635,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 					       pixel_size, fb->pitches[0]);
 	linear_offset -= dvssurf_offset;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -647,10 +661,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static void
-ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
+ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+		  const struct intel_crtc_wm_config *config)
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -660,6 +677,10 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 	u32 start_vbl_count;
 	bool atomic_update;
 
+	intel_crtc->pri_wm = config->pri;
+	intel_plane->wm = config->spr;
+	intel_program_watermarks_pre(intel_crtc, config);
+
 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
@@ -675,13 +696,7 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
 
-	/*
-	 * Avoid underruns when disabling the sprite.
-	 * FIXME remove once watermark updates are done properly.
-	 */
-	intel_wait_for_vblank(dev, pipe);
-
-	intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
+	intel_program_watermarks_post(intel_crtc, config);
 }
 
 static void
@@ -801,6 +816,19 @@ static bool colorkey_enabled(struct intel_plane *intel_plane)
 	return key.flags != I915_SET_COLORKEY_NONE;
 }
 
+static void update_pri_params(struct intel_crtc *crtc,
+			      struct intel_plane_wm_parameters *params,
+			      bool primary_enabled)
+{
+	if (!crtc->active || !primary_enabled)
+		return;
+
+	params->horiz_pixels = crtc->config.pipe_src_w;
+	params->bytes_per_pixel =
+		drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
+	params->enabled = true;
+}
+
 static int
 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -852,6 +880,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		.src_w = src_w,
 		.src_h = src_h,
 	};
+	struct intel_crtc_wm_config config = {};
 
 	/* Don't modify another pipe's plane */
 	if (intel_plane->pipe != intel_crtc->pipe) {
@@ -989,6 +1018,19 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane);
 	WARN_ON(!primary_enabled && !visible && intel_crtc->active);
 
+	if (visible) {
+		config.spr.horiz_pixels = src_w;
+		config.spr.bytes_per_pixel = pixel_size;
+		config.spr.enabled = true;
+		config.spr.scaled = src_w != crtc_w || src_h != crtc_h;
+	}
+
+	update_pri_params(intel_crtc, &config.pri, primary_enabled);
+
+	ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
+	if (ret)
+		return ret;
+
 	mutex_lock(&dev->struct_mutex);
 
 	/* Note that this will apply the VT-d workaround for scanouts,
@@ -1027,9 +1069,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		if (visible)
 			intel_plane->update_plane(plane, crtc, fb, obj,
 						  crtc_x, crtc_y, crtc_w, crtc_h,
-						  src_x, src_y, src_w, src_h);
+						  src_x, src_y, src_w, src_h,
+						  &config);
 		else
-			intel_plane->disable_plane(plane, crtc);
+			intel_plane->disable_plane(plane, crtc, &config);
 
 		if (!primary_was_enabled && primary_enabled)
 			intel_post_enable_primary(crtc);
@@ -1060,6 +1103,8 @@ intel_disable_plane(struct drm_plane *plane)
 	struct drm_device *dev = plane->dev;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct intel_crtc *intel_crtc;
+	struct intel_crtc_wm_config config = {};
+	int ret;
 
 	if (!plane->fb)
 		return 0;
@@ -1069,12 +1114,18 @@ intel_disable_plane(struct drm_plane *plane)
 
 	intel_crtc = to_intel_crtc(plane->crtc);
 
+	update_pri_params(intel_crtc, &config.pri, true);
+
+	ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
+	if (ret)
+		return ret;
+
 	if (intel_crtc->active) {
 		bool primary_was_enabled = intel_crtc->primary_enabled;
 
 		intel_crtc->primary_enabled = true;
 
-		intel_plane->disable_plane(plane, plane->crtc);
+		intel_plane->disable_plane(plane, plane->crtc, &config);
 
 		if (!primary_was_enabled && intel_crtc->primary_enabled)
 			intel_post_enable_primary(plane->crtc);
-- 
1.8.5.5

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

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

* [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (8 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 13:54   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH 11/16] drm/i915: Refactor get_other_active_crtc() ville.syrjala
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

After we've disabled the planes, it seems like a good idea wait for
the vblank driven watermark updates to finish before we turn off the
vblank interrupts and eventually the entire pipe.

v2: Rebase and s/intel_crtc/crtc/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |  1 +
 drivers/gpu/drm/i915/intel_display.c |  2 ++
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 drivers/gpu/drm/i915/intel_pm.c      | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5b1404e..1fe0cac 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1554,6 +1554,7 @@ struct drm_i915_private {
 		struct mutex mutex;
 
 		struct work_struct work;
+		wait_queue_head_t wait;
 	} wm;
 
 	struct i915_runtime_pm pm;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5bf1633..ca362db 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3960,6 +3960,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
 	intel_disable_planes(crtc);
 	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
+	ilk_wm_synchronize(intel_crtc);
+
 	drm_vblank_off(dev, pipe);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1ec4379..5ad7ad5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1021,6 +1021,7 @@ void intel_program_watermarks_pre(struct intel_crtc *crtc,
 				  const struct intel_crtc_wm_config *config);
 void intel_program_watermarks_post(struct intel_crtc *crtc,
 				   const struct intel_crtc_wm_config *config);
+void ilk_wm_synchronize(struct intel_crtc *crtc);
 
 
 /* intel_sdvo.c */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 13366b7..1c072cd 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2812,6 +2812,7 @@ static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
 
 static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc;
 	bool changed = false;
 
@@ -2833,6 +2834,9 @@ static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
 		changed = true;
 	}
 
+	if (changed)
+		wake_up_all(&dev_priv->wm.wait);
+
 	return changed;
 }
 
@@ -3029,6 +3033,33 @@ static void ilk_wm_cancel(struct intel_crtc *crtc)
 	}
 }
 
+void ilk_wm_synchronize(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum pipe pipe = crtc->pipe;
+	unsigned long timeout = msecs_to_jiffies(100);
+
+	wait_event_timeout(dev_priv->wm.wait, !crtc->wm.dirty, timeout);
+
+	mutex_lock(&dev_priv->wm.mutex);
+
+	spin_lock_irq(&crtc->wm.lock);
+
+	WARN(crtc->wm.dirty, "pipe %c watermark updates failed to complete\n",
+	     pipe_name(pipe));
+
+	/* clean up if something is left behind */
+	ilk_wm_cancel(crtc);
+
+	spin_unlock_irq(&crtc->wm.lock);
+
+	/* pending update (if any) got cancelled */
+	crtc->wm.pending = crtc->wm.active;
+
+	mutex_unlock(&dev_priv->wm.mutex);
+}
+
 static int ilk_update_primary_wm(struct intel_crtc *crtc,
 				 struct intel_crtc_wm_config *config)
 {
@@ -6736,6 +6767,7 @@ void intel_init_pm(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	mutex_init(&dev_priv->wm.mutex);
+	init_waitqueue_head(&dev_priv->wm.wait);
 	INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);
 
 	if (HAS_FBC(dev)) {
-- 
1.8.5.5

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

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

* [PATCH 11/16] drm/i915: Refactor get_other_active_crtc()
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (9 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 16:59   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes ville.syrjala
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pull the code to locate the other active crtc out from
haswell_mode_set_planes_workaround() into a separate function.
This will have another use later.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ca362db..bccf414 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3965,6 +3965,26 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
 	drm_vblank_off(dev, pipe);
 }
 
+static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct intel_crtc *crtc_it, *other_active_crtc = NULL;
+
+	/* We want to get the other_active_crtc only if there's only 1 other
+	 * active crtc. */
+	for_each_intel_crtc(dev, crtc_it) {
+		if (!crtc_it->active || crtc_it == crtc)
+			continue;
+
+		if (other_active_crtc)
+			return NULL;
+
+		other_active_crtc = crtc_it;
+	}
+
+	return other_active_crtc;
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -4057,19 +4077,8 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
 static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
-	struct intel_crtc *crtc_it, *other_active_crtc = NULL;
-
-	/* We want to get the other_active_crtc only if there's only 1 other
-	 * active crtc. */
-	for_each_intel_crtc(dev, crtc_it) {
-		if (!crtc_it->active || crtc_it == crtc)
-			continue;
+	struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc);
 
-		if (other_active_crtc)
-			return;
-
-		other_active_crtc = crtc_it;
-	}
 	if (!other_active_crtc)
 		return;
 
-- 
1.8.5.5

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

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

* [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (10 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 11/16] drm/i915: Refactor get_other_active_crtc() ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 18:24   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks ville.syrjala
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

When we switch between one active pipe and multiple active pipes, the
display FIFO gets repartitioned. Disable the LP1+ waterwarks while that
is happening to make sure we don't get any glitches on other active
pipes while doing a modeset on another other pipe.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 45 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |  2 ++
 drivers/gpu/drm/i915/intel_pm.c      | 47 ++++++++++++++++++++++++++++++++----
 3 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bccf414..311c0f0 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3985,6 +3985,27 @@ static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc)
 	return other_active_crtc;
 }
 
+static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc);
+
+	/*
+	 * If we change between one pipe and multiple pipes,
+	 * make sure the other active pipe is prepared
+	 * for having its FIFO resized. We do that by making
+	 * sure the pipe isn't using LP1+ watermarks when
+	 * the second pipe gets enabled or disabled.
+	 */
+	if (!other_active_crtc)
+		return;
+
+	ilk_wm_synchronize(other_active_crtc);
+
+	if (ilk_disable_lp_wm(dev))
+		intel_wait_for_vblank(dev, other_active_crtc->pipe);
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -4023,6 +4044,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
 	intel_crtc->active = true;
 
+	/* Make sure other pipes are prepared for FIFO resizing */
+	ilk_prepare_for_num_pipes_change(intel_crtc);
+
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 	intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
 
@@ -4123,6 +4147,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 
 	intel_crtc->active = true;
 
+	/* Make sure other pipes are prepared for FIFO resizing */
+	ilk_prepare_for_num_pipes_change(intel_crtc);
+
 	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 	if (intel_crtc->config.has_pch_encoder)
 		intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
@@ -4192,6 +4219,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
 	intel_crtc_disable_planes(crtc);
 
+	/* Make sure other pipes are prepared for FIFO resizing */
+	ilk_prepare_for_num_pipes_change(intel_crtc);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->disable(encoder);
 
@@ -4235,6 +4265,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
 	intel_crtc->active = false;
 
+	/*
+	 * Potentially let some other pipe use the
+	 * full FIFO, and re-enable LP1+ watermarks.
+	 */
+	ilk_wm_pipe_post_disable(intel_crtc);
+
 	mutex_lock(&dev->struct_mutex);
 	intel_update_fbc(dev);
 	intel_edp_psr_update(dev);
@@ -4255,6 +4291,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
 	intel_crtc_disable_planes(crtc);
 
+	/* Make sure other pipes are prepared for FIFO resizing */
+	ilk_prepare_for_num_pipes_change(intel_crtc);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		intel_opregion_notify_encoder(encoder, false);
 		encoder->disable(encoder);
@@ -4282,6 +4321,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
 	intel_crtc->active = false;
 
+	/*
+	 * Potentially let some other pipe use the
+	 * full FIFO, and re-enable LP1+ watermarks.
+	 */
+	ilk_wm_pipe_post_disable(intel_crtc);
+
 	mutex_lock(&dev->struct_mutex);
 	intel_update_fbc(dev);
 	intel_edp_psr_update(dev);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5ad7ad5..98f878f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1022,6 +1022,8 @@ void intel_program_watermarks_pre(struct intel_crtc *crtc,
 void intel_program_watermarks_post(struct intel_crtc *crtc,
 				   const struct intel_crtc_wm_config *config);
 void ilk_wm_synchronize(struct intel_crtc *crtc);
+void ilk_wm_pipe_post_disable(struct intel_crtc *crtc);
+bool ilk_disable_lp_wm(struct drm_device *dev);
 
 
 /* intel_sdvo.c */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1c072cd..18ea8b1 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2765,7 +2765,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
 	}
 }
 
-static bool ilk_disable_lp_wm(struct drm_device *dev)
+bool ilk_disable_lp_wm(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	bool changed;
@@ -2873,16 +2873,17 @@ static void ilk_program_watermarks(struct drm_device *dev)
 	ilk_write_wm_values(dev_priv, &results);
 }
 
-static void ilk_update_watermarks(struct drm_device *dev)
+static void ilk_update_watermarks(struct drm_device *dev, bool force)
 {
 	bool changed;
 
 	changed = ilk_refresh_pending_watermarks(dev);
 
-	if (changed)
+	if (changed || force)
 		ilk_program_watermarks(dev);
 }
 
+/* Prepare the pipe to update the its watermarks on the next vblank */
 static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
 					 const struct intel_pipe_wm *pipe_wm,
 					 u32 vbl_count)
@@ -2905,7 +2906,7 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
 	spin_unlock_irq(&crtc->wm.lock);
 
 	/* try to update immediately */
-	ilk_update_watermarks(dev);
+	ilk_update_watermarks(dev, false);
 
 	spin_lock_irq(&crtc->wm.lock);
 
@@ -2999,7 +3000,7 @@ static void ilk_watermark_work(struct work_struct *work)
 
 	mutex_lock(&dev_priv->wm.mutex);
 
-	ilk_update_watermarks(dev_priv->dev);
+	ilk_update_watermarks(dev_priv->dev, false);
 
 	mutex_unlock(&dev_priv->wm.mutex);
 }
@@ -3060,6 +3061,42 @@ void ilk_wm_synchronize(struct intel_crtc *crtc)
 	mutex_unlock(&dev_priv->wm.mutex);
 }
 
+void ilk_wm_pipe_post_disable(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct ilk_pipe_wm_parameters params = {};
+	struct intel_pipe_wm pipe_wm = {};
+
+	WARN(crtc->active, "pipe %c should be disabled\n",
+	     pipe_name(crtc->pipe));
+
+	ilk_compute_wm_parameters(&crtc->base, &params);
+
+	intel_compute_pipe_wm(&crtc->base, &params, &pipe_wm);
+
+	mutex_lock(&dev_priv->wm.mutex);
+
+	spin_lock_irq(&crtc->wm.lock);
+
+	WARN(crtc->wm.dirty, "pipe %c disabled with dirty watermarks\n",
+	     pipe_name(crtc->pipe));
+
+	/* clean up if something is left behind */
+	ilk_wm_cancel(crtc);
+
+	spin_unlock_irq(&crtc->wm.lock);
+
+	crtc->wm.active = pipe_wm;
+
+	/* pending update (if any) got cancelled */
+	crtc->wm.pending = crtc->wm.active;
+
+	ilk_update_watermarks(dev, true);
+
+	mutex_unlock(&dev_priv->wm.mutex);
+}
+
 static int ilk_update_primary_wm(struct intel_crtc *crtc,
 				 struct intel_crtc_wm_config *config)
 {
-- 
1.8.5.5

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

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

* [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (11 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 18:30   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled ville.syrjala
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Currently ilk_disable_lp_wm() just disabled LP1+ watermarks directly.
However there's nothing preventing someone else from re-enabling them
immediately. To make sure sure LP1+ watermarks stay disabled for the
intended period, keep track which pipes require the LP1+ watermarks
to be disabled.

v2: Rebase and s/intel_crtc/crtc/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |  6 ++++++
 drivers/gpu/drm/i915/intel_display.c |  2 +-
 drivers/gpu/drm/i915/intel_drv.h     |  2 +-
 drivers/gpu/drm/i915/intel_pm.c      | 22 ++++++++++++++++++----
 4 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1fe0cac..02ffbfc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1548,6 +1548,12 @@ struct drm_i915_private {
 		struct ilk_wm_values hw;
 
 		/*
+		 * bitmask of pipes that have requested
+		 * LP1+ watermarks to be disabled.
+		 */
+		unsigned int lp_disabled;
+
+		/*
 		 * protects some dev_priv->wm and intel_crtc->wm
 		 * state as well as the actual hardware registers
 		 */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 311c0f0..879c649 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4002,7 +4002,7 @@ static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc)
 
 	ilk_wm_synchronize(other_active_crtc);
 
-	if (ilk_disable_lp_wm(dev))
+	if (ilk_disable_lp_wm(crtc))
 		intel_wait_for_vblank(dev, other_active_crtc->pipe);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 98f878f..2a3ad60 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1023,7 +1023,7 @@ void intel_program_watermarks_post(struct intel_crtc *crtc,
 				   const struct intel_crtc_wm_config *config);
 void ilk_wm_synchronize(struct intel_crtc *crtc);
 void ilk_wm_pipe_post_disable(struct intel_crtc *crtc);
-bool ilk_disable_lp_wm(struct drm_device *dev);
+bool ilk_disable_lp_wm(struct intel_crtc *crtc);
 
 
 /* intel_sdvo.c */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 18ea8b1..17f1769 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2428,6 +2428,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
 				   enum intel_ddb_partitioning partitioning,
 				   struct ilk_wm_values *results)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
 	int level, wm_lp;
 
@@ -2451,7 +2452,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
 			(r->pri_val << WM1_LP_SR_SHIFT) |
 			r->cur_val;
 
-		if (r->enable)
+		if (r->enable && !dev_priv->wm.lp_disabled)
 			results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
 
 		if (INTEL_INFO(dev)->gen >= 8)
@@ -2765,13 +2766,18 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
 	}
 }
 
-bool ilk_disable_lp_wm(struct drm_device *dev)
+bool ilk_disable_lp_wm(struct intel_crtc *crtc)
 {
+	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	bool changed;
 
 	mutex_lock(&dev_priv->wm.mutex);
+
+	dev_priv->wm.lp_disabled |= 1 << crtc->pipe;
+
 	changed = _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
+
 	mutex_unlock(&dev_priv->wm.mutex);
 
 	return changed;
@@ -2889,15 +2895,20 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
 					 u32 vbl_count)
 {
 	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum pipe pipe = crtc->pipe;
 
 	WARN(!crtc->active, "pipe %c should be enabled\n",
 	     pipe_name(pipe));
 
 	/* do the watermarks actually need changing? */
-	if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
+	if (!(dev_priv->wm.lp_disabled & (1 << pipe)) &&
+	    !memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
 		return;
 
+	/* allow LP1+ watermarks again */
+	dev_priv->wm.lp_disabled &= ~(1 << pipe);
+
 	crtc->wm.pending = *pipe_wm;
 
 	spin_lock_irq(&crtc->wm.lock);
@@ -3092,6 +3103,9 @@ void ilk_wm_pipe_post_disable(struct intel_crtc *crtc)
 	/* pending update (if any) got cancelled */
 	crtc->wm.pending = crtc->wm.active;
 
+	/* allow LP1+ watermarks again */
+	dev_priv->wm.lp_disabled &= ~(1 << crtc->pipe);
+
 	ilk_update_watermarks(dev, true);
 
 	mutex_unlock(&dev_priv->wm.mutex);
@@ -3145,7 +3159,7 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
 	 *
 	 * WaCxSRDisabledForSpriteScaling:ivb
 	 */
-	if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
+	if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
 		intel_wait_for_vblank(dev, plane->pipe);
 
 	params.pri = config->pri;
-- 
1.8.5.5

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

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

* [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (12 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 18:34   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching ville.syrjala
  2014-05-22 14:48 ` [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled ville.syrjala
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

When the primary plane is disabled, pick the 5/6 DDB split to give the
sprite as much FIFO space as possible.

The normal heuristic of just looking at the highest valid WM level won't
necessarily pick the optimal split since both splits might have the same
number of levels enabled.

Preferring the 5/6 split won't actually affect the watermarks here, but
it does give more FIFO space to the sprite leading to potentially longer
periods spent in LP1+ states since the FIFO takes longer to drain.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h |  1 +
 drivers/gpu/drm/i915/intel_pm.c  | 27 ++++++++++++++++++++++-----
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2a3ad60..4575017 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -354,6 +354,7 @@ struct intel_pipe_wm {
 	uint32_t linetime;
 	bool fbc_wm_enabled;
 	bool pipe_enabled;
+	bool primary_enabled;
 	bool sprites_enabled;
 	bool sprites_scaled;
 };
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 17f1769..66af79d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1736,6 +1736,7 @@ struct ilk_wm_maximums {
 /* used in computing the new watermarks state */
 struct intel_wm_config {
 	unsigned int num_pipes_active;
+	bool primary_enabled;
 	bool sprites_enabled;
 	bool sprites_scaled;
 };
@@ -2212,6 +2213,7 @@ static void ilk_compute_wm_config(struct drm_device *dev,
 		if (!wm->pipe_enabled)
 			continue;
 
+		config->primary_enabled |= wm->primary_enabled;
 		config->sprites_enabled |= wm->sprites_enabled;
 		config->sprites_scaled |= wm->sprites_scaled;
 		config->num_pipes_active++;
@@ -2224,6 +2226,7 @@ static bool ilk_validate_pipe_wm(struct drm_device *dev,
 	/* LP0 watermark maximums depend on this pipe alone */
 	const struct intel_wm_config config = {
 		.num_pipes_active = 1,
+		.primary_enabled = pipe_wm->primary_enabled,
 		.sprites_enabled = pipe_wm->sprites_enabled,
 		.sprites_scaled = pipe_wm->sprites_scaled,
 	};
@@ -2247,6 +2250,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 	struct ilk_wm_maximums max;
 
 	pipe_wm->pipe_enabled = params->active;
+	pipe_wm->primary_enabled = params->pri.enabled;
 	pipe_wm->sprites_enabled = params->spr.enabled;
 	pipe_wm->sprites_scaled = params->spr.scaled;
 
@@ -2299,6 +2303,7 @@ static void ilk_wm_merge_intermediate(struct drm_device *dev,
 	int level, max_level = ilk_wm_max_level(dev);
 
 	a->pipe_enabled |= b->pipe_enabled;
+	a->primary_enabled |= b->primary_enabled;
 	a->sprites_enabled |= b->sprites_enabled;
 	a->sprites_scaled |= b->sprites_scaled;
 
@@ -2491,11 +2496,21 @@ static void ilk_compute_wm_results(struct drm_device *dev,
 	}
 }
 
-/* Find the result with the highest level enabled. Check for enable_fbc_wm in
- * case both are at the same level. Prefer r1 in case they're the same. */
+/*
+ * Find the result with the highest level enabled.
+ * When the max level for each result is the same, pick r2
+ * when the primary plane is disabled, otherwise prefer the
+ * result which has FBC WM enabled. All else being equal, pick
+ * r1.
+ *
+ * FIXME should ideally calculate the FIFO drain time for each
+ * plane, and determine which split has the chance to keep
+ * the memory asleep for longest.
+ */
 static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
 						  struct intel_pipe_wm *r1,
-						  struct intel_pipe_wm *r2)
+						  struct intel_pipe_wm *r2,
+						  bool primary_enabled)
 {
 	int level, max_level = ilk_wm_max_level(dev);
 	int level1 = 0, level2 = 0;
@@ -2508,7 +2523,8 @@ static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
 	}
 
 	if (level1 == level2) {
-		if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled)
+		if (!primary_enabled ||
+		    (r2->fbc_wm_enabled && !r1->fbc_wm_enabled))
 			return r2;
 		else
 			return r1;
@@ -2866,7 +2882,8 @@ static void ilk_program_watermarks(struct drm_device *dev)
 		ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
 		ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
 
-		best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
+		best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6,
+						  config.primary_enabled);
 	} else {
 		best_lp_wm = &lp_wm_1_2;
 	}
-- 
1.8.5.5

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

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

* [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (13 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 18:44   ` Paulo Zanoni
  2014-05-22 14:48 ` [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled ville.syrjala
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

ILK and IVB don't like switching between sprite only and primary only
configurations when LP1+ watermarks have been enabled in the recent
past. Like WaCxSRDisabledForSpriteScaling we can avoid the flash
by disabling LP1+ watermarks for one frame before the critical plane
reconfiguration.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 66af79d..ea1f990 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3175,9 +3175,18 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
 	 * when scaling is disabled.
 	 *
 	 * WaCxSRDisabledForSpriteScaling:ivb
+	 *
+	 * We also seem to need something similar when switching between
+	 * primary only and sprite only configurations. Otherwise the screen
+	 * flashes black. No underrun reported though.
 	 */
 	if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
 		intel_wait_for_vblank(dev, plane->pipe);
+	else if (config->pri.enabled != config->spr.enabled &&
+		 config->pri.enabled != params.pri.enabled &&
+		 config->spr.enabled != params.spr.enabled &&
+		 ilk_disable_lp_wm(crtc))
+		intel_wait_for_vblank(dev, plane->pipe);
 
 	params.pri = config->pri;
 	params.spr = config->spr;
-- 
1.8.5.5

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

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

* [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled
  2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
                   ` (14 preceding siblings ...)
  2014-05-22 14:48 ` [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching ville.syrjala
@ 2014-05-22 14:48 ` ville.syrjala
  2014-06-04 18:49   ` Paulo Zanoni
  15 siblings, 1 reply; 39+ messages in thread
From: ville.syrjala @ 2014-05-22 14:48 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

If we mark the LP1+ watermarks as disabled every time sprite scaling
is enabled, we end doing pointless work applying watermarks even though
nothing has changed. This is an artifact of the way
dev_priv->wm.lp_disabled affects the operation of
ilk_setup_pending_watermarks(). If the current pipe is included in
dev_priv->wm.lp_disabled, ilk_setup_pending_watermarks() will not check
if the watermarks actually changed since it will assume it will need to
disable LP1+ watermarks anyway.

A quick fix is to just check if sprite scaling was enabled for the
previous plane update, and if so, we know that LP1+ watermarks must
already be disabled. It might be better in long run to attempt to
change the way the LP1+ disable tracking integrates with the rest of
the watermark update mechanism. But this seems like a simple enough
solution for now.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index ea1f990..0365ea6 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3180,7 +3180,8 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
 	 * primary only and sprite only configurations. Otherwise the screen
 	 * flashes black. No underrun reported though.
 	 */
-	if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
+	if (IS_IVYBRIDGE(dev) && !params.spr.scaled &&
+	    config->spr.scaled && ilk_disable_lp_wm(crtc))
 		intel_wait_for_vblank(dev, plane->pipe);
 	else if (config->pri.enabled != config->spr.enabled &&
 		 config->pri.enabled != params.pri.enabled &&
-- 
1.8.5.5

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

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

* Re: [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes
  2014-05-22 14:48 ` [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes ville.syrjala
@ 2014-05-26 13:56   ` Daniel Vetter
  2014-06-04  6:00     ` Arun Murthy
  0 siblings, 1 reply; 39+ messages in thread
From: Daniel Vetter @ 2014-05-26 13:56 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx

On Thu, May 22, 2014 at 05:48:06PM +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Because of the upcoming vblank interrupt driven watermark update
> mechanism we will have use for vblank interrupts during plane
> enabling/disabling. So don't call drm_vblank_off() until planes
> are off, and call drm_vblank_on() just before we start to enable
> the planes.
> 
> v2: Pimp commit message (Paulo)
> 
> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Merged up to this one until I've stumbled into the first patch lacking an
r-b. Can you please update the review board a bit with the current state
and maybe repoke reviewers that there's a new series?

Thanks, Daniel

> ---
>  drivers/gpu/drm/i915/intel_display.c | 13 ++++---------
>  1 file changed, 4 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 019e9e1..a11bd78 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3885,6 +3885,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc)
>  	int pipe = intel_crtc->pipe;
>  	int plane = intel_crtc->plane;
>  
> +	drm_vblank_on(dev, pipe);
> +
>  	intel_enable_primary_hw_plane(dev_priv, plane, pipe);
>  	intel_enable_planes(crtc);
>  	/* The fixup needs to happen before cursor is enabled */
> @@ -3910,7 +3912,6 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
>  	int plane = intel_crtc->plane;
>  
>  	intel_crtc_wait_for_pending_flips(crtc);
> -	drm_crtc_vblank_off(crtc);
>  
>  	if (dev_priv->fbc.plane == plane)
>  		intel_disable_fbc(dev);
> @@ -3921,6 +3922,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
>  	intel_crtc_update_cursor(crtc, false);
>  	intel_disable_planes(crtc);
>  	intel_disable_primary_hw_plane(dev_priv, plane, pipe);
> +
> +	drm_vblank_off(dev, pipe);
>  }
>  
>  static void ironlake_crtc_enable(struct drm_crtc *crtc)
> @@ -3999,8 +4002,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>  		cpt_verify_modeset(dev, intel_crtc->pipe);
>  
>  	intel_crtc_enable_planes(crtc);
> -
> -	drm_crtc_vblank_on(crtc);
>  }
>  
>  /* IPS only exists on ULT machines and is tied to pipe A. */
> @@ -4114,8 +4115,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>  	 * to change the workaround. */
>  	haswell_mode_set_planes_workaround(intel_crtc);
>  	intel_crtc_enable_planes(crtc);
> -
> -	drm_crtc_vblank_on(crtc);
>  }
>  
>  static void ironlake_pfit_disable(struct intel_crtc *crtc)
> @@ -4625,8 +4624,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
>  
>  	intel_crtc_enable_planes(crtc);
>  
> -	drm_crtc_vblank_on(crtc);
> -
>  	/* Underruns don't raise interrupts, so check manually. */
>  	i9xx_check_fifo_underruns(dev);
>  }
> @@ -4719,8 +4716,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
>  	if (IS_GEN2(dev))
>  		intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
>  
> -	drm_crtc_vblank_on(crtc);
> -
>  	/* Underruns don't raise interrupts, so check manually. */
>  	i9xx_check_fifo_underruns(dev);
>  }
> -- 
> 1.8.5.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-05-22 14:48 ` [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism ville.syrjala
@ 2014-06-03 18:50   ` Paulo Zanoni
  2014-06-03 19:32     ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-03 18:50 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Add a mechanism by which you can queue up watermark update to happen
> after the vblank counter has reached a certain value. The vblank
> interrupt handler will schedule a work which will do the actual
> watermark programming in process context.
>
> v2: Rebase and s/intel_crtc/crtc/
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   2 +
>  drivers/gpu/drm/i915/i915_irq.c      |  12 ++-
>  drivers/gpu/drm/i915/intel_display.c |   1 +
>  drivers/gpu/drm/i915/intel_drv.h     |  27 +++++++
>  drivers/gpu/drm/i915/intel_pm.c      | 144 +++++++++++++++++++++++++++++++++++
>  5 files changed, 183 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index a2302a7..c90d5ac 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1541,6 +1541,8 @@ struct drm_i915_private {
>                  * state as well as the actual hardware registers
>                  */
>                 struct mutex mutex;
> +
> +               struct work_struct work;
>         } wm;
>
>         struct i915_runtime_pm pm;
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 304f86a..c680020 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2067,8 +2067,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
>                 DRM_ERROR("Poison interrupt\n");
>
>         for_each_pipe(pipe) {
> -               if (de_iir & DE_PIPE_VBLANK(pipe))
> +               if (de_iir & DE_PIPE_VBLANK(pipe)) {
>                         intel_pipe_handle_vblank(dev, pipe);
> +                       ilk_update_pipe_wm(dev, pipe);
> +               }
>
>                 if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
>                         if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
> @@ -2117,8 +2119,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
>                 intel_opregion_asle_intr(dev);
>
>         for_each_pipe(pipe) {
> -               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
> +               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) {
>                         intel_pipe_handle_vblank(dev, pipe);
> +                       ilk_update_pipe_wm(dev, pipe);
> +               }
>
>                 /* plane/pipes map 1:1 on ilk+ */
>                 if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
> @@ -2260,8 +2264,10 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
>                         continue;
>
>                 pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> -               if (pipe_iir & GEN8_PIPE_VBLANK)
> +               if (pipe_iir & GEN8_PIPE_VBLANK) {
>                         intel_pipe_handle_vblank(dev, pipe);
> +                       ilk_update_pipe_wm(dev, pipe);
> +               }
>
>                 if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
>                         intel_prepare_page_flip(dev, pipe);
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index a11bd78..408b238 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10961,6 +10961,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>                 intel_crtc->plane = !pipe;
>         }
>
> +       spin_lock_init(&intel_crtc->wm.lock);
>         init_waitqueue_head(&intel_crtc->vbl_wait);
>
>         BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index d75cc2b..72f01b1 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -409,6 +409,32 @@ struct intel_crtc {
>                  * protected by dev_priv->wm.mutex
>                  */
>                 struct intel_pipe_wm active;
> +               /*
> +                * watermarks queued for next vblank
> +                * protected by dev_priv->wm.mutex
> +                */
> +               struct intel_pipe_wm pending;
> +
> +               /*
> +                * the vblank count after which we can switch over to 'pending'
> +                * protected by intel_crtc->wm.lock
> +                */
> +               u32 pending_vbl_count;
> +               /*
> +                * indicates that 'pending' contains changed watermarks
> +                * protected by intel_crtc->wm.lock
> +                */
> +               bool dirty;
> +               /*
> +                * watermark update has a vblank reference?
> +                * protected by intel_crtc->wm.lock
> +                */
> +               bool vblank;

I would rename this variable. Maybe has_vblank_ref?


> +
> +               /*
> +                * protects some intel_crtc->wm state

Please be more precise on what "some" actually means, since it's easy
to guess that a spinlock protects "some related state" :P


> +                */
> +               spinlock_t lock;
>         } wm;
>
>         wait_queue_head_t vbl_wait;
> @@ -974,6 +1000,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
>  void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
>  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
>  void ilk_wm_get_hw_state(struct drm_device *dev);
> +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);

This chunk needs rebase.


>
>
>  /* intel_sdvo.c */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 2a63418..6fc6416 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2752,6 +2752,65 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
>         return changed;
>  }
>
> +static bool vbl_count_after_eq(struct drm_device *dev, u32 a, u32 b)

Since I had to stop and think for more than 10 seconds to discover if
this was checking for A >= B or A <= B or something else, I think this
function deserves a nice comment explaining what it's supposed to do.


> +{
> +       u32 mask = dev->max_vblank_count;
> +
> +       /* just the msb please */
> +       mask &= ~(mask >> 1);
> +
> +       return !((a - b) & mask);
> +}
> +
> +static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       u32 vbl_count;
> +
> +       assert_spin_locked(&crtc->wm.lock);
> +
> +       if (!crtc->wm.dirty)
> +               return false;
> +
> +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
> +
> +       if (!vbl_count_after_eq(dev, vbl_count, crtc->wm.pending_vbl_count))
> +               return false;
> +
> +       if (crtc->wm.vblank) {
> +               drm_vblank_put(dev, crtc->pipe);
> +               crtc->wm.vblank = false;
> +       }
> +
> +       return true;
> +}
> +
> +static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
> +{
> +       struct intel_crtc *crtc;
> +       bool changed = false;
> +
> +       for_each_intel_crtc(dev, crtc) {
> +               bool ready;
> +
> +               spin_lock_irq(&crtc->wm.lock);
> +
> +               ready = ilk_pending_watermarks_ready(crtc);
> +               if (ready)
> +                       crtc->wm.dirty = false;
> +
> +               spin_unlock_irq(&crtc->wm.lock);
> +
> +               if (!ready)
> +                       continue;
> +
> +               crtc->wm.active = crtc->wm.pending;
> +               changed = true;
> +       }
> +
> +       return changed;
> +}
> +
>  static void ilk_program_watermarks(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -2810,6 +2869,87 @@ static void ilk_update_wm(struct drm_crtc *crtc)
>         mutex_unlock(&dev_priv->wm.mutex);
>  }
>
> +static void ilk_update_watermarks(struct drm_device *dev)

Now we have ilk_update_wm() and ilk_update_watermarks(). This is
confusing, since one can't really tell the difference just by reading
the name. Maybe we should rename one of them (unless a future patch
kills one of them, which I didn't check yet).


> +{
> +       bool changed;
> +
> +       changed = ilk_refresh_pending_watermarks(dev);
> +
> +       if (changed)
> +               ilk_program_watermarks(dev);

Also, don't we need to grab dev_priv->wm.mutex here? I'm asking since
the other caller of ilk_program_watermarks() has the mutex locked. It
should probably help if we had assert_mutex_is_locked() at some
places. Or maybe the callers of ilk_program_watermarks() would need
the lock.


> +}
> +
> +static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
> +                                        const struct intel_pipe_wm *pipe_wm,
> +                                        u32 vbl_count)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       enum pipe pipe = crtc->pipe;
> +
> +       WARN(!crtc->active, "pipe %c should be enabled\n",
> +            pipe_name(pipe));
> +
> +       /* do the watermarks actually need changing? */
> +       if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
> +               return;
> +
> +       crtc->wm.pending = *pipe_wm;
> +
> +       spin_lock_irq(&crtc->wm.lock);
> +       crtc->wm.pending_vbl_count = (vbl_count + 1) & dev->max_vblank_count;
> +       crtc->wm.dirty = true;
> +       spin_unlock_irq(&crtc->wm.lock);
> +
> +       /* try to update immediately */
> +       ilk_update_watermarks(dev);

I'm failing to imagine a case where this would help. Can you please tell me?


> +
> +       spin_lock_irq(&crtc->wm.lock);
> +
> +       /* did the immediate update succeed? */
> +       if (!crtc->wm.dirty)
> +               goto unlock;
> +
> +       /*
> +        * We might already have a pending watermark update, in
> +        * which case we shouldn't grab another vblank reference.
> +        */
> +       if (!crtc->wm.vblank && drm_vblank_get(dev, pipe) == 0)
> +               crtc->wm.vblank = true;
> +
> +       WARN(!crtc->wm.vblank,
> +            "unable to set up watermarks for pipe %c\n", pipe_name(pipe));
> +
> + unlock:
> +       spin_unlock_irq(&crtc->wm.lock);
> +}
> +
> +static void ilk_watermark_work(struct work_struct *work)
> +{
> +       struct drm_i915_private *dev_priv =
> +               container_of(work, struct drm_i915_private, wm.work);
> +
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       ilk_update_watermarks(dev_priv->dev);
> +
> +       mutex_unlock(&dev_priv->wm.mutex);
> +}
> +
> +/* Called from vblank irq */
> +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
> +{
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct intel_crtc *crtc =
> +               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +
> +       spin_lock(&crtc->wm.lock);
> +
> +       if (ilk_pending_watermarks_ready(crtc))
> +               schedule_work(&dev_priv->wm.work);
> +
> +       spin_unlock(&crtc->wm.lock);
> +}
> +
>  static void ilk_update_sprite_wm(struct drm_plane *plane,
>                                      struct drm_crtc *crtc,
>                                      uint32_t sprite_width, int pixel_size,
> @@ -2872,6 +3012,9 @@ static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
>                 for (level = 0; level <= max_level; level++)
>                         active->wm[level].enable = true;
>         }
> +
> +       /* no update pending */
> +       intel_crtc->wm.pending = intel_crtc->wm.active;

It feels a little weird that the function that gets the HW state will
also cancel any scheduled watermark updates. Programmers from the
future are really bad, they will probably not notice this and
introduce bugs.


>  }
>
>  void ilk_wm_get_hw_state(struct drm_device *dev)
> @@ -6385,6 +6528,7 @@ void intel_init_pm(struct drm_device *dev)
>         struct drm_i915_private *dev_priv = dev->dev_private;
>
>         mutex_init(&dev_priv->wm.mutex);
> +       INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);

Don't we also need to cancel the work in the places where we disable
interrupts? Maybe it is possible to schedule a WM update, then disable
everything and runtime suspend before the scheduled work happens... Or
do something similar at S3 or driver unload.

Since there's no caller for ilk_setup_pending_watermarks() I guess
this patch will introduce a compiler warning here. I'm not sure what's
our policy for that... I guess I'd vote to merge only when the next
patches also have their RB tags.


>
>         if (HAS_FBC(dev)) {
>                 if (INTEL_INFO(dev)->gen >= 7) {
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-06-03 18:50   ` Paulo Zanoni
@ 2014-06-03 19:32     ` Ville Syrjälä
  2014-06-04 14:01       ` Paulo Zanoni
  0 siblings, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-03 19:32 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Tue, Jun 03, 2014 at 03:50:12PM -0300, Paulo Zanoni wrote:
> 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > Add a mechanism by which you can queue up watermark update to happen
> > after the vblank counter has reached a certain value. The vblank
> > interrupt handler will schedule a work which will do the actual
> > watermark programming in process context.
> >
> > v2: Rebase and s/intel_crtc/crtc/
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_drv.h      |   2 +
> >  drivers/gpu/drm/i915/i915_irq.c      |  12 ++-
> >  drivers/gpu/drm/i915/intel_display.c |   1 +
> >  drivers/gpu/drm/i915/intel_drv.h     |  27 +++++++
> >  drivers/gpu/drm/i915/intel_pm.c      | 144 +++++++++++++++++++++++++++++++++++
> >  5 files changed, 183 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index a2302a7..c90d5ac 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -1541,6 +1541,8 @@ struct drm_i915_private {
> >                  * state as well as the actual hardware registers
> >                  */
> >                 struct mutex mutex;
> > +
> > +               struct work_struct work;
> >         } wm;
> >
> >         struct i915_runtime_pm pm;
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 304f86a..c680020 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2067,8 +2067,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
> >                 DRM_ERROR("Poison interrupt\n");
> >
> >         for_each_pipe(pipe) {
> > -               if (de_iir & DE_PIPE_VBLANK(pipe))
> > +               if (de_iir & DE_PIPE_VBLANK(pipe)) {
> >                         intel_pipe_handle_vblank(dev, pipe);
> > +                       ilk_update_pipe_wm(dev, pipe);
> > +               }
> >
> >                 if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
> >                         if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
> > @@ -2117,8 +2119,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
> >                 intel_opregion_asle_intr(dev);
> >
> >         for_each_pipe(pipe) {
> > -               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
> > +               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) {
> >                         intel_pipe_handle_vblank(dev, pipe);
> > +                       ilk_update_pipe_wm(dev, pipe);
> > +               }
> >
> >                 /* plane/pipes map 1:1 on ilk+ */
> >                 if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
> > @@ -2260,8 +2264,10 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
> >                         continue;
> >
> >                 pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> > -               if (pipe_iir & GEN8_PIPE_VBLANK)
> > +               if (pipe_iir & GEN8_PIPE_VBLANK) {
> >                         intel_pipe_handle_vblank(dev, pipe);
> > +                       ilk_update_pipe_wm(dev, pipe);
> > +               }
> >
> >                 if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
> >                         intel_prepare_page_flip(dev, pipe);
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index a11bd78..408b238 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -10961,6 +10961,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
> >                 intel_crtc->plane = !pipe;
> >         }
> >
> > +       spin_lock_init(&intel_crtc->wm.lock);
> >         init_waitqueue_head(&intel_crtc->vbl_wait);
> >
> >         BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index d75cc2b..72f01b1 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -409,6 +409,32 @@ struct intel_crtc {
> >                  * protected by dev_priv->wm.mutex
> >                  */
> >                 struct intel_pipe_wm active;
> > +               /*
> > +                * watermarks queued for next vblank
> > +                * protected by dev_priv->wm.mutex
> > +                */
> > +               struct intel_pipe_wm pending;
> > +
> > +               /*
> > +                * the vblank count after which we can switch over to 'pending'
> > +                * protected by intel_crtc->wm.lock
> > +                */
> > +               u32 pending_vbl_count;
> > +               /*
> > +                * indicates that 'pending' contains changed watermarks
> > +                * protected by intel_crtc->wm.lock
> > +                */
> > +               bool dirty;
> > +               /*
> > +                * watermark update has a vblank reference?
> > +                * protected by intel_crtc->wm.lock
> > +                */
> > +               bool vblank;
> 
> I would rename this variable. Maybe has_vblank_ref?

I think I had it something like that originally but changed it at some
point when I got tired of the extra characters ;) I can change it back.

> 
> 
> > +
> > +               /*
> > +                * protects some intel_crtc->wm state
> 
> Please be more precise on what "some" actually means, since it's easy
> to guess that a spinlock protects "some related state" :P

The precise part is there in the comments for each struct member.

> 
> 
> > +                */
> > +               spinlock_t lock;
> >         } wm;
> >
> >         wait_queue_head_t vbl_wait;
> > @@ -974,6 +1000,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
> >  void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
> >  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
> >  void ilk_wm_get_hw_state(struct drm_device *dev);
> > +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
> 
> This chunk needs rebase.
> 
> 
> >
> >
> >  /* intel_sdvo.c */
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 2a63418..6fc6416 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -2752,6 +2752,65 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
> >         return changed;
> >  }
> >
> > +static bool vbl_count_after_eq(struct drm_device *dev, u32 a, u32 b)
> 
> Since I had to stop and think for more than 10 seconds to discover if
> this was checking for A >= B or A <= B or something else, I think this
> function deserves a nice comment explaining what it's supposed to do.

I added such a comment for the flip counter check, but forgot to
add one here. Will add it.

> 
> 
> > +{
> > +       u32 mask = dev->max_vblank_count;
> > +
> > +       /* just the msb please */
> > +       mask &= ~(mask >> 1);
> > +
> > +       return !((a - b) & mask);
> > +}
> > +
> > +static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       u32 vbl_count;
> > +
> > +       assert_spin_locked(&crtc->wm.lock);
> > +
> > +       if (!crtc->wm.dirty)
> > +               return false;
> > +
> > +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
> > +
> > +       if (!vbl_count_after_eq(dev, vbl_count, crtc->wm.pending_vbl_count))
> > +               return false;
> > +
> > +       if (crtc->wm.vblank) {
> > +               drm_vblank_put(dev, crtc->pipe);
> > +               crtc->wm.vblank = false;
> > +       }
> > +
> > +       return true;
> > +}
> > +
> > +static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
> > +{
> > +       struct intel_crtc *crtc;
> > +       bool changed = false;
> > +
> > +       for_each_intel_crtc(dev, crtc) {
> > +               bool ready;
> > +
> > +               spin_lock_irq(&crtc->wm.lock);
> > +
> > +               ready = ilk_pending_watermarks_ready(crtc);
> > +               if (ready)
> > +                       crtc->wm.dirty = false;
> > +
> > +               spin_unlock_irq(&crtc->wm.lock);
> > +
> > +               if (!ready)
> > +                       continue;
> > +
> > +               crtc->wm.active = crtc->wm.pending;
> > +               changed = true;
> > +       }
> > +
> > +       return changed;
> > +}
> > +
> >  static void ilk_program_watermarks(struct drm_device *dev)
> >  {
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -2810,6 +2869,87 @@ static void ilk_update_wm(struct drm_crtc *crtc)
> >         mutex_unlock(&dev_priv->wm.mutex);
> >  }
> >
> > +static void ilk_update_watermarks(struct drm_device *dev)
> 
> Now we have ilk_update_wm() and ilk_update_watermarks(). This is
> confusing, since one can't really tell the difference just by reading
> the name. Maybe we should rename one of them (unless a future patch
> kills one of them, which I didn't check yet).

Yeah the other one gets killed in one of the following patches.

> 
> 
> > +{
> > +       bool changed;
> > +
> > +       changed = ilk_refresh_pending_watermarks(dev);
> > +
> > +       if (changed)
> > +               ilk_program_watermarks(dev);
> 
> Also, don't we need to grab dev_priv->wm.mutex here? I'm asking since
> the other caller of ilk_program_watermarks() has the mutex locked. It
> should probably help if we had assert_mutex_is_locked() at some
> places. Or maybe the callers of ilk_program_watermarks() would need
> the lock.

Here the caller is responsible for the locking. I should sprinkle some
lockdep asserts around.

> 
> 
> > +}
> > +
> > +static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
> > +                                        const struct intel_pipe_wm *pipe_wm,
> > +                                        u32 vbl_count)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       enum pipe pipe = crtc->pipe;
> > +
> > +       WARN(!crtc->active, "pipe %c should be enabled\n",
> > +            pipe_name(pipe));
> > +
> > +       /* do the watermarks actually need changing? */
> > +       if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
> > +               return;
> > +
> > +       crtc->wm.pending = *pipe_wm;
> > +
> > +       spin_lock_irq(&crtc->wm.lock);
> > +       crtc->wm.pending_vbl_count = (vbl_count + 1) & dev->max_vblank_count;
> > +       crtc->wm.dirty = true;
> > +       spin_unlock_irq(&crtc->wm.lock);
> > +
> > +       /* try to update immediately */
> > +       ilk_update_watermarks(dev);
> 
> I'm failing to imagine a case where this would help. Can you please tell me?

In case the target vblank passed already. Though this is racy since we do
the check before drm_vblank_get() so we might still miss the interrupt
and then have to wait for the next one. I should reorder this a bit...

Although I now have a rather generic vblank notify mechanism cooking as
part of my fbc patches that doesn't suffer from this race, and my plan
is to use it also for watermarks. But back when I wrote the watermark
patches I didn't have the vblank notify thing coded up yet. Also I've
not yet tried to use it for watermarks, so it might require a bit of
further tuning before it can handle such things. This is just a FYI
really. I don't think we should stall the watermark patches behind
the vblank notify thing.

> 
> 
> > +
> > +       spin_lock_irq(&crtc->wm.lock);
> > +
> > +       /* did the immediate update succeed? */
> > +       if (!crtc->wm.dirty)
> > +               goto unlock;
> > +
> > +       /*
> > +        * We might already have a pending watermark update, in
> > +        * which case we shouldn't grab another vblank reference.
> > +        */
> > +       if (!crtc->wm.vblank && drm_vblank_get(dev, pipe) == 0)
> > +               crtc->wm.vblank = true;
> > +
> > +       WARN(!crtc->wm.vblank,
> > +            "unable to set up watermarks for pipe %c\n", pipe_name(pipe));
> > +
> > + unlock:
> > +       spin_unlock_irq(&crtc->wm.lock);
> > +}
> > +
> > +static void ilk_watermark_work(struct work_struct *work)
> > +{
> > +       struct drm_i915_private *dev_priv =
> > +               container_of(work, struct drm_i915_private, wm.work);
> > +
> > +       mutex_lock(&dev_priv->wm.mutex);
> > +
> > +       ilk_update_watermarks(dev_priv->dev);
> > +
> > +       mutex_unlock(&dev_priv->wm.mutex);
> > +}
> > +
> > +/* Called from vblank irq */
> > +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
> > +{
> > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > +       struct intel_crtc *crtc =
> > +               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> > +
> > +       spin_lock(&crtc->wm.lock);
> > +
> > +       if (ilk_pending_watermarks_ready(crtc))
> > +               schedule_work(&dev_priv->wm.work);
> > +
> > +       spin_unlock(&crtc->wm.lock);
> > +}
> > +
> >  static void ilk_update_sprite_wm(struct drm_plane *plane,
> >                                      struct drm_crtc *crtc,
> >                                      uint32_t sprite_width, int pixel_size,
> > @@ -2872,6 +3012,9 @@ static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
> >                 for (level = 0; level <= max_level; level++)
> >                         active->wm[level].enable = true;
> >         }
> > +
> > +       /* no update pending */
> > +       intel_crtc->wm.pending = intel_crtc->wm.active;
> 
> It feels a little weird that the function that gets the HW state will
> also cancel any scheduled watermark updates. Programmers from the
> future are really bad, they will probably not notice this and
> introduce bugs.

This function is only called at init/resume. It populates the software
state with something that matches the current hardware state. I guess
a comment explaning the purpose of the function is the best we can do
here, or do you have a better idea?

> 
> 
> >  }
> >
> >  void ilk_wm_get_hw_state(struct drm_device *dev)
> > @@ -6385,6 +6528,7 @@ void intel_init_pm(struct drm_device *dev)
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> >
> >         mutex_init(&dev_priv->wm.mutex);
> > +       INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);
> 
> Don't we also need to cancel the work in the places where we disable
> interrupts? Maybe it is possible to schedule a WM update, then disable
> everything and runtime suspend before the scheduled work happens... Or
> do something similar at S3 or driver unload.

The crtc disable will eventually wait for the wm update, although it
would seem to be a good idea to cancel the work in case it got
scheduled twice and the first run already managed to apply all the
pending watermarks.

And in fact maybe we don't want to wait for the pending watermark update
at crtc disable. Everything is going to get turned off anyway soon, so
letting it roll with the current watermarks till the end seems perfectly
acceptable, and it might shave off one vblank wait from the modeset.

Anyways I'll see about adding some explicit cancelling somewhere.

> 
> Since there's no caller for ilk_setup_pending_watermarks() I guess
> this patch will introduce a compiler warning here. I'm not sure what's
> our policy for that... I guess I'd vote to merge only when the next
> patches also have their RB tags.

Yeah there are a few patches here that don't make a whole lot of sense
on their own.

> 
> 
> >
> >         if (HAS_FBC(dev)) {
> >                 if (INTEL_INFO(dev)->gen >= 7) {
> > --
> > 1.8.5.5
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps
  2014-05-22 14:48 ` [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps ville.syrjala
@ 2014-06-03 20:51   ` Paulo Zanoni
  2014-06-04 16:22     ` Daniel Vetter
  0 siblings, 1 reply; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-03 20:51 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> We need to perform watermark programming before and after changing the
> plane configuration. Add two new vfuncs to do that. The pre phase is
> supposed to switch over to the intermediate watermarks which are
> computed so that they can deal with both the old and new plane
> configurations. The post phase will arm the vblank based update
> systems to switch over to the optimal target watermarks after the
> plane configuration has for sure changed.
>
> v2: Pass around intel_crtc and s/intel_crtc/crtc/
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h  |  5 +++
>  drivers/gpu/drm/i915/intel_drv.h | 11 +++++
>  drivers/gpu/drm/i915/intel_pm.c  | 88 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 104 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c90d5ac..d4f8ae8 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -407,6 +407,7 @@ struct intel_plane_config;
>  struct intel_crtc;
>  struct intel_limit;
>  struct dpll;
> +struct intel_crtc_wm_config;
>
>  struct drm_i915_display_funcs {
>         bool (*fbc_enabled)(struct drm_device *dev);
> @@ -437,6 +438,10 @@ struct drm_i915_display_funcs {
>                                  struct drm_crtc *crtc,
>                                  uint32_t sprite_width, int pixel_size,
>                                  bool enable, bool scaled);
> +       void (*program_wm_pre)(struct intel_crtc *crtc,
> +                              const struct intel_crtc_wm_config *config);
> +       void (*program_wm_post)(struct intel_crtc *crtc,
> +                               const struct intel_crtc_wm_config *config);
>         void (*modeset_global_resources)(struct drm_device *dev);
>         /* Returns the active state of the crtc, and if the crtc is active,
>          * fills out the pipe-config with the hw state. */
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 72f01b1..4b59be3 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -358,6 +358,13 @@ struct intel_pipe_wm {
>         bool sprites_scaled;
>  };
>
> +struct intel_crtc_wm_config {
> +       /* target watermarks for the pipe */
> +       struct intel_pipe_wm target;
> +       /* intermediate watermarks for pending/active->target transition */
> +       struct intel_pipe_wm intm;

It seems you always prefer shorter names such as "intm", and I usually
prefer the longer ones like "intermediate". Looks like this is a
common topic for my bikesheddings on your patches. When I read "intm"
my brain parses it as "Int M" and then aborts execution =P

With or without that changed: Reviewed-by: Paulo Zanoni
<paulo.r.zanoni@intel.com>

> +};
> +
>  struct intel_crtc {
>         struct drm_crtc base;
>         enum pipe pipe;
> @@ -1001,6 +1008,10 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
>  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
>  void ilk_wm_get_hw_state(struct drm_device *dev);
>  void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
> +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> +                                 const struct intel_crtc_wm_config *config);
> +void intel_program_watermarks_post(struct intel_crtc *crtc,
> +                                  const struct intel_crtc_wm_config *config);
>
>
>  /* intel_sdvo.c */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 6fc6416..ccf920a 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2950,6 +2950,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
>         spin_unlock(&crtc->wm.lock);
>  }
>
> +static void ilk_wm_cancel(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +
> +       assert_spin_locked(&crtc->wm.lock);
> +
> +       crtc->wm.dirty = false;
> +
> +       if (crtc->wm.vblank) {
> +               drm_vblank_put(dev, crtc->pipe);
> +               crtc->wm.vblank = false;
> +       }
> +}
> +
>  static void ilk_update_sprite_wm(struct drm_plane *plane,
>                                      struct drm_crtc *crtc,
>                                      uint32_t sprite_width, int pixel_size,
> @@ -3084,6 +3098,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
>                                                    pixel_size, enabled, scaled);
>  }
>
> +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> +                                 const struct intel_crtc_wm_config *config)
> +{
> +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> +
> +       if (dev_priv->display.program_wm_pre)
> +               dev_priv->display.program_wm_pre(crtc, config);
> +}
> +
> +void intel_program_watermarks_post(struct intel_crtc *crtc,
> +                                  const struct intel_crtc_wm_config *config)
> +{
> +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> +
> +       if (dev_priv->display.program_wm_post)
> +               dev_priv->display.program_wm_post(crtc, config);
> +}
> +
>  static struct drm_i915_gem_object *
>  intel_alloc_context_page(struct drm_device *dev)
>  {
> @@ -6522,6 +6554,60 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
>         pm_runtime_disable(device);
>  }
>
> +static void ilk_program_wm_pre(struct intel_crtc *crtc,
> +                              const struct intel_crtc_wm_config *config)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       spin_lock_irq(&crtc->wm.lock);
> +       ilk_wm_cancel(crtc);
> +       spin_unlock_irq(&crtc->wm.lock);
> +
> +       /* pending update (if any) got cancelled */
> +       crtc->wm.pending = crtc->wm.active;
> +
> +       if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
> +               goto unlock;
> +
> +       crtc->wm.active = config->intm;
> +
> +       /* use the most up to date watermarks for other pipes */
> +       ilk_refresh_pending_watermarks(dev);
> +
> +       /* switch over to the intermediate watermarks */
> +       ilk_program_watermarks(dev);
> +
> + unlock:
> +       mutex_unlock(&dev_priv->wm.mutex);
> +}
> +
> +static void ilk_program_wm_post(struct intel_crtc *crtc,
> +                               const struct intel_crtc_wm_config *config)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       u32 vbl_count;
> +
> +       /*
> +        * FIXME sample this inside the atomic section to avoid
> +        * needlessly long periods w/ sub-par watermarks
> +        */
> +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
> +
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       /*
> +        * We can switch over to the target
> +        * watermarks after the next vblank.
> +        */
> +       ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
> +
> +       mutex_unlock(&dev_priv->wm.mutex);
> +}
> +
>  /* Set up chip specific power management-related functions */
>  void intel_init_pm(struct drm_device *dev)
>  {
> @@ -6569,6 +6655,8 @@ void intel_init_pm(struct drm_device *dev)
>                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
>                         dev_priv->display.update_wm = ilk_update_wm;
>                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> +                       dev_priv->display.program_wm_pre = ilk_program_wm_pre;
> +                       dev_priv->display.program_wm_post = ilk_program_wm_post;
>                 } else {
>                         DRM_DEBUG_KMS("Failed to read display plane latency. "
>                                       "Disable CxSR\n");
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases
  2014-05-22 14:48 ` [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases ville.syrjala
@ 2014-06-03 22:47   ` Paulo Zanoni
  2014-06-09 18:28     ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-03 22:47 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Switch the code over to using the two phase watermark update. The steps
> generally follow this pattern:
>
> 1. Calculate new plane parameters for changed planes
> 2. Calculate new target and intermediate watermarks
> 3. Check that both the target and intermediate watermarks are valid
> 4. Program the hardware with the intermediate watermarks
> 5. Program the plane registers
> 6. Arm the vblank watermark update machinery for the next vblank
> 7. Program the hardware with the target watermarks (after vblank)
>
> v2: Rebased, pass intel_crtc around, s/intel_crtc/crtc/
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

This patch is huge. If we bisect any regression to it, we will be
completely lost and hopeless. Also, my tiny little brain doesn't have
enough power to do a proper review of this patch with so many changes
happening all at the same place. I tried, but I gave up in the middle.

Please try to convert this patch into many smaller patches. I don't
know if the following idea is actually possible, but it is what I
could extract from what I read of your patch:
- I'd start with the way you update watermarks parameters. Start by
patching ilk_compute_wm_parameters() and making it directly call your
new update_xxx_params() functions. You can even do separate patches
for _pri, _cur and _spr patches since it seems the _spr code is
different for most of your patch due to the old
intel_update_sprite_watermarks() function.
- Then you change the way you use to set your parameters (there's a
comment below mentioning the specific line which I'm talking about
here)
- Then you can patch intel_display.c so you will only update the WM
params when you actually change the HW (the _hw_plane and
update_cursor functions). Again, you can even split _pri, _cur and
_spr on separate patches.
- Then you can introduce the update_cursor_wm() and
update_primary_wm() functions, but still make them call the old-style
intel_update_watermarks() or something similar.
- You can also add the functions to deal with intermediate watermarks,
but without using them. Or you could, for example, make the
intermediate watermarks just be the same as the "old" ones, so the
only real update will be the final one (which, I believe, will mean
the code still behaves as it does today, no regressions).
- Then you can add the final piece of the code that uses all the new
infrastructure to actually generate and use the intermediate
watermarks. And this would be a much smaller patch.

There are still some comments below:

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |  14 ++-
>  drivers/gpu/drm/i915/intel_display.c |  58 ++++++++-
>  drivers/gpu/drm/i915/intel_drv.h     |  35 ++++--
>  drivers/gpu/drm/i915/intel_pm.c      | 229 +++++++++++++++++++++++++++--------
>  drivers/gpu/drm/i915/intel_sprite.c  | 119 ++++++++++++------
>  5 files changed, 347 insertions(+), 108 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index d4f8ae8..5b1404e 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -405,9 +405,12 @@ struct intel_connector;
>  struct intel_crtc_config;
>  struct intel_plane_config;
>  struct intel_crtc;
> +struct intel_plane;
>  struct intel_limit;
>  struct dpll;
>  struct intel_crtc_wm_config;
> +struct intel_plane_wm_parameters;
> +struct intel_crtc_wm_config;
>
>  struct drm_i915_display_funcs {
>         bool (*fbc_enabled)(struct drm_device *dev);
> @@ -434,10 +437,13 @@ struct drm_i915_display_funcs {
>                           struct dpll *match_clock,
>                           struct dpll *best_clock);
>         void (*update_wm)(struct drm_crtc *crtc);
> -       void (*update_sprite_wm)(struct drm_plane *plane,
> -                                struct drm_crtc *crtc,
> -                                uint32_t sprite_width, int pixel_size,
> -                                bool enable, bool scaled);
> +       int (*update_primary_wm)(struct intel_crtc *crtc,
> +                                struct intel_crtc_wm_config *config);
> +       int (*update_cursor_wm)(struct intel_crtc *crtc,
> +                               struct intel_crtc_wm_config *config);
> +       int (*update_sprite_wm)(struct intel_plane *plane,
> +                               struct intel_crtc *crtc,
> +                               struct intel_crtc_wm_config *config);
>         void (*program_wm_pre)(struct intel_crtc *crtc,
>                                const struct intel_crtc_wm_config *config);
>         void (*program_wm_post)(struct intel_crtc *crtc,
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 408b238..5bf1633 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2078,6 +2078,19 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
>         POSTING_READ(reg);
>  }
>
> +static void update_pri_params(struct intel_crtc *crtc,
> +                             struct intel_plane_wm_parameters *params,
> +                             bool primary_enabled)
> +{
> +       if (!crtc->active || !primary_enabled)
> +               return;
> +
> +       params->horiz_pixels = crtc->config.pipe_src_w;
> +       params->bytes_per_pixel =
> +               drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
> +       params->enabled = true;
> +}

You add two copies of this function, one here and one at the very end.

Also, the params->bytes_per_pixel used here is different from the one
originally used at ilk_compute_wm_parameters(). This should be on a
separate patch with a nice explanation of the differences between
both.

> +
>  /**
>   * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
>   * @dev_priv: i915 private structure
> @@ -2091,6 +2104,8 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
>  {
>         struct intel_crtc *intel_crtc =
>                 to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +       struct intel_crtc_wm_config config = {};

These temporary structs that get created an assigned really bother me,
especially in these cases where we are just interested in a sub-field
of the struct. This probably suggests there is something wrong with
our abstractions. After all this work is merged, we should probably
try to get rid of these things.


> +       int ret;
>         int reg;
>         u32 val;
>
> @@ -2100,14 +2115,24 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
>         if (intel_crtc->primary_enabled)
>                 return;
>
> +       update_pri_params(intel_crtc, &config.pri, true);
> +
> +       ret = intel_update_primary_watermarks(intel_crtc, &config);
> +       WARN(ret, "primary watermarks invalid\n");
> +
>         intel_crtc->primary_enabled = true;
>
>         reg = DSPCNTR(plane);
>         val = I915_READ(reg);
>         WARN_ON(val & DISPLAY_PLANE_ENABLE);
>
> +       intel_crtc->pri_wm = config.pri;
> +       intel_program_watermarks_pre(intel_crtc, &config);
> +
>         I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
>         intel_flush_primary_plane(dev_priv, plane);
> +
> +       intel_program_watermarks_post(intel_crtc, &config);
>  }
>
>  /**
> @@ -2123,20 +2148,32 @@ static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
>  {
>         struct intel_crtc *intel_crtc =
>                 to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +       struct intel_crtc_wm_config config = {};
> +       int ret;
>         int reg;
>         u32 val;
>
>         if (!intel_crtc->primary_enabled)
>                 return;
>
> +       update_pri_params(intel_crtc, &config.pri, false);
> +
> +       ret = intel_update_primary_watermarks(intel_crtc, &config);
> +       WARN(ret, "primary watermarks invalid\n");
> +
>         intel_crtc->primary_enabled = false;
>
>         reg = DSPCNTR(plane);
>         val = I915_READ(reg);
>         WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0);
>
> +       intel_crtc->pri_wm = config.pri;
> +       intel_program_watermarks_pre(intel_crtc, &config);
> +
>         I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
>         intel_flush_primary_plane(dev_priv, plane);
> +
> +       intel_program_watermarks_post(intel_crtc, &config);
>  }
>
>  static bool need_vtd_wa(struct drm_device *dev)
> @@ -3989,7 +4026,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>          */
>         intel_crtc_load_lut(crtc);
>
> -       intel_update_watermarks(crtc);
>         intel_enable_pipe(intel_crtc);
>
>         if (intel_crtc->config.has_pch_encoder)
> @@ -4100,7 +4136,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>         intel_ddi_set_pipe_settings(crtc);
>         intel_ddi_enable_transcoder_func(crtc);
>
> -       intel_update_watermarks(crtc);
>         intel_enable_pipe(intel_crtc);
>
>         if (intel_crtc->config.has_pch_encoder)
> @@ -4188,7 +4223,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>         }
>
>         intel_crtc->active = false;
> -       intel_update_watermarks(crtc);
>
>         mutex_lock(&dev->struct_mutex);
>         intel_update_fbc(dev);
> @@ -4236,7 +4270,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>         }
>
>         intel_crtc->active = false;
> -       intel_update_watermarks(crtc);
>
>         mutex_lock(&dev->struct_mutex);
>         intel_update_fbc(dev);
> @@ -7985,11 +8018,13 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>         struct drm_device *dev = crtc->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +       struct intel_crtc_wm_config config = {};
>         int pipe = intel_crtc->pipe;
>         int x = intel_crtc->cursor_x;
>         int y = intel_crtc->cursor_y;
>         u32 base = 0, pos = 0;
>         bool visible;
> +       int ret;
>
>         if (on)
>                 base = intel_crtc->cursor_addr;
> @@ -8022,6 +8057,19 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>         if (!visible && !intel_crtc->cursor_visible)
>                 return;
>
> +       if (visible) {
> +               /* FIXME should we use the clipped width? */
> +               config.cur.horiz_pixels = intel_crtc->cursor_width;
> +               config.cur.bytes_per_pixel = 4;
> +               config.cur.enabled = true;
> +       }
> +
> +       ret = intel_update_cursor_watermarks(intel_crtc, &config);
> +       WARN(ret, "cursor watermarks invalid\n");
> +
> +       intel_crtc->cur_wm = config.cur;
> +       intel_program_watermarks_pre(intel_crtc, &config);
> +
>         I915_WRITE(CURPOS(pipe), pos);
>
>         if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
> @@ -8030,6 +8078,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>                 i845_update_cursor(crtc, base);
>         else
>                 i9xx_update_cursor(crtc, base);
> +
> +       intel_program_watermarks_post(intel_crtc, &config);
>  }
>
>  static int intel_crtc_cursor_set(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 4b59be3..1ec4379 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -358,7 +358,15 @@ struct intel_pipe_wm {
>         bool sprites_scaled;
>  };
>
> +struct intel_plane_wm_parameters {
> +       uint32_t horiz_pixels;
> +       uint8_t bytes_per_pixel;
> +       bool enabled;
> +       bool scaled;
> +};
> +
>  struct intel_crtc_wm_config {
> +       struct intel_plane_wm_parameters pri, spr, cur;
>         /* target watermarks for the pipe */
>         struct intel_pipe_wm target;
>         /* intermediate watermarks for pending/active->target transition */
> @@ -444,18 +452,14 @@ struct intel_crtc {
>                 spinlock_t lock;
>         } wm;
>
> +       struct intel_plane_wm_parameters pri_wm;
> +       struct intel_plane_wm_parameters cur_wm;

Why isn't this inside "struct wm"?

Also please add _params to the name. Every new patch adds a different
WM struct with a similar name, I am confused.

> +
>         wait_queue_head_t vbl_wait;
>
>         int scanline_offset;
>  };
>
> -struct intel_plane_wm_parameters {
> -       uint32_t horiz_pixels;
> -       uint8_t bytes_per_pixel;
> -       bool enabled;
> -       bool scaled;
> -};
> -
>  struct intel_plane {
>         struct drm_plane base;
>         int plane;
> @@ -483,9 +487,11 @@ struct intel_plane {
>                              int crtc_x, int crtc_y,
>                              unsigned int crtc_w, unsigned int crtc_h,
>                              uint32_t x, uint32_t y,
> -                            uint32_t src_w, uint32_t src_h);
> +                            uint32_t src_w, uint32_t src_h,
> +                            const struct intel_crtc_wm_config *config);
>         void (*disable_plane)(struct drm_plane *plane,
> -                             struct drm_crtc *crtc);
> +                             struct drm_crtc *crtc,
> +                             const struct intel_crtc_wm_config *config);
>         int (*update_colorkey)(struct drm_plane *plane,
>                                struct drm_intel_sprite_colorkey *key);
>         void (*get_colorkey)(struct drm_plane *plane,
> @@ -969,10 +975,13 @@ void intel_init_clock_gating(struct drm_device *dev);
>  void intel_suspend_hw(struct drm_device *dev);
>  int ilk_wm_max_level(const struct drm_device *dev);
>  void intel_update_watermarks(struct drm_crtc *crtc);
> -void intel_update_sprite_watermarks(struct drm_plane *plane,
> -                                   struct drm_crtc *crtc,
> -                                   uint32_t sprite_width, int pixel_size,
> -                                   bool enabled, bool scaled);
> +int intel_update_cursor_watermarks(struct intel_crtc *crtc,
> +                                  struct intel_crtc_wm_config *config);
> +int intel_update_primary_watermarks(struct intel_crtc *crtc,
> +                                  struct intel_crtc_wm_config *config);
> +int intel_update_sprite_watermarks(struct intel_plane *plane,
> +                                  struct intel_crtc *crtc,
> +                                  struct intel_crtc_wm_config *config);
>  void intel_init_pm(struct drm_device *dev);
>  void intel_pm_setup(struct drm_device *dev);
>  bool intel_fbc_enabled(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index ccf920a..13366b7 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2186,13 +2186,9 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
>         p->active = true;
>         p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
>         p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> -       p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
> -       p->cur.bytes_per_pixel = 4;
> -       p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
> -       p->cur.horiz_pixels = intel_crtc->cursor_width;
> -       /* TODO: for now, assume primary and cursor planes are always enabled. */
> -       p->pri.enabled = true;
> -       p->cur.enabled = true;
> +
> +       p->pri = intel_crtc->pri_wm;
> +       p->cur = intel_crtc->cur_wm;
>
>         drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
>                 struct intel_plane *intel_plane = to_intel_plane(plane);
> @@ -2292,6 +2288,35 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
>  }
>
>  /*
> + * Merge two pipe watermark sets.
> + * Used for computing intermediate watermark levels
> + * for transitioning between two different configurations.
> + */
> +static void ilk_wm_merge_intermediate(struct drm_device *dev,
> +                                     struct intel_pipe_wm *a,
> +                                     const struct intel_pipe_wm *b)
> +{
> +       int level, max_level = ilk_wm_max_level(dev);
> +
> +       a->pipe_enabled |= b->pipe_enabled;
> +       a->sprites_enabled |= b->sprites_enabled;
> +       a->sprites_scaled |= b->sprites_scaled;
> +
> +       /* Merge _all_ levels including 0 */
> +       for (level = 0; level <= max_level; level++) {
> +               struct intel_wm_level *a_wm = &a->wm[level];
> +               const struct intel_wm_level *b_wm = &b->wm[level];
> +
> +               a_wm->enable &= b_wm->enable;
> +
> +               a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
> +               a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
> +               a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
> +               a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
> +       }
> +}

Maybe this question don't make much sense, but:
- What if A was WM calculated with one type of paritioning and/or FBC
enabled, while B was calculated with the other partitioning and/or FBC
disabled? Can't we reach a case where the watermarks generated by this
function are insufficient (due to fbc/partitioning/etc) or don't even
make sense (values we would never generate with the current BSpec
algorithms)?


> +
> +/*
>   * Merge the watermarks from all active pipes for a specific level.
>   */
>  static void ilk_merge_wm_level(struct drm_device *dev,
> @@ -2844,31 +2869,6 @@ static void ilk_program_watermarks(struct drm_device *dev)
>         ilk_write_wm_values(dev_priv, &results);
>  }
>
> -static void ilk_update_wm(struct drm_crtc *crtc)
> -{
> -       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -       struct drm_device *dev = crtc->dev;
> -       struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct ilk_pipe_wm_parameters params = {};
> -       struct intel_pipe_wm pipe_wm = {};
> -
> -       ilk_compute_wm_parameters(crtc, &params);
> -
> -       intel_compute_pipe_wm(crtc, &params, &pipe_wm);
> -
> -       mutex_lock(&dev_priv->wm.mutex);
> -
> -       if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
> -               goto unlock;
> -
> -       intel_crtc->wm.active = pipe_wm;
> -
> -       ilk_program_watermarks(dev);
> -
> - unlock:
> -       mutex_unlock(&dev_priv->wm.mutex);
> -}
> -
>  static void ilk_update_watermarks(struct drm_device *dev)
>  {
>         bool changed;
> @@ -2923,6 +2923,71 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
>         spin_unlock_irq(&crtc->wm.lock);
>  }
>
> +static int ilk_pipe_compute_watermarks(struct intel_crtc *crtc,
> +                                      struct intel_pipe_wm *target,
> +                                      struct intel_pipe_wm *intm)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct intel_pipe_wm intm_pending;
> +       bool dirty;
> +
> +       /* are the target watermarks valid at all? */
> +       if (!ilk_validate_pipe_wm(dev, target))
> +               return -EINVAL;
> +
> +       /*
> +        * We need to come up with intermediate watermark levels
> +        * that will support both the old and new plane configuration
> +        * since we can't flip over to the final watermarks until
> +        * the plane configuration has been latched at some future vblank.
> +        *
> +        * Additionally if there's already an update pending, we can't
> +        * yet be sure which plane configuration will be active at the
> +        * time we apply the intermediate watermarks, so we must account
> +        * for both possibilities.
> +        */
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       intm_pending = crtc->wm.pending;
> +       *intm = crtc->wm.active;
> +
> +       spin_lock_irq(&crtc->wm.lock);
> +       dirty = crtc->wm.dirty;
> +       spin_unlock_irq(&crtc->wm.lock);
> +
> +       mutex_unlock(&dev_priv->wm.mutex);
> +
> +       /*
> +        * If the intermediate watermarks aren't valid, we must tell the user to
> +        * try something a bit different. There are two cases to be considered.
> +        * 1) there is no pending update:
> +        *    If the intermediate watermarks for transitioning from the currently
> +        *    active configuration to the new configuration aren't valid, the
> +        *    user must choose another configuration as there is no safe way to
> +        *    transition from the currently active config to the new config.

Why/how would this happen?

In the worst case, the intermediate watermarks would just disable all
the LP WMs, go back to 1/2 partitioning, disable FBC, and use the
maximum register values for level 0. Anything that needs more than
that is an unsupported mode. By the way, we could get completely rid
of these intermediate WM calculations if we just used these maximum
values as the intermediate ones: of course, they would be less
power-efficient than your current code, but maybe the difference
wouldn't be noticeable.

Thanks,
Paulo

> +        * 2) there is a pending update:
> +        *    If the intermediate watermarks for transitioning from the ccurrently
> +        *    pending configuration to the new configuration are valid, we can
> +        *    simply tell the user to try again after a while.
> +        */
> +       if (dirty) {
> +               ilk_wm_merge_intermediate(dev, &intm_pending, target);
> +               if (!ilk_validate_pipe_wm(dev, &intm_pending))
> +                       return -EINVAL;
> +
> +               ilk_wm_merge_intermediate(dev, intm, &intm_pending);
> +               if (!ilk_validate_pipe_wm(dev, intm))
> +                       return -EAGAIN;
> +       } else {
> +               ilk_wm_merge_intermediate(dev, intm, target);
> +               if (!ilk_validate_pipe_wm(dev, intm))
> +                       return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
>  static void ilk_watermark_work(struct work_struct *work)
>  {
>         struct drm_i915_private *dev_priv =
> @@ -2964,18 +3029,46 @@ static void ilk_wm_cancel(struct intel_crtc *crtc)
>         }
>  }
>
> -static void ilk_update_sprite_wm(struct drm_plane *plane,
> -                                    struct drm_crtc *crtc,
> -                                    uint32_t sprite_width, int pixel_size,
> -                                    bool enabled, bool scaled)
> +static int ilk_update_primary_wm(struct intel_crtc *crtc,
> +                                struct intel_crtc_wm_config *config)
> +{
> +       struct ilk_pipe_wm_parameters params = {};
> +
> +       ilk_compute_wm_parameters(&crtc->base, &params);
> +
> +       params.pri = config->pri;
> +
> +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
> +
> +       return ilk_pipe_compute_watermarks(crtc,
> +                                          &config->target,
> +                                          &config->intm);
> +}
> +
> +static int ilk_update_cursor_wm(struct intel_crtc *crtc,
> +                               struct intel_crtc_wm_config *config)
> +{
> +       struct ilk_pipe_wm_parameters params = {};
> +
> +       ilk_compute_wm_parameters(&crtc->base, &params);
> +
> +       params.cur = config->cur;
> +
> +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
> +
> +       return ilk_pipe_compute_watermarks(crtc,
> +                                          &config->target,
> +                                          &config->intm);
> +}
> +
> +static int ilk_update_sprite_wm(struct intel_plane *plane,
> +                               struct intel_crtc *crtc,
> +                               struct intel_crtc_wm_config *config)
>  {
> -       struct drm_device *dev = plane->dev;
> -       struct intel_plane *intel_plane = to_intel_plane(plane);
> +       struct drm_device *dev = crtc->base.dev;
> +       struct ilk_pipe_wm_parameters params = {};
>
> -       intel_plane->wm.enabled = enabled;
> -       intel_plane->wm.scaled = scaled;
> -       intel_plane->wm.horiz_pixels = sprite_width;
> -       intel_plane->wm.bytes_per_pixel = pixel_size;
> +       ilk_compute_wm_parameters(&crtc->base, &params);
>
>         /*
>          * IVB workaround: must disable low power watermarks for at least
> @@ -2984,10 +3077,17 @@ static void ilk_update_sprite_wm(struct drm_plane *plane,
>          *
>          * WaCxSRDisabledForSpriteScaling:ivb
>          */
> -       if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
> -               intel_wait_for_vblank(dev, intel_plane->pipe);
> +       if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
> +               intel_wait_for_vblank(dev, plane->pipe);
> +
> +       params.pri = config->pri;
> +       params.spr = config->spr;
> +
> +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
>
> -       ilk_update_wm(crtc);
> +       return ilk_pipe_compute_watermarks(crtc,
> +                                          &config->target,
> +                                          &config->intm);
>  }
>
>  static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
> @@ -3086,16 +3186,38 @@ void intel_update_watermarks(struct drm_crtc *crtc)
>                 dev_priv->display.update_wm(crtc);
>  }
>
> -void intel_update_sprite_watermarks(struct drm_plane *plane,
> -                                   struct drm_crtc *crtc,
> -                                   uint32_t sprite_width, int pixel_size,
> -                                   bool enabled, bool scaled)
> +int intel_update_primary_watermarks(struct intel_crtc *crtc,
> +                                   struct intel_crtc_wm_config *config)
>  {
> -       struct drm_i915_private *dev_priv = plane->dev->dev_private;
> +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> +
> +       if (dev_priv->display.update_primary_wm)
> +               return dev_priv->display.update_primary_wm(crtc, config);
> +
> +       return 0;
> +}
> +
> +int intel_update_cursor_watermarks(struct intel_crtc *crtc,
> +                                  struct intel_crtc_wm_config *config)
> +{
> +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> +
> +       if (dev_priv->display.update_cursor_wm)
> +               return dev_priv->display.update_cursor_wm(crtc, config);
> +
> +       return 0;
> +}
> +
> +int intel_update_sprite_watermarks(struct intel_plane *plane,
> +                                  struct intel_crtc *crtc,
> +                                  struct intel_crtc_wm_config *config)
> +{
> +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>
>         if (dev_priv->display.update_sprite_wm)
> -               dev_priv->display.update_sprite_wm(plane, crtc, sprite_width,
> -                                                  pixel_size, enabled, scaled);
> +               return dev_priv->display.update_sprite_wm(plane, crtc, config);
> +
> +       return 0;
>  }
>
>  void intel_program_watermarks_pre(struct intel_crtc *crtc,
> @@ -6653,7 +6775,8 @@ void intel_init_pm(struct drm_device *dev)
>                      dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
>                     (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
>                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
> -                       dev_priv->display.update_wm = ilk_update_wm;
> +                       dev_priv->display.update_primary_wm = ilk_update_primary_wm;
> +                       dev_priv->display.update_cursor_wm = ilk_update_cursor_wm;
>                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
>                         dev_priv->display.program_wm_pre = ilk_program_wm_pre;
>                         dev_priv->display.program_wm_post = ilk_program_wm_post;
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index d6acd6b..c9b1750 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -131,7 +131,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
>         struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>         int reg = DSPCNTR(crtc->plane);
>
> -       if (crtc->primary_enabled)
> +       if (crtc->pri_wm.enabled)
>                 I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
>         else
>                 I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
> @@ -143,7 +143,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
>                  unsigned int crtc_w, unsigned int crtc_h,
>                  uint32_t x, uint32_t y,
> -                uint32_t src_w, uint32_t src_h)
> +                uint32_t src_w, uint32_t src_h,
> +                const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = dplane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -218,9 +219,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>
>         sprctl |= SP_ENABLE;
>
> -       intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
> -                                      src_w != crtc_w || src_h != crtc_h);
> -
>         /* Sizes are 0 based */
>         src_w--;
>         src_h--;
> @@ -234,6 +232,10 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>                                                         fb->pitches[0]);
>         linear_offset -= sprsurf_offset;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -255,10 +257,13 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> +
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static void
> -vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
> +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> +                 const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = dplane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -269,6 +274,10 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
>         u32 start_vbl_count;
>         bool atomic_update;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -283,7 +292,7 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
>
> -       intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static int
> @@ -343,7 +352,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
>                  unsigned int crtc_w, unsigned int crtc_h,
>                  uint32_t x, uint32_t y,
> -                uint32_t src_w, uint32_t src_h)
> +                uint32_t src_w, uint32_t src_h,
> +                const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = plane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -406,9 +416,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>         if (IS_HASWELL(dev) || IS_BROADWELL(dev))
>                 sprctl |= SPRITE_PIPE_CSC_ENABLE;
>
> -       intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
> -                                      src_w != crtc_w || src_h != crtc_h);
> -
>         /* Sizes are 0 based */
>         src_w--;
>         src_h--;
> @@ -424,6 +431,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                                                pixel_size, fb->pitches[0]);
>         linear_offset -= sprsurf_offset;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -451,10 +462,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> +
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static void
> -ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> +                 const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = plane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -464,6 +478,10 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
>         u32 start_vbl_count;
>         bool atomic_update;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -480,13 +498,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
>
> -       /*
> -        * Avoid underruns when disabling the sprite.
> -        * FIXME remove once watermark updates are done properly.
> -        */
> -       intel_wait_for_vblank(dev, pipe);
> -
> -       intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static int
> @@ -549,7 +561,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
>                  unsigned int crtc_w, unsigned int crtc_h,
>                  uint32_t x, uint32_t y,
> -                uint32_t src_w, uint32_t src_h)
> +                uint32_t src_w, uint32_t src_h,
> +                const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = plane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -606,9 +619,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                 dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
>         dvscntr |= DVS_ENABLE;
>
> -       intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
> -                                      src_w != crtc_w || src_h != crtc_h);
> -
>         /* Sizes are 0 based */
>         src_w--;
>         src_h--;
> @@ -625,6 +635,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                                                pixel_size, fb->pitches[0]);
>         linear_offset -= dvssurf_offset;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -647,10 +661,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> +
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static void
> -ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> +                 const struct intel_crtc_wm_config *config)
>  {
>         struct drm_device *dev = plane->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -660,6 +677,10 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
>         u32 start_vbl_count;
>         bool atomic_update;
>
> +       intel_crtc->pri_wm = config->pri;
> +       intel_plane->wm = config->spr;
> +       intel_program_watermarks_pre(intel_crtc, config);
> +
>         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
>
>         intel_update_primary_plane(intel_crtc);
> @@ -675,13 +696,7 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
>         if (atomic_update)
>                 intel_pipe_update_end(intel_crtc, start_vbl_count);
>
> -       /*
> -        * Avoid underruns when disabling the sprite.
> -        * FIXME remove once watermark updates are done properly.
> -        */
> -       intel_wait_for_vblank(dev, pipe);
> -
> -       intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
> +       intel_program_watermarks_post(intel_crtc, config);
>  }
>
>  static void
> @@ -801,6 +816,19 @@ static bool colorkey_enabled(struct intel_plane *intel_plane)
>         return key.flags != I915_SET_COLORKEY_NONE;
>  }
>
> +static void update_pri_params(struct intel_crtc *crtc,
> +                             struct intel_plane_wm_parameters *params,
> +                             bool primary_enabled)
> +{
> +       if (!crtc->active || !primary_enabled)
> +               return;
> +
> +       params->horiz_pixels = crtc->config.pipe_src_w;
> +       params->bytes_per_pixel =
> +               drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
> +       params->enabled = true;
> +}
> +
>  static int
>  intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                    struct drm_framebuffer *fb, int crtc_x, int crtc_y,
> @@ -852,6 +880,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                 .src_w = src_w,
>                 .src_h = src_h,
>         };
> +       struct intel_crtc_wm_config config = {};
>
>         /* Don't modify another pipe's plane */
>         if (intel_plane->pipe != intel_crtc->pipe) {
> @@ -989,6 +1018,19 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>         primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane);
>         WARN_ON(!primary_enabled && !visible && intel_crtc->active);
>
> +       if (visible) {
> +               config.spr.horiz_pixels = src_w;
> +               config.spr.bytes_per_pixel = pixel_size;
> +               config.spr.enabled = true;
> +               config.spr.scaled = src_w != crtc_w || src_h != crtc_h;
> +       }
> +
> +       update_pri_params(intel_crtc, &config.pri, primary_enabled);
> +
> +       ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
> +       if (ret)
> +               return ret;
> +
>         mutex_lock(&dev->struct_mutex);
>
>         /* Note that this will apply the VT-d workaround for scanouts,
> @@ -1027,9 +1069,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
>                 if (visible)
>                         intel_plane->update_plane(plane, crtc, fb, obj,
>                                                   crtc_x, crtc_y, crtc_w, crtc_h,
> -                                                 src_x, src_y, src_w, src_h);
> +                                                 src_x, src_y, src_w, src_h,
> +                                                 &config);
>                 else
> -                       intel_plane->disable_plane(plane, crtc);
> +                       intel_plane->disable_plane(plane, crtc, &config);
>
>                 if (!primary_was_enabled && primary_enabled)
>                         intel_post_enable_primary(crtc);
> @@ -1060,6 +1103,8 @@ intel_disable_plane(struct drm_plane *plane)
>         struct drm_device *dev = plane->dev;
>         struct intel_plane *intel_plane = to_intel_plane(plane);
>         struct intel_crtc *intel_crtc;
> +       struct intel_crtc_wm_config config = {};
> +       int ret;
>
>         if (!plane->fb)
>                 return 0;
> @@ -1069,12 +1114,18 @@ intel_disable_plane(struct drm_plane *plane)
>
>         intel_crtc = to_intel_crtc(plane->crtc);
>
> +       update_pri_params(intel_crtc, &config.pri, true);
> +
> +       ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
> +       if (ret)
> +               return ret;
> +
>         if (intel_crtc->active) {
>                 bool primary_was_enabled = intel_crtc->primary_enabled;
>
>                 intel_crtc->primary_enabled = true;
>
> -               intel_plane->disable_plane(plane, plane->crtc);
> +               intel_plane->disable_plane(plane, plane->crtc, &config);
>
>                 if (!primary_was_enabled && intel_crtc->primary_enabled)
>                         intel_post_enable_primary(plane->crtc);
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes
  2014-05-26 13:56   ` Daniel Vetter
@ 2014-06-04  6:00     ` Arun Murthy
  2014-06-10 16:22       ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Arun Murthy @ 2014-06-04  6:00 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Mon, May 26, 2014 at 7:26 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Thu, May 22, 2014 at 05:48:06PM +0300, ville.syrjala@linux.intel.com wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> Because of the upcoming vblank interrupt driven watermark update
>> mechanism we will have use for vblank interrupts during plane
>> enabling/disabling. So don't call drm_vblank_off() until planes
>> are off, and call drm_vblank_on() just before we start to enable
>> the planes.

Since watermark and display control registers are double buffered
both of them get updated on next blank and hence in sync.
Can you let me know the need for vblank driven watermark updates?

Thanks and Regards,
Arun R Murthy
-------------------
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe
  2014-05-22 14:48 ` [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe ville.syrjala
@ 2014-06-04 13:54   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 13:54 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> After we've disabled the planes, it seems like a good idea wait for
> the vblank driven watermark updates to finish before we turn off the
> vblank interrupts and eventually the entire pipe.

Can you please elaborate more on why it is a "good idea"? Is is a real
requirement? A bugfix? What happens if we don't do this?
The answer should be on the commit message.

The only potential problem I could find is that we'll wake up the
waitqueue after ilk_refresh_pending_watermarks() but still before
ilk_program_watermarks(). This doesn't seem to be a problem with the
current code, but is the kid of thing that could lead to future bugs
due to the constant code rewrite/refactor we do. Maybe a comment on
top of the ilk_wm_synchronize() definition - explaining that the
function may return while the register values are still not
"synchronized" - would help a little bit. Or maybe we could just call
wake_up_all() after the registers are written.

With at least the commit message amended: Reviewed-by: Paulo Zanoni
<paulo.r.zanoni@intel.com>

>
> v2: Rebase and s/intel_crtc/crtc/
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |  1 +
>  drivers/gpu/drm/i915/intel_display.c |  2 ++
>  drivers/gpu/drm/i915/intel_drv.h     |  1 +
>  drivers/gpu/drm/i915/intel_pm.c      | 32 ++++++++++++++++++++++++++++++++
>  4 files changed, 36 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 5b1404e..1fe0cac 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1554,6 +1554,7 @@ struct drm_i915_private {
>                 struct mutex mutex;
>
>                 struct work_struct work;
> +               wait_queue_head_t wait;
>         } wm;
>
>         struct i915_runtime_pm pm;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 5bf1633..ca362db 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3960,6 +3960,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
>         intel_disable_planes(crtc);
>         intel_disable_primary_hw_plane(dev_priv, plane, pipe);
>
> +       ilk_wm_synchronize(intel_crtc);
> +
>         drm_vblank_off(dev, pipe);
>  }
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 1ec4379..5ad7ad5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1021,6 +1021,7 @@ void intel_program_watermarks_pre(struct intel_crtc *crtc,
>                                   const struct intel_crtc_wm_config *config);
>  void intel_program_watermarks_post(struct intel_crtc *crtc,
>                                    const struct intel_crtc_wm_config *config);
> +void ilk_wm_synchronize(struct intel_crtc *crtc);
>
>
>  /* intel_sdvo.c */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 13366b7..1c072cd 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2812,6 +2812,7 @@ static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
>
>  static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
>  {
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         struct intel_crtc *crtc;
>         bool changed = false;
>
> @@ -2833,6 +2834,9 @@ static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
>                 changed = true;
>         }
>
> +       if (changed)
> +               wake_up_all(&dev_priv->wm.wait);
> +
>         return changed;
>  }
>
> @@ -3029,6 +3033,33 @@ static void ilk_wm_cancel(struct intel_crtc *crtc)
>         }
>  }
>
> +void ilk_wm_synchronize(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum pipe pipe = crtc->pipe;
> +       unsigned long timeout = msecs_to_jiffies(100);
> +
> +       wait_event_timeout(dev_priv->wm.wait, !crtc->wm.dirty, timeout);
> +
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       spin_lock_irq(&crtc->wm.lock);
> +
> +       WARN(crtc->wm.dirty, "pipe %c watermark updates failed to complete\n",
> +            pipe_name(pipe));
> +
> +       /* clean up if something is left behind */
> +       ilk_wm_cancel(crtc);
> +
> +       spin_unlock_irq(&crtc->wm.lock);
> +
> +       /* pending update (if any) got cancelled */
> +       crtc->wm.pending = crtc->wm.active;
> +
> +       mutex_unlock(&dev_priv->wm.mutex);
> +}
> +
>  static int ilk_update_primary_wm(struct intel_crtc *crtc,
>                                  struct intel_crtc_wm_config *config)
>  {
> @@ -6736,6 +6767,7 @@ void intel_init_pm(struct drm_device *dev)
>         struct drm_i915_private *dev_priv = dev->dev_private;
>
>         mutex_init(&dev_priv->wm.mutex);
> +       init_waitqueue_head(&dev_priv->wm.wait);
>         INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);
>
>         if (HAS_FBC(dev)) {
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-06-03 19:32     ` Ville Syrjälä
@ 2014-06-04 14:01       ` Paulo Zanoni
  2014-06-04 16:10         ` Daniel Vetter
  0 siblings, 1 reply; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 14:01 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-06-03 16:32 GMT-03:00 Ville Syrjälä <ville.syrjala@linux.intel.com>:
> On Tue, Jun 03, 2014 at 03:50:12PM -0300, Paulo Zanoni wrote:
>> 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
>> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >
>> > Add a mechanism by which you can queue up watermark update to happen
>> > after the vblank counter has reached a certain value. The vblank
>> > interrupt handler will schedule a work which will do the actual
>> > watermark programming in process context.
>> >
>> > v2: Rebase and s/intel_crtc/crtc/
>> >
>> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> > ---
>> >  drivers/gpu/drm/i915/i915_drv.h      |   2 +
>> >  drivers/gpu/drm/i915/i915_irq.c      |  12 ++-
>> >  drivers/gpu/drm/i915/intel_display.c |   1 +
>> >  drivers/gpu/drm/i915/intel_drv.h     |  27 +++++++
>> >  drivers/gpu/drm/i915/intel_pm.c      | 144 +++++++++++++++++++++++++++++++++++
>> >  5 files changed, 183 insertions(+), 3 deletions(-)
>> >
>> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> > index a2302a7..c90d5ac 100644
>> > --- a/drivers/gpu/drm/i915/i915_drv.h
>> > +++ b/drivers/gpu/drm/i915/i915_drv.h
>> > @@ -1541,6 +1541,8 @@ struct drm_i915_private {
>> >                  * state as well as the actual hardware registers
>> >                  */
>> >                 struct mutex mutex;
>> > +
>> > +               struct work_struct work;
>> >         } wm;
>> >
>> >         struct i915_runtime_pm pm;
>> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>> > index 304f86a..c680020 100644
>> > --- a/drivers/gpu/drm/i915/i915_irq.c
>> > +++ b/drivers/gpu/drm/i915/i915_irq.c
>> > @@ -2067,8 +2067,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
>> >                 DRM_ERROR("Poison interrupt\n");
>> >
>> >         for_each_pipe(pipe) {
>> > -               if (de_iir & DE_PIPE_VBLANK(pipe))
>> > +               if (de_iir & DE_PIPE_VBLANK(pipe)) {
>> >                         intel_pipe_handle_vblank(dev, pipe);
>> > +                       ilk_update_pipe_wm(dev, pipe);
>> > +               }
>> >
>> >                 if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
>> >                         if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
>> > @@ -2117,8 +2119,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
>> >                 intel_opregion_asle_intr(dev);
>> >
>> >         for_each_pipe(pipe) {
>> > -               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
>> > +               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) {
>> >                         intel_pipe_handle_vblank(dev, pipe);
>> > +                       ilk_update_pipe_wm(dev, pipe);
>> > +               }
>> >
>> >                 /* plane/pipes map 1:1 on ilk+ */
>> >                 if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
>> > @@ -2260,8 +2264,10 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
>> >                         continue;
>> >
>> >                 pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
>> > -               if (pipe_iir & GEN8_PIPE_VBLANK)
>> > +               if (pipe_iir & GEN8_PIPE_VBLANK) {
>> >                         intel_pipe_handle_vblank(dev, pipe);
>> > +                       ilk_update_pipe_wm(dev, pipe);
>> > +               }
>> >
>> >                 if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
>> >                         intel_prepare_page_flip(dev, pipe);
>> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> > index a11bd78..408b238 100644
>> > --- a/drivers/gpu/drm/i915/intel_display.c
>> > +++ b/drivers/gpu/drm/i915/intel_display.c
>> > @@ -10961,6 +10961,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>> >                 intel_crtc->plane = !pipe;
>> >         }
>> >
>> > +       spin_lock_init(&intel_crtc->wm.lock);
>> >         init_waitqueue_head(&intel_crtc->vbl_wait);
>> >
>> >         BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
>> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> > index d75cc2b..72f01b1 100644
>> > --- a/drivers/gpu/drm/i915/intel_drv.h
>> > +++ b/drivers/gpu/drm/i915/intel_drv.h
>> > @@ -409,6 +409,32 @@ struct intel_crtc {
>> >                  * protected by dev_priv->wm.mutex
>> >                  */
>> >                 struct intel_pipe_wm active;
>> > +               /*
>> > +                * watermarks queued for next vblank
>> > +                * protected by dev_priv->wm.mutex
>> > +                */
>> > +               struct intel_pipe_wm pending;
>> > +
>> > +               /*
>> > +                * the vblank count after which we can switch over to 'pending'
>> > +                * protected by intel_crtc->wm.lock
>> > +                */
>> > +               u32 pending_vbl_count;
>> > +               /*
>> > +                * indicates that 'pending' contains changed watermarks
>> > +                * protected by intel_crtc->wm.lock
>> > +                */
>> > +               bool dirty;
>> > +               /*
>> > +                * watermark update has a vblank reference?
>> > +                * protected by intel_crtc->wm.lock
>> > +                */
>> > +               bool vblank;
>>
>> I would rename this variable. Maybe has_vblank_ref?
>
> I think I had it something like that originally but changed it at some
> point when I got tired of the extra characters ;) I can change it back.
>
>>
>>
>> > +
>> > +               /*
>> > +                * protects some intel_crtc->wm state
>>
>> Please be more precise on what "some" actually means, since it's easy
>> to guess that a spinlock protects "some related state" :P
>
> The precise part is there in the comments for each struct member.
>
>>
>>
>> > +                */
>> > +               spinlock_t lock;
>> >         } wm;
>> >
>> >         wait_queue_head_t vbl_wait;
>> > @@ -974,6 +1000,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
>> >  void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
>> >  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
>> >  void ilk_wm_get_hw_state(struct drm_device *dev);
>> > +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
>>
>> This chunk needs rebase.
>>
>>
>> >
>> >
>> >  /* intel_sdvo.c */
>> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
>> > index 2a63418..6fc6416 100644
>> > --- a/drivers/gpu/drm/i915/intel_pm.c
>> > +++ b/drivers/gpu/drm/i915/intel_pm.c
>> > @@ -2752,6 +2752,65 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
>> >         return changed;
>> >  }
>> >
>> > +static bool vbl_count_after_eq(struct drm_device *dev, u32 a, u32 b)
>>
>> Since I had to stop and think for more than 10 seconds to discover if
>> this was checking for A >= B or A <= B or something else, I think this
>> function deserves a nice comment explaining what it's supposed to do.
>
> I added such a comment for the flip counter check, but forgot to
> add one here. Will add it.
>
>>
>>
>> > +{
>> > +       u32 mask = dev->max_vblank_count;
>> > +
>> > +       /* just the msb please */
>> > +       mask &= ~(mask >> 1);
>> > +
>> > +       return !((a - b) & mask);
>> > +}
>> > +
>> > +static bool ilk_pending_watermarks_ready(struct intel_crtc *crtc)
>> > +{
>> > +       struct drm_device *dev = crtc->base.dev;
>> > +       u32 vbl_count;
>> > +
>> > +       assert_spin_locked(&crtc->wm.lock);
>> > +
>> > +       if (!crtc->wm.dirty)
>> > +               return false;
>> > +
>> > +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
>> > +
>> > +       if (!vbl_count_after_eq(dev, vbl_count, crtc->wm.pending_vbl_count))
>> > +               return false;
>> > +
>> > +       if (crtc->wm.vblank) {
>> > +               drm_vblank_put(dev, crtc->pipe);
>> > +               crtc->wm.vblank = false;
>> > +       }
>> > +
>> > +       return true;
>> > +}
>> > +
>> > +static bool ilk_refresh_pending_watermarks(struct drm_device *dev)
>> > +{
>> > +       struct intel_crtc *crtc;
>> > +       bool changed = false;
>> > +
>> > +       for_each_intel_crtc(dev, crtc) {
>> > +               bool ready;
>> > +
>> > +               spin_lock_irq(&crtc->wm.lock);
>> > +
>> > +               ready = ilk_pending_watermarks_ready(crtc);
>> > +               if (ready)
>> > +                       crtc->wm.dirty = false;
>> > +
>> > +               spin_unlock_irq(&crtc->wm.lock);
>> > +
>> > +               if (!ready)
>> > +                       continue;
>> > +
>> > +               crtc->wm.active = crtc->wm.pending;
>> > +               changed = true;
>> > +       }
>> > +
>> > +       return changed;
>> > +}
>> > +
>> >  static void ilk_program_watermarks(struct drm_device *dev)
>> >  {
>> >         struct drm_i915_private *dev_priv = dev->dev_private;
>> > @@ -2810,6 +2869,87 @@ static void ilk_update_wm(struct drm_crtc *crtc)
>> >         mutex_unlock(&dev_priv->wm.mutex);
>> >  }
>> >
>> > +static void ilk_update_watermarks(struct drm_device *dev)
>>
>> Now we have ilk_update_wm() and ilk_update_watermarks(). This is
>> confusing, since one can't really tell the difference just by reading
>> the name. Maybe we should rename one of them (unless a future patch
>> kills one of them, which I didn't check yet).
>
> Yeah the other one gets killed in one of the following patches.
>
>>
>>
>> > +{
>> > +       bool changed;
>> > +
>> > +       changed = ilk_refresh_pending_watermarks(dev);
>> > +
>> > +       if (changed)
>> > +               ilk_program_watermarks(dev);
>>
>> Also, don't we need to grab dev_priv->wm.mutex here? I'm asking since
>> the other caller of ilk_program_watermarks() has the mutex locked. It
>> should probably help if we had assert_mutex_is_locked() at some
>> places. Or maybe the callers of ilk_program_watermarks() would need
>> the lock.
>
> Here the caller is responsible for the locking. I should sprinkle some
> lockdep asserts around.
>
>>
>>
>> > +}
>> > +
>> > +static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
>> > +                                        const struct intel_pipe_wm *pipe_wm,
>> > +                                        u32 vbl_count)
>> > +{
>> > +       struct drm_device *dev = crtc->base.dev;
>> > +       enum pipe pipe = crtc->pipe;
>> > +
>> > +       WARN(!crtc->active, "pipe %c should be enabled\n",
>> > +            pipe_name(pipe));
>> > +
>> > +       /* do the watermarks actually need changing? */
>> > +       if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
>> > +               return;
>> > +
>> > +       crtc->wm.pending = *pipe_wm;
>> > +
>> > +       spin_lock_irq(&crtc->wm.lock);
>> > +       crtc->wm.pending_vbl_count = (vbl_count + 1) & dev->max_vblank_count;
>> > +       crtc->wm.dirty = true;
>> > +       spin_unlock_irq(&crtc->wm.lock);
>> > +
>> > +       /* try to update immediately */
>> > +       ilk_update_watermarks(dev);
>>
>> I'm failing to imagine a case where this would help. Can you please tell me?
>
> In case the target vblank passed already. Though this is racy since we do
> the check before drm_vblank_get() so we might still miss the interrupt
> and then have to wait for the next one. I should reorder this a bit...
>
> Although I now have a rather generic vblank notify mechanism cooking as
> part of my fbc patches that doesn't suffer from this race, and my plan
> is to use it also for watermarks. But back when I wrote the watermark
> patches I didn't have the vblank notify thing coded up yet. Also I've
> not yet tried to use it for watermarks, so it might require a bit of
> further tuning before it can handle such things. This is just a FYI
> really. I don't think we should stall the watermark patches behind
> the vblank notify thing.
>
>>
>>
>> > +
>> > +       spin_lock_irq(&crtc->wm.lock);
>> > +
>> > +       /* did the immediate update succeed? */
>> > +       if (!crtc->wm.dirty)
>> > +               goto unlock;
>> > +
>> > +       /*
>> > +        * We might already have a pending watermark update, in
>> > +        * which case we shouldn't grab another vblank reference.
>> > +        */
>> > +       if (!crtc->wm.vblank && drm_vblank_get(dev, pipe) == 0)
>> > +               crtc->wm.vblank = true;
>> > +
>> > +       WARN(!crtc->wm.vblank,
>> > +            "unable to set up watermarks for pipe %c\n", pipe_name(pipe));
>> > +
>> > + unlock:
>> > +       spin_unlock_irq(&crtc->wm.lock);
>> > +}
>> > +
>> > +static void ilk_watermark_work(struct work_struct *work)
>> > +{
>> > +       struct drm_i915_private *dev_priv =
>> > +               container_of(work, struct drm_i915_private, wm.work);
>> > +
>> > +       mutex_lock(&dev_priv->wm.mutex);
>> > +
>> > +       ilk_update_watermarks(dev_priv->dev);
>> > +
>> > +       mutex_unlock(&dev_priv->wm.mutex);
>> > +}
>> > +
>> > +/* Called from vblank irq */
>> > +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
>> > +{
>> > +       struct drm_i915_private *dev_priv = dev->dev_private;
>> > +       struct intel_crtc *crtc =
>> > +               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
>> > +
>> > +       spin_lock(&crtc->wm.lock);
>> > +
>> > +       if (ilk_pending_watermarks_ready(crtc))
>> > +               schedule_work(&dev_priv->wm.work);
>> > +
>> > +       spin_unlock(&crtc->wm.lock);
>> > +}
>> > +
>> >  static void ilk_update_sprite_wm(struct drm_plane *plane,
>> >                                      struct drm_crtc *crtc,
>> >                                      uint32_t sprite_width, int pixel_size,
>> > @@ -2872,6 +3012,9 @@ static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
>> >                 for (level = 0; level <= max_level; level++)
>> >                         active->wm[level].enable = true;
>> >         }
>> > +
>> > +       /* no update pending */
>> > +       intel_crtc->wm.pending = intel_crtc->wm.active;
>>
>> It feels a little weird that the function that gets the HW state will
>> also cancel any scheduled watermark updates. Programmers from the
>> future are really bad, they will probably not notice this and
>> introduce bugs.
>
> This function is only called at init/resume. It populates the software
> state with something that matches the current hardware state. I guess
> a comment explaning the purpose of the function is the best we can do
> here, or do you have a better idea?

The problem is that we can use the get_hw_state functions not only to
check driver state a init/resume, but also to do state tracking
assertions at certain points of the code. Since most (all?) the other
HW state readout functions don't have side-effects, there's a
possibility that someone may add code to do HW state assertion at some
points, and just call these things without realizing the potential
side effects. A comment would help, but moving the assignment to
another place would also solve the problem for me. You choose.

>
>>
>>
>> >  }
>> >
>> >  void ilk_wm_get_hw_state(struct drm_device *dev)
>> > @@ -6385,6 +6528,7 @@ void intel_init_pm(struct drm_device *dev)
>> >         struct drm_i915_private *dev_priv = dev->dev_private;
>> >
>> >         mutex_init(&dev_priv->wm.mutex);
>> > +       INIT_WORK(&dev_priv->wm.work, ilk_watermark_work);
>>
>> Don't we also need to cancel the work in the places where we disable
>> interrupts? Maybe it is possible to schedule a WM update, then disable
>> everything and runtime suspend before the scheduled work happens... Or
>> do something similar at S3 or driver unload.
>
> The crtc disable will eventually wait for the wm update, although it
> would seem to be a good idea to cancel the work in case it got
> scheduled twice and the first run already managed to apply all the
> pending watermarks.
>
> And in fact maybe we don't want to wait for the pending watermark update
> at crtc disable. Everything is going to get turned off anyway soon, so
> letting it roll with the current watermarks till the end seems perfectly
> acceptable, and it might shave off one vblank wait from the modeset.
>
> Anyways I'll see about adding some explicit cancelling somewhere.
>
>>
>> Since there's no caller for ilk_setup_pending_watermarks() I guess
>> this patch will introduce a compiler warning here. I'm not sure what's
>> our policy for that... I guess I'd vote to merge only when the next
>> patches also have their RB tags.
>
> Yeah there are a few patches here that don't make a whole lot of sense
> on their own.
>
>>
>>
>> >
>> >         if (HAS_FBC(dev)) {
>> >                 if (INTEL_INFO(dev)->gen >= 7) {
>> > --
>> > 1.8.5.5
>> >
>> > _______________________________________________
>> > Intel-gfx mailing list
>> > Intel-gfx@lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>>
>>
>> --
>> Paulo Zanoni
>
> --
> Ville Syrjälä
> Intel OTC



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

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

* Re: [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-06-04 14:01       ` Paulo Zanoni
@ 2014-06-04 16:10         ` Daniel Vetter
  2014-06-09 15:01           ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Daniel Vetter @ 2014-06-04 16:10 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Wed, Jun 04, 2014 at 11:01:01AM -0300, Paulo Zanoni wrote:
> > This function is only called at init/resume. It populates the software
> > state with something that matches the current hardware state. I guess
> > a comment explaning the purpose of the function is the best we can do
> > here, or do you have a better idea?
> 
> The problem is that we can use the get_hw_state functions not only to
> check driver state a init/resume, but also to do state tracking
> assertions at certain points of the code. Since most (all?) the other
> HW state readout functions don't have side-effects, there's a
> possibility that someone may add code to do HW state assertion at some
> points, and just call these things without realizing the potential
> side effects. A comment would help, but moving the assignment to
> another place would also solve the problem for me. You choose.

We already do that in other places, e.g. the edp bit depth hacks we have.
But a comment might be justified.

I haven't looked at the details here, just a high-level comment that we do
play such ugly tricks already. And I agree that it's unexpected.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps
  2014-06-03 20:51   ` Paulo Zanoni
@ 2014-06-04 16:22     ` Daniel Vetter
  2014-06-09 17:03       ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Daniel Vetter @ 2014-06-04 16:22 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Tue, Jun 03, 2014 at 05:51:01PM -0300, Paulo Zanoni wrote:
> 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > We need to perform watermark programming before and after changing the
> > plane configuration. Add two new vfuncs to do that. The pre phase is
> > supposed to switch over to the intermediate watermarks which are
> > computed so that they can deal with both the old and new plane
> > configurations. The post phase will arm the vblank based update
> > systems to switch over to the optimal target watermarks after the
> > plane configuration has for sure changed.
> >
> > v2: Pass around intel_crtc and s/intel_crtc/crtc/
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_drv.h  |  5 +++
> >  drivers/gpu/drm/i915/intel_drv.h | 11 +++++
> >  drivers/gpu/drm/i915/intel_pm.c  | 88 ++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 104 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index c90d5ac..d4f8ae8 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -407,6 +407,7 @@ struct intel_plane_config;
> >  struct intel_crtc;
> >  struct intel_limit;
> >  struct dpll;
> > +struct intel_crtc_wm_config;
> >
> >  struct drm_i915_display_funcs {
> >         bool (*fbc_enabled)(struct drm_device *dev);
> > @@ -437,6 +438,10 @@ struct drm_i915_display_funcs {
> >                                  struct drm_crtc *crtc,
> >                                  uint32_t sprite_width, int pixel_size,
> >                                  bool enable, bool scaled);
> > +       void (*program_wm_pre)(struct intel_crtc *crtc,
> > +                              const struct intel_crtc_wm_config *config);
> > +       void (*program_wm_post)(struct intel_crtc *crtc,
> > +                               const struct intel_crtc_wm_config *config);
> >         void (*modeset_global_resources)(struct drm_device *dev);
> >         /* Returns the active state of the crtc, and if the crtc is active,
> >          * fills out the pipe-config with the hw state. */
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 72f01b1..4b59be3 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -358,6 +358,13 @@ struct intel_pipe_wm {
> >         bool sprites_scaled;
> >  };
> >
> > +struct intel_crtc_wm_config {
> > +       /* target watermarks for the pipe */
> > +       struct intel_pipe_wm target;
> > +       /* intermediate watermarks for pending/active->target transition */
> > +       struct intel_pipe_wm intm;
> 
> It seems you always prefer shorter names such as "intm", and I usually
> prefer the longer ones like "intermediate". Looks like this is a
> common topic for my bikesheddings on your patches. When I read "intm"
> my brain parses it as "Int M" and then aborts execution =P

I agree with Paulo here. Some other name suggestion (since intermediate is
so long): transition/transit, merged, pending, ...
-Daniel

> 
> With or without that changed: Reviewed-by: Paulo Zanoni
> <paulo.r.zanoni@intel.com>
> 
> > +};
> > +
> >  struct intel_crtc {
> >         struct drm_crtc base;
> >         enum pipe pipe;
> > @@ -1001,6 +1008,10 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
> >  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
> >  void ilk_wm_get_hw_state(struct drm_device *dev);
> >  void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
> > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> > +                                 const struct intel_crtc_wm_config *config);
> > +void intel_program_watermarks_post(struct intel_crtc *crtc,
> > +                                  const struct intel_crtc_wm_config *config);
> >
> >
> >  /* intel_sdvo.c */
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 6fc6416..ccf920a 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -2950,6 +2950,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
> >         spin_unlock(&crtc->wm.lock);
> >  }
> >
> > +static void ilk_wm_cancel(struct intel_crtc *crtc)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +
> > +       assert_spin_locked(&crtc->wm.lock);
> > +
> > +       crtc->wm.dirty = false;
> > +
> > +       if (crtc->wm.vblank) {
> > +               drm_vblank_put(dev, crtc->pipe);
> > +               crtc->wm.vblank = false;
> > +       }
> > +}
> > +
> >  static void ilk_update_sprite_wm(struct drm_plane *plane,
> >                                      struct drm_crtc *crtc,
> >                                      uint32_t sprite_width, int pixel_size,
> > @@ -3084,6 +3098,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
> >                                                    pixel_size, enabled, scaled);
> >  }
> >
> > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> > +                                 const struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +
> > +       if (dev_priv->display.program_wm_pre)
> > +               dev_priv->display.program_wm_pre(crtc, config);
> > +}
> > +
> > +void intel_program_watermarks_post(struct intel_crtc *crtc,
> > +                                  const struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +
> > +       if (dev_priv->display.program_wm_post)
> > +               dev_priv->display.program_wm_post(crtc, config);
> > +}
> > +
> >  static struct drm_i915_gem_object *
> >  intel_alloc_context_page(struct drm_device *dev)
> >  {
> > @@ -6522,6 +6554,60 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
> >         pm_runtime_disable(device);
> >  }
> >
> > +static void ilk_program_wm_pre(struct intel_crtc *crtc,
> > +                              const struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > +
> > +       mutex_lock(&dev_priv->wm.mutex);
> > +
> > +       spin_lock_irq(&crtc->wm.lock);
> > +       ilk_wm_cancel(crtc);
> > +       spin_unlock_irq(&crtc->wm.lock);
> > +
> > +       /* pending update (if any) got cancelled */
> > +       crtc->wm.pending = crtc->wm.active;
> > +
> > +       if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
> > +               goto unlock;
> > +
> > +       crtc->wm.active = config->intm;
> > +
> > +       /* use the most up to date watermarks for other pipes */
> > +       ilk_refresh_pending_watermarks(dev);
> > +
> > +       /* switch over to the intermediate watermarks */
> > +       ilk_program_watermarks(dev);
> > +
> > + unlock:
> > +       mutex_unlock(&dev_priv->wm.mutex);
> > +}
> > +
> > +static void ilk_program_wm_post(struct intel_crtc *crtc,
> > +                               const struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > +       u32 vbl_count;
> > +
> > +       /*
> > +        * FIXME sample this inside the atomic section to avoid
> > +        * needlessly long periods w/ sub-par watermarks
> > +        */
> > +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
> > +
> > +       mutex_lock(&dev_priv->wm.mutex);
> > +
> > +       /*
> > +        * We can switch over to the target
> > +        * watermarks after the next vblank.
> > +        */
> > +       ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
> > +
> > +       mutex_unlock(&dev_priv->wm.mutex);
> > +}
> > +
> >  /* Set up chip specific power management-related functions */
> >  void intel_init_pm(struct drm_device *dev)
> >  {
> > @@ -6569,6 +6655,8 @@ void intel_init_pm(struct drm_device *dev)
> >                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
> >                         dev_priv->display.update_wm = ilk_update_wm;
> >                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> > +                       dev_priv->display.program_wm_pre = ilk_program_wm_pre;
> > +                       dev_priv->display.program_wm_post = ilk_program_wm_post;
> >                 } else {
> >                         DRM_DEBUG_KMS("Failed to read display plane latency. "
> >                                       "Disable CxSR\n");
> > --
> > 1.8.5.5
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH 11/16] drm/i915: Refactor get_other_active_crtc()
  2014-05-22 14:48 ` [PATCH 11/16] drm/i915: Refactor get_other_active_crtc() ville.syrjala
@ 2014-06-04 16:59   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 16:59 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Pull the code to locate the other active crtc out from
> haswell_mode_set_planes_workaround() into a separate function.
> This will have another use later.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_display.c | 33 +++++++++++++++++++++------------
>  1 file changed, 21 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index ca362db..bccf414 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3965,6 +3965,26 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
>         drm_vblank_off(dev, pipe);
>  }
>
> +static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct intel_crtc *crtc_it, *other_active_crtc = NULL;
> +
> +       /* We want to get the other_active_crtc only if there's only 1 other
> +        * active crtc. */
> +       for_each_intel_crtc(dev, crtc_it) {
> +               if (!crtc_it->active || crtc_it == crtc)
> +                       continue;
> +
> +               if (other_active_crtc)
> +                       return NULL;
> +
> +               other_active_crtc = crtc_it;
> +       }
> +
> +       return other_active_crtc;
> +}
> +
>  static void ironlake_crtc_enable(struct drm_crtc *crtc)
>  {
>         struct drm_device *dev = crtc->dev;
> @@ -4057,19 +4077,8 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
>  static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc)
>  {
>         struct drm_device *dev = crtc->base.dev;
> -       struct intel_crtc *crtc_it, *other_active_crtc = NULL;
> -
> -       /* We want to get the other_active_crtc only if there's only 1 other
> -        * active crtc. */
> -       for_each_intel_crtc(dev, crtc_it) {
> -               if (!crtc_it->active || crtc_it == crtc)
> -                       continue;
> +       struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc);
>
> -               if (other_active_crtc)
> -                       return;
> -
> -               other_active_crtc = crtc_it;
> -       }
>         if (!other_active_crtc)
>                 return;
>
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes
  2014-05-22 14:48 ` [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes ville.syrjala
@ 2014-06-04 18:24   ` Paulo Zanoni
  2014-06-09 16:51     ` Ville Syrjälä
  0 siblings, 1 reply; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 18:24 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> When we switch between one active pipe and multiple active pipes, the
> display FIFO gets repartitioned. Disable the LP1+ waterwarks while that
> is happening to make sure we don't get any glitches on other active
> pipes while doing a modeset on another other pipe.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c | 45 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h     |  2 ++
>  drivers/gpu/drm/i915/intel_pm.c      | 47 ++++++++++++++++++++++++++++++++----
>  3 files changed, 89 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index bccf414..311c0f0 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3985,6 +3985,27 @@ static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc)
>         return other_active_crtc;
>  }
>
> +static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc);
> +
> +       /*
> +        * If we change between one pipe and multiple pipes,
> +        * make sure the other active pipe is prepared
> +        * for having its FIFO resized. We do that by making
> +        * sure the pipe isn't using LP1+ watermarks when
> +        * the second pipe gets enabled or disabled.
> +        */
> +       if (!other_active_crtc)
> +               return;

But get_other_active_crtc() returns NULL in case 2 other CRTCs are
already active. If we're the third pipe being enabled, we may still
get an underrun.

> +
> +       ilk_wm_synchronize(other_active_crtc);
> +
> +       if (ilk_disable_lp_wm(dev))
> +               intel_wait_for_vblank(dev, other_active_crtc->pipe);
> +}
> +
>  static void ironlake_crtc_enable(struct drm_crtc *crtc)
>  {
>         struct drm_device *dev = crtc->dev;
> @@ -4023,6 +4044,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>
>         intel_crtc->active = true;
>
> +       /* Make sure other pipes are prepared for FIFO resizing */
> +       ilk_prepare_for_num_pipes_change(intel_crtc);
> +
>         intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
>         intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
>
> @@ -4123,6 +4147,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>
>         intel_crtc->active = true;
>
> +       /* Make sure other pipes are prepared for FIFO resizing */
> +       ilk_prepare_for_num_pipes_change(intel_crtc);
> +
>         intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
>         if (intel_crtc->config.has_pch_encoder)
>                 intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
> @@ -4192,6 +4219,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>
>         intel_crtc_disable_planes(crtc);
>
> +       /* Make sure other pipes are prepared for FIFO resizing */
> +       ilk_prepare_for_num_pipes_change(intel_crtc);
> +
>         for_each_encoder_on_crtc(dev, crtc, encoder)
>                 encoder->disable(encoder);
>
> @@ -4235,6 +4265,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>
>         intel_crtc->active = false;
>
> +       /*
> +        * Potentially let some other pipe use the
> +        * full FIFO, and re-enable LP1+ watermarks.
> +        */
> +       ilk_wm_pipe_post_disable(intel_crtc);
> +
>         mutex_lock(&dev->struct_mutex);
>         intel_update_fbc(dev);
>         intel_edp_psr_update(dev);
> @@ -4255,6 +4291,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>
>         intel_crtc_disable_planes(crtc);
>
> +       /* Make sure other pipes are prepared for FIFO resizing */
> +       ilk_prepare_for_num_pipes_change(intel_crtc);
> +
>         for_each_encoder_on_crtc(dev, crtc, encoder) {
>                 intel_opregion_notify_encoder(encoder, false);
>                 encoder->disable(encoder);
> @@ -4282,6 +4321,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>
>         intel_crtc->active = false;
>
> +       /*
> +        * Potentially let some other pipe use the
> +        * full FIFO, and re-enable LP1+ watermarks.
> +        */
> +       ilk_wm_pipe_post_disable(intel_crtc);
> +
>         mutex_lock(&dev->struct_mutex);
>         intel_update_fbc(dev);
>         intel_edp_psr_update(dev);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 5ad7ad5..98f878f 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1022,6 +1022,8 @@ void intel_program_watermarks_pre(struct intel_crtc *crtc,
>  void intel_program_watermarks_post(struct intel_crtc *crtc,
>                                    const struct intel_crtc_wm_config *config);
>  void ilk_wm_synchronize(struct intel_crtc *crtc);
> +void ilk_wm_pipe_post_disable(struct intel_crtc *crtc);
> +bool ilk_disable_lp_wm(struct drm_device *dev);
>
>
>  /* intel_sdvo.c */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 1c072cd..18ea8b1 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2765,7 +2765,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
>         }
>  }
>
> -static bool ilk_disable_lp_wm(struct drm_device *dev)
> +bool ilk_disable_lp_wm(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         bool changed;
> @@ -2873,16 +2873,17 @@ static void ilk_program_watermarks(struct drm_device *dev)
>         ilk_write_wm_values(dev_priv, &results);
>  }
>
> -static void ilk_update_watermarks(struct drm_device *dev)
> +static void ilk_update_watermarks(struct drm_device *dev, bool force)
>  {
>         bool changed;
>
>         changed = ilk_refresh_pending_watermarks(dev);
>
> -       if (changed)
> +       if (changed || force)
>                 ilk_program_watermarks(dev);
>  }
>
> +/* Prepare the pipe to update the its watermarks on the next vblank */
>  static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
>                                          const struct intel_pipe_wm *pipe_wm,
>                                          u32 vbl_count)
> @@ -2905,7 +2906,7 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
>         spin_unlock_irq(&crtc->wm.lock);
>
>         /* try to update immediately */
> -       ilk_update_watermarks(dev);
> +       ilk_update_watermarks(dev, false);
>
>         spin_lock_irq(&crtc->wm.lock);
>
> @@ -2999,7 +3000,7 @@ static void ilk_watermark_work(struct work_struct *work)
>
>         mutex_lock(&dev_priv->wm.mutex);
>
> -       ilk_update_watermarks(dev_priv->dev);
> +       ilk_update_watermarks(dev_priv->dev, false);
>
>         mutex_unlock(&dev_priv->wm.mutex);
>  }
> @@ -3060,6 +3061,42 @@ void ilk_wm_synchronize(struct intel_crtc *crtc)
>         mutex_unlock(&dev_priv->wm.mutex);
>  }
>
> +void ilk_wm_pipe_post_disable(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct ilk_pipe_wm_parameters params = {};
> +       struct intel_pipe_wm pipe_wm = {};
> +
> +       WARN(crtc->active, "pipe %c should be disabled\n",
> +            pipe_name(crtc->pipe));
> +
> +       ilk_compute_wm_parameters(&crtc->base, &params);
> +
> +       intel_compute_pipe_wm(&crtc->base, &params, &pipe_wm);
> +
> +       mutex_lock(&dev_priv->wm.mutex);
> +
> +       spin_lock_irq(&crtc->wm.lock);
> +
> +       WARN(crtc->wm.dirty, "pipe %c disabled with dirty watermarks\n",
> +            pipe_name(crtc->pipe));
> +
> +       /* clean up if something is left behind */
> +       ilk_wm_cancel(crtc);
> +
> +       spin_unlock_irq(&crtc->wm.lock);
> +
> +       crtc->wm.active = pipe_wm;
> +
> +       /* pending update (if any) got cancelled */
> +       crtc->wm.pending = crtc->wm.active;
> +
> +       ilk_update_watermarks(dev, true);
> +
> +       mutex_unlock(&dev_priv->wm.mutex);
> +}
> +
>  static int ilk_update_primary_wm(struct intel_crtc *crtc,
>                                  struct intel_crtc_wm_config *config)
>  {
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks
  2014-05-22 14:48 ` [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks ville.syrjala
@ 2014-06-04 18:30   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 18:30 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Currently ilk_disable_lp_wm() just disabled LP1+ watermarks directly.
> However there's nothing preventing someone else from re-enabling them
> immediately. To make sure sure LP1+ watermarks stay disabled for the
> intended period, keep track which pipes require the LP1+ watermarks
> to be disabled.
>
> v2: Rebase and s/intel_crtc/crtc/

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |  6 ++++++
>  drivers/gpu/drm/i915/intel_display.c |  2 +-
>  drivers/gpu/drm/i915/intel_drv.h     |  2 +-
>  drivers/gpu/drm/i915/intel_pm.c      | 22 ++++++++++++++++++----
>  4 files changed, 26 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1fe0cac..02ffbfc 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1548,6 +1548,12 @@ struct drm_i915_private {
>                 struct ilk_wm_values hw;
>
>                 /*
> +                * bitmask of pipes that have requested
> +                * LP1+ watermarks to be disabled.
> +                */
> +               unsigned int lp_disabled;
> +
> +               /*
>                  * protects some dev_priv->wm and intel_crtc->wm
>                  * state as well as the actual hardware registers
>                  */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 311c0f0..879c649 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4002,7 +4002,7 @@ static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc)
>
>         ilk_wm_synchronize(other_active_crtc);
>
> -       if (ilk_disable_lp_wm(dev))
> +       if (ilk_disable_lp_wm(crtc))
>                 intel_wait_for_vblank(dev, other_active_crtc->pipe);
>  }
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 98f878f..2a3ad60 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1023,7 +1023,7 @@ void intel_program_watermarks_post(struct intel_crtc *crtc,
>                                    const struct intel_crtc_wm_config *config);
>  void ilk_wm_synchronize(struct intel_crtc *crtc);
>  void ilk_wm_pipe_post_disable(struct intel_crtc *crtc);
> -bool ilk_disable_lp_wm(struct drm_device *dev);
> +bool ilk_disable_lp_wm(struct intel_crtc *crtc);
>
>
>  /* intel_sdvo.c */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 18ea8b1..17f1769 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2428,6 +2428,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
>                                    enum intel_ddb_partitioning partitioning,
>                                    struct ilk_wm_values *results)
>  {
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         struct intel_crtc *intel_crtc;
>         int level, wm_lp;
>
> @@ -2451,7 +2452,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
>                         (r->pri_val << WM1_LP_SR_SHIFT) |
>                         r->cur_val;
>
> -               if (r->enable)
> +               if (r->enable && !dev_priv->wm.lp_disabled)
>                         results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
>
>                 if (INTEL_INFO(dev)->gen >= 8)
> @@ -2765,13 +2766,18 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
>         }
>  }
>
> -bool ilk_disable_lp_wm(struct drm_device *dev)
> +bool ilk_disable_lp_wm(struct intel_crtc *crtc)
>  {
> +       struct drm_device *dev = crtc->base.dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         bool changed;
>
>         mutex_lock(&dev_priv->wm.mutex);
> +
> +       dev_priv->wm.lp_disabled |= 1 << crtc->pipe;
> +
>         changed = _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
> +
>         mutex_unlock(&dev_priv->wm.mutex);
>
>         return changed;
> @@ -2889,15 +2895,20 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
>                                          u32 vbl_count)
>  {
>         struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         enum pipe pipe = crtc->pipe;
>
>         WARN(!crtc->active, "pipe %c should be enabled\n",
>              pipe_name(pipe));
>
>         /* do the watermarks actually need changing? */
> -       if (!memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
> +       if (!(dev_priv->wm.lp_disabled & (1 << pipe)) &&
> +           !memcmp(&crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
>                 return;
>
> +       /* allow LP1+ watermarks again */
> +       dev_priv->wm.lp_disabled &= ~(1 << pipe);
> +
>         crtc->wm.pending = *pipe_wm;
>
>         spin_lock_irq(&crtc->wm.lock);
> @@ -3092,6 +3103,9 @@ void ilk_wm_pipe_post_disable(struct intel_crtc *crtc)
>         /* pending update (if any) got cancelled */
>         crtc->wm.pending = crtc->wm.active;
>
> +       /* allow LP1+ watermarks again */
> +       dev_priv->wm.lp_disabled &= ~(1 << crtc->pipe);
> +
>         ilk_update_watermarks(dev, true);
>
>         mutex_unlock(&dev_priv->wm.mutex);
> @@ -3145,7 +3159,7 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
>          *
>          * WaCxSRDisabledForSpriteScaling:ivb
>          */
> -       if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
> +       if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
>                 intel_wait_for_vblank(dev, plane->pipe);
>
>         params.pri = config->pri;
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled
  2014-05-22 14:48 ` [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled ville.syrjala
@ 2014-06-04 18:34   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 18:34 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> When the primary plane is disabled, pick the 5/6 DDB split to give the
> sprite as much FIFO space as possible.
>
> The normal heuristic of just looking at the highest valid WM level won't
> necessarily pick the optimal split since both splits might have the same
> number of levels enabled.
>
> Preferring the 5/6 split won't actually affect the watermarks here, but
> it does give more FIFO space to the sprite leading to potentially longer
> periods spent in LP1+ states since the FIFO takes longer to drain.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_drv.h |  1 +
>  drivers/gpu/drm/i915/intel_pm.c  | 27 ++++++++++++++++++++++-----
>  2 files changed, 23 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 2a3ad60..4575017 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -354,6 +354,7 @@ struct intel_pipe_wm {
>         uint32_t linetime;
>         bool fbc_wm_enabled;
>         bool pipe_enabled;
> +       bool primary_enabled;
>         bool sprites_enabled;
>         bool sprites_scaled;
>  };
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 17f1769..66af79d 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -1736,6 +1736,7 @@ struct ilk_wm_maximums {
>  /* used in computing the new watermarks state */
>  struct intel_wm_config {
>         unsigned int num_pipes_active;
> +       bool primary_enabled;
>         bool sprites_enabled;
>         bool sprites_scaled;
>  };
> @@ -2212,6 +2213,7 @@ static void ilk_compute_wm_config(struct drm_device *dev,
>                 if (!wm->pipe_enabled)
>                         continue;
>
> +               config->primary_enabled |= wm->primary_enabled;
>                 config->sprites_enabled |= wm->sprites_enabled;
>                 config->sprites_scaled |= wm->sprites_scaled;
>                 config->num_pipes_active++;
> @@ -2224,6 +2226,7 @@ static bool ilk_validate_pipe_wm(struct drm_device *dev,
>         /* LP0 watermark maximums depend on this pipe alone */
>         const struct intel_wm_config config = {
>                 .num_pipes_active = 1,
> +               .primary_enabled = pipe_wm->primary_enabled,
>                 .sprites_enabled = pipe_wm->sprites_enabled,
>                 .sprites_scaled = pipe_wm->sprites_scaled,
>         };
> @@ -2247,6 +2250,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
>         struct ilk_wm_maximums max;
>
>         pipe_wm->pipe_enabled = params->active;
> +       pipe_wm->primary_enabled = params->pri.enabled;
>         pipe_wm->sprites_enabled = params->spr.enabled;
>         pipe_wm->sprites_scaled = params->spr.scaled;
>
> @@ -2299,6 +2303,7 @@ static void ilk_wm_merge_intermediate(struct drm_device *dev,
>         int level, max_level = ilk_wm_max_level(dev);
>
>         a->pipe_enabled |= b->pipe_enabled;
> +       a->primary_enabled |= b->primary_enabled;
>         a->sprites_enabled |= b->sprites_enabled;
>         a->sprites_scaled |= b->sprites_scaled;
>
> @@ -2491,11 +2496,21 @@ static void ilk_compute_wm_results(struct drm_device *dev,
>         }
>  }
>
> -/* Find the result with the highest level enabled. Check for enable_fbc_wm in
> - * case both are at the same level. Prefer r1 in case they're the same. */
> +/*
> + * Find the result with the highest level enabled.
> + * When the max level for each result is the same, pick r2
> + * when the primary plane is disabled, otherwise prefer the
> + * result which has FBC WM enabled. All else being equal, pick
> + * r1.
> + *
> + * FIXME should ideally calculate the FIFO drain time for each
> + * plane, and determine which split has the chance to keep
> + * the memory asleep for longest.
> + */
>  static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
>                                                   struct intel_pipe_wm *r1,
> -                                                 struct intel_pipe_wm *r2)
> +                                                 struct intel_pipe_wm *r2,
> +                                                 bool primary_enabled)
>  {
>         int level, max_level = ilk_wm_max_level(dev);
>         int level1 = 0, level2 = 0;
> @@ -2508,7 +2523,8 @@ static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
>         }
>
>         if (level1 == level2) {
> -               if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled)
> +               if (!primary_enabled ||
> +                   (r2->fbc_wm_enabled && !r1->fbc_wm_enabled))
>                         return r2;
>                 else
>                         return r1;
> @@ -2866,7 +2882,8 @@ static void ilk_program_watermarks(struct drm_device *dev)
>                 ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
>                 ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
>
> -               best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
> +               best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6,
> +                                                 config.primary_enabled);
>         } else {
>                 best_lp_wm = &lp_wm_1_2;
>         }
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching
  2014-05-22 14:48 ` [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching ville.syrjala
@ 2014-06-04 18:44   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 18:44 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> ILK and IVB don't like switching between sprite only and primary only
> configurations when LP1+ watermarks have been enabled in the recent
> past. Like WaCxSRDisabledForSpriteScaling we can avoid the flash
> by disabling LP1+ watermarks for one frame before the critical plane
> reconfiguration.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_pm.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 66af79d..ea1f990 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3175,9 +3175,18 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
>          * when scaling is disabled.
>          *
>          * WaCxSRDisabledForSpriteScaling:ivb
> +        *
> +        * We also seem to need something similar when switching between
> +        * primary only and sprite only configurations. Otherwise the screen
> +        * flashes black. No underrun reported though.
>          */
>         if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
>                 intel_wait_for_vblank(dev, plane->pipe);
> +       else if (config->pri.enabled != config->spr.enabled &&
> +                config->pri.enabled != params.pri.enabled &&
> +                config->spr.enabled != params.spr.enabled &&
> +                ilk_disable_lp_wm(crtc))
> +               intel_wait_for_vblank(dev, plane->pipe);

Those names are bad. It is not clear at all which one is the "curent"
one and which one is the one we're going to set (between config->x and
params->x). I hope we can fix this later.

Still, the patch seems correct: Reviewed-by: Paulo Zanoni
<paulo.r.zanoni@intel.com>.

>
>         params.pri = config->pri;
>         params.spr = config->spr;
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled
  2014-05-22 14:48 ` [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled ville.syrjala
@ 2014-06-04 18:49   ` Paulo Zanoni
  0 siblings, 0 replies; 39+ messages in thread
From: Paulo Zanoni @ 2014-06-04 18:49 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Intel Graphics Development

2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> If we mark the LP1+ watermarks as disabled every time sprite scaling
> is enabled, we end doing pointless work applying watermarks even though
> nothing has changed. This is an artifact of the way
> dev_priv->wm.lp_disabled affects the operation of
> ilk_setup_pending_watermarks(). If the current pipe is included in
> dev_priv->wm.lp_disabled, ilk_setup_pending_watermarks() will not check
> if the watermarks actually changed since it will assume it will need to
> disable LP1+ watermarks anyway.
>
> A quick fix is to just check if sprite scaling was enabled for the
> previous plane update, and if so, we know that LP1+ watermarks must
> already be disabled. It might be better in long run to attempt to
> change the way the LP1+ disable tracking integrates with the rest of
> the watermark update mechanism. But this seems like a simple enough
> solution for now.

I agree. Adding TODO a comment somewhere describing the possible
improvement wouldn't hurt either.

With or without that: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_pm.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index ea1f990..0365ea6 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3180,7 +3180,8 @@ static int ilk_update_sprite_wm(struct intel_plane *plane,
>          * primary only and sprite only configurations. Otherwise the screen
>          * flashes black. No underrun reported though.
>          */
> -       if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(crtc))
> +       if (IS_IVYBRIDGE(dev) && !params.spr.scaled &&
> +           config->spr.scaled && ilk_disable_lp_wm(crtc))
>                 intel_wait_for_vblank(dev, plane->pipe);
>         else if (config->pri.enabled != config->spr.enabled &&
>                  config->pri.enabled != params.pri.enabled &&
> --
> 1.8.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



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

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

* Re: [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism
  2014-06-04 16:10         ` Daniel Vetter
@ 2014-06-09 15:01           ` Ville Syrjälä
  0 siblings, 0 replies; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-09 15:01 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 04, 2014 at 06:10:44PM +0200, Daniel Vetter wrote:
> On Wed, Jun 04, 2014 at 11:01:01AM -0300, Paulo Zanoni wrote:
> > > This function is only called at init/resume. It populates the software
> > > state with something that matches the current hardware state. I guess
> > > a comment explaning the purpose of the function is the best we can do
> > > here, or do you have a better idea?
> > 
> > The problem is that we can use the get_hw_state functions not only to
> > check driver state a init/resume, but also to do state tracking
> > assertions at certain points of the code. Since most (all?) the other
> > HW state readout functions don't have side-effects, there's a
> > possibility that someone may add code to do HW state assertion at some
> > points, and just call these things without realizing the potential
> > side effects. A comment would help, but moving the assignment to
> > another place would also solve the problem for me. You choose.
> 
> We already do that in other places, e.g. the edp bit depth hacks we have.
> But a comment might be justified.
> 
> I haven't looked at the details here, just a high-level comment that we do
> play such ugly tricks already. And I agree that it's unexpected.

Well IIRC I didn't even call this function get_hw_state() until
"someone" asked me to rename it ;) I could rename it back to whatever
it was originally. It was never meant to be just a "read hardware state
into a temp structure" type of thing since it's been updating
intel_crtc->wm.active from the start.

With the rename I should be able to drop the ugly underscore from
_ilk_wm_get_hw_state().

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes
  2014-06-04 18:24   ` Paulo Zanoni
@ 2014-06-09 16:51     ` Ville Syrjälä
  0 siblings, 0 replies; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-09 16:51 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Wed, Jun 04, 2014 at 03:24:13PM -0300, Paulo Zanoni wrote:
> 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > When we switch between one active pipe and multiple active pipes, the
> > display FIFO gets repartitioned. Disable the LP1+ waterwarks while that
> > is happening to make sure we don't get any glitches on other active
> > pipes while doing a modeset on another other pipe.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_display.c | 45 ++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/intel_drv.h     |  2 ++
> >  drivers/gpu/drm/i915/intel_pm.c      | 47 ++++++++++++++++++++++++++++++++----
> >  3 files changed, 89 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index bccf414..311c0f0 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -3985,6 +3985,27 @@ static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc)
> >         return other_active_crtc;
> >  }
> >
> > +static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc);
> > +
> > +       /*
> > +        * If we change between one pipe and multiple pipes,
> > +        * make sure the other active pipe is prepared
> > +        * for having its FIFO resized. We do that by making
> > +        * sure the pipe isn't using LP1+ watermarks when
> > +        * the second pipe gets enabled or disabled.
> > +        */
> > +       if (!other_active_crtc)
> > +               return;
> 
> But get_other_active_crtc() returns NULL in case 2 other CRTCs are
> already active. If we're the third pipe being enabled, we may still
> get an underrun.

The FIFO repartitioning happens only when going 1<->2 pipes, so the
2<->3 cases don't matter here.

> 
> > +
> > +       ilk_wm_synchronize(other_active_crtc);
> > +
> > +       if (ilk_disable_lp_wm(dev))
> > +               intel_wait_for_vblank(dev, other_active_crtc->pipe);
> > +}
> > +
> >  static void ironlake_crtc_enable(struct drm_crtc *crtc)
> >  {
> >         struct drm_device *dev = crtc->dev;
> > @@ -4023,6 +4044,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
> >
> >         intel_crtc->active = true;
> >
> > +       /* Make sure other pipes are prepared for FIFO resizing */
> > +       ilk_prepare_for_num_pipes_change(intel_crtc);
> > +
> >         intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
> >         intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
> >
> > @@ -4123,6 +4147,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
> >
> >         intel_crtc->active = true;
> >
> > +       /* Make sure other pipes are prepared for FIFO resizing */
> > +       ilk_prepare_for_num_pipes_change(intel_crtc);
> > +
> >         intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
> >         if (intel_crtc->config.has_pch_encoder)
> >                 intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
> > @@ -4192,6 +4219,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
> >
> >         intel_crtc_disable_planes(crtc);
> >
> > +       /* Make sure other pipes are prepared for FIFO resizing */
> > +       ilk_prepare_for_num_pipes_change(intel_crtc);
> > +
> >         for_each_encoder_on_crtc(dev, crtc, encoder)
> >                 encoder->disable(encoder);
> >
> > @@ -4235,6 +4265,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
> >
> >         intel_crtc->active = false;
> >
> > +       /*
> > +        * Potentially let some other pipe use the
> > +        * full FIFO, and re-enable LP1+ watermarks.
> > +        */
> > +       ilk_wm_pipe_post_disable(intel_crtc);
> > +
> >         mutex_lock(&dev->struct_mutex);
> >         intel_update_fbc(dev);
> >         intel_edp_psr_update(dev);
> > @@ -4255,6 +4291,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
> >
> >         intel_crtc_disable_planes(crtc);
> >
> > +       /* Make sure other pipes are prepared for FIFO resizing */
> > +       ilk_prepare_for_num_pipes_change(intel_crtc);
> > +
> >         for_each_encoder_on_crtc(dev, crtc, encoder) {
> >                 intel_opregion_notify_encoder(encoder, false);
> >                 encoder->disable(encoder);
> > @@ -4282,6 +4321,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
> >
> >         intel_crtc->active = false;
> >
> > +       /*
> > +        * Potentially let some other pipe use the
> > +        * full FIFO, and re-enable LP1+ watermarks.
> > +        */
> > +       ilk_wm_pipe_post_disable(intel_crtc);
> > +
> >         mutex_lock(&dev->struct_mutex);
> >         intel_update_fbc(dev);
> >         intel_edp_psr_update(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 5ad7ad5..98f878f 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1022,6 +1022,8 @@ void intel_program_watermarks_pre(struct intel_crtc *crtc,
> >  void intel_program_watermarks_post(struct intel_crtc *crtc,
> >                                    const struct intel_crtc_wm_config *config);
> >  void ilk_wm_synchronize(struct intel_crtc *crtc);
> > +void ilk_wm_pipe_post_disable(struct intel_crtc *crtc);
> > +bool ilk_disable_lp_wm(struct drm_device *dev);
> >
> >
> >  /* intel_sdvo.c */
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 1c072cd..18ea8b1 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -2765,7 +2765,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
> >         }
> >  }
> >
> > -static bool ilk_disable_lp_wm(struct drm_device *dev)
> > +bool ilk_disable_lp_wm(struct drm_device *dev)
> >  {
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> >         bool changed;
> > @@ -2873,16 +2873,17 @@ static void ilk_program_watermarks(struct drm_device *dev)
> >         ilk_write_wm_values(dev_priv, &results);
> >  }
> >
> > -static void ilk_update_watermarks(struct drm_device *dev)
> > +static void ilk_update_watermarks(struct drm_device *dev, bool force)
> >  {
> >         bool changed;
> >
> >         changed = ilk_refresh_pending_watermarks(dev);
> >
> > -       if (changed)
> > +       if (changed || force)
> >                 ilk_program_watermarks(dev);
> >  }
> >
> > +/* Prepare the pipe to update the its watermarks on the next vblank */
> >  static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
> >                                          const struct intel_pipe_wm *pipe_wm,
> >                                          u32 vbl_count)
> > @@ -2905,7 +2906,7 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
> >         spin_unlock_irq(&crtc->wm.lock);
> >
> >         /* try to update immediately */
> > -       ilk_update_watermarks(dev);
> > +       ilk_update_watermarks(dev, false);
> >
> >         spin_lock_irq(&crtc->wm.lock);
> >
> > @@ -2999,7 +3000,7 @@ static void ilk_watermark_work(struct work_struct *work)
> >
> >         mutex_lock(&dev_priv->wm.mutex);
> >
> > -       ilk_update_watermarks(dev_priv->dev);
> > +       ilk_update_watermarks(dev_priv->dev, false);
> >
> >         mutex_unlock(&dev_priv->wm.mutex);
> >  }
> > @@ -3060,6 +3061,42 @@ void ilk_wm_synchronize(struct intel_crtc *crtc)
> >         mutex_unlock(&dev_priv->wm.mutex);
> >  }
> >
> > +void ilk_wm_pipe_post_disable(struct intel_crtc *crtc)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > +       struct ilk_pipe_wm_parameters params = {};
> > +       struct intel_pipe_wm pipe_wm = {};
> > +
> > +       WARN(crtc->active, "pipe %c should be disabled\n",
> > +            pipe_name(crtc->pipe));
> > +
> > +       ilk_compute_wm_parameters(&crtc->base, &params);
> > +
> > +       intel_compute_pipe_wm(&crtc->base, &params, &pipe_wm);
> > +
> > +       mutex_lock(&dev_priv->wm.mutex);
> > +
> > +       spin_lock_irq(&crtc->wm.lock);
> > +
> > +       WARN(crtc->wm.dirty, "pipe %c disabled with dirty watermarks\n",
> > +            pipe_name(crtc->pipe));
> > +
> > +       /* clean up if something is left behind */
> > +       ilk_wm_cancel(crtc);
> > +
> > +       spin_unlock_irq(&crtc->wm.lock);
> > +
> > +       crtc->wm.active = pipe_wm;
> > +
> > +       /* pending update (if any) got cancelled */
> > +       crtc->wm.pending = crtc->wm.active;
> > +
> > +       ilk_update_watermarks(dev, true);
> > +
> > +       mutex_unlock(&dev_priv->wm.mutex);
> > +}
> > +
> >  static int ilk_update_primary_wm(struct intel_crtc *crtc,
> >                                  struct intel_crtc_wm_config *config)
> >  {
> > --
> > 1.8.5.5
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps
  2014-06-04 16:22     ` Daniel Vetter
@ 2014-06-09 17:03       ` Ville Syrjälä
  2014-06-10 11:46         ` Jani Nikula
  0 siblings, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-09 17:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 04, 2014 at 06:22:13PM +0200, Daniel Vetter wrote:
> On Tue, Jun 03, 2014 at 05:51:01PM -0300, Paulo Zanoni wrote:
> > 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >
> > > We need to perform watermark programming before and after changing the
> > > plane configuration. Add two new vfuncs to do that. The pre phase is
> > > supposed to switch over to the intermediate watermarks which are
> > > computed so that they can deal with both the old and new plane
> > > configurations. The post phase will arm the vblank based update
> > > systems to switch over to the optimal target watermarks after the
> > > plane configuration has for sure changed.
> > >
> > > v2: Pass around intel_crtc and s/intel_crtc/crtc/
> > >
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/i915_drv.h  |  5 +++
> > >  drivers/gpu/drm/i915/intel_drv.h | 11 +++++
> > >  drivers/gpu/drm/i915/intel_pm.c  | 88 ++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 104 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > > index c90d5ac..d4f8ae8 100644
> > > --- a/drivers/gpu/drm/i915/i915_drv.h
> > > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > > @@ -407,6 +407,7 @@ struct intel_plane_config;
> > >  struct intel_crtc;
> > >  struct intel_limit;
> > >  struct dpll;
> > > +struct intel_crtc_wm_config;
> > >
> > >  struct drm_i915_display_funcs {
> > >         bool (*fbc_enabled)(struct drm_device *dev);
> > > @@ -437,6 +438,10 @@ struct drm_i915_display_funcs {
> > >                                  struct drm_crtc *crtc,
> > >                                  uint32_t sprite_width, int pixel_size,
> > >                                  bool enable, bool scaled);
> > > +       void (*program_wm_pre)(struct intel_crtc *crtc,
> > > +                              const struct intel_crtc_wm_config *config);
> > > +       void (*program_wm_post)(struct intel_crtc *crtc,
> > > +                               const struct intel_crtc_wm_config *config);
> > >         void (*modeset_global_resources)(struct drm_device *dev);
> > >         /* Returns the active state of the crtc, and if the crtc is active,
> > >          * fills out the pipe-config with the hw state. */
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > index 72f01b1..4b59be3 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -358,6 +358,13 @@ struct intel_pipe_wm {
> > >         bool sprites_scaled;
> > >  };
> > >
> > > +struct intel_crtc_wm_config {
> > > +       /* target watermarks for the pipe */
> > > +       struct intel_pipe_wm target;
> > > +       /* intermediate watermarks for pending/active->target transition */
> > > +       struct intel_pipe_wm intm;
> > 
> > It seems you always prefer shorter names such as "intm", and I usually
> > prefer the longer ones like "intermediate". Looks like this is a
> > common topic for my bikesheddings on your patches. When I read "intm"
> > my brain parses it as "Int M" and then aborts execution =P
> 
> I agree with Paulo here. Some other name suggestion (since intermediate is
> so long): transition/transit, merged, pending, ...

The two good names I could think of "intermediate" and "transitional"
are both really long. I agree that "intm" is a horrible shorthand,
but I couldn't come up with anything half sane and still reasonably
short.

"merged" and "pending" already appear in the code with different
meaning, so I'd rather not confuse the matter by reusing those.
"transition" seems OK to me, though not that short either.
"transit" brings up wrong kinds of images in my brain so i don't
really like it.

> -Daniel
> 
> > 
> > With or without that changed: Reviewed-by: Paulo Zanoni
> > <paulo.r.zanoni@intel.com>
> > 
> > > +};
> > > +
> > >  struct intel_crtc {
> > >         struct drm_crtc base;
> > >         enum pipe pipe;
> > > @@ -1001,6 +1008,10 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
> > >  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
> > >  void ilk_wm_get_hw_state(struct drm_device *dev);
> > >  void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
> > > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> > > +                                 const struct intel_crtc_wm_config *config);
> > > +void intel_program_watermarks_post(struct intel_crtc *crtc,
> > > +                                  const struct intel_crtc_wm_config *config);
> > >
> > >
> > >  /* intel_sdvo.c */
> > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > > index 6fc6416..ccf920a 100644
> > > --- a/drivers/gpu/drm/i915/intel_pm.c
> > > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > > @@ -2950,6 +2950,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
> > >         spin_unlock(&crtc->wm.lock);
> > >  }
> > >
> > > +static void ilk_wm_cancel(struct intel_crtc *crtc)
> > > +{
> > > +       struct drm_device *dev = crtc->base.dev;
> > > +
> > > +       assert_spin_locked(&crtc->wm.lock);
> > > +
> > > +       crtc->wm.dirty = false;
> > > +
> > > +       if (crtc->wm.vblank) {
> > > +               drm_vblank_put(dev, crtc->pipe);
> > > +               crtc->wm.vblank = false;
> > > +       }
> > > +}
> > > +
> > >  static void ilk_update_sprite_wm(struct drm_plane *plane,
> > >                                      struct drm_crtc *crtc,
> > >                                      uint32_t sprite_width, int pixel_size,
> > > @@ -3084,6 +3098,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
> > >                                                    pixel_size, enabled, scaled);
> > >  }
> > >
> > > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
> > > +                                 const struct intel_crtc_wm_config *config)
> > > +{
> > > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > > +
> > > +       if (dev_priv->display.program_wm_pre)
> > > +               dev_priv->display.program_wm_pre(crtc, config);
> > > +}
> > > +
> > > +void intel_program_watermarks_post(struct intel_crtc *crtc,
> > > +                                  const struct intel_crtc_wm_config *config)
> > > +{
> > > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > > +
> > > +       if (dev_priv->display.program_wm_post)
> > > +               dev_priv->display.program_wm_post(crtc, config);
> > > +}
> > > +
> > >  static struct drm_i915_gem_object *
> > >  intel_alloc_context_page(struct drm_device *dev)
> > >  {
> > > @@ -6522,6 +6554,60 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
> > >         pm_runtime_disable(device);
> > >  }
> > >
> > > +static void ilk_program_wm_pre(struct intel_crtc *crtc,
> > > +                              const struct intel_crtc_wm_config *config)
> > > +{
> > > +       struct drm_device *dev = crtc->base.dev;
> > > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > > +
> > > +       mutex_lock(&dev_priv->wm.mutex);
> > > +
> > > +       spin_lock_irq(&crtc->wm.lock);
> > > +       ilk_wm_cancel(crtc);
> > > +       spin_unlock_irq(&crtc->wm.lock);
> > > +
> > > +       /* pending update (if any) got cancelled */
> > > +       crtc->wm.pending = crtc->wm.active;
> > > +
> > > +       if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
> > > +               goto unlock;
> > > +
> > > +       crtc->wm.active = config->intm;
> > > +
> > > +       /* use the most up to date watermarks for other pipes */
> > > +       ilk_refresh_pending_watermarks(dev);
> > > +
> > > +       /* switch over to the intermediate watermarks */
> > > +       ilk_program_watermarks(dev);
> > > +
> > > + unlock:
> > > +       mutex_unlock(&dev_priv->wm.mutex);
> > > +}
> > > +
> > > +static void ilk_program_wm_post(struct intel_crtc *crtc,
> > > +                               const struct intel_crtc_wm_config *config)
> > > +{
> > > +       struct drm_device *dev = crtc->base.dev;
> > > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > > +       u32 vbl_count;
> > > +
> > > +       /*
> > > +        * FIXME sample this inside the atomic section to avoid
> > > +        * needlessly long periods w/ sub-par watermarks
> > > +        */
> > > +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
> > > +
> > > +       mutex_lock(&dev_priv->wm.mutex);
> > > +
> > > +       /*
> > > +        * We can switch over to the target
> > > +        * watermarks after the next vblank.
> > > +        */
> > > +       ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
> > > +
> > > +       mutex_unlock(&dev_priv->wm.mutex);
> > > +}
> > > +
> > >  /* Set up chip specific power management-related functions */
> > >  void intel_init_pm(struct drm_device *dev)
> > >  {
> > > @@ -6569,6 +6655,8 @@ void intel_init_pm(struct drm_device *dev)
> > >                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
> > >                         dev_priv->display.update_wm = ilk_update_wm;
> > >                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> > > +                       dev_priv->display.program_wm_pre = ilk_program_wm_pre;
> > > +                       dev_priv->display.program_wm_post = ilk_program_wm_post;
> > >                 } else {
> > >                         DRM_DEBUG_KMS("Failed to read display plane latency. "
> > >                                       "Disable CxSR\n");
> > > --
> > > 1.8.5.5
> > >
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 
> > 
> > 
> > -- 
> > Paulo Zanoni
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases
  2014-06-03 22:47   ` Paulo Zanoni
@ 2014-06-09 18:28     ` Ville Syrjälä
  0 siblings, 0 replies; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-09 18:28 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Tue, Jun 03, 2014 at 07:47:11PM -0300, Paulo Zanoni wrote:
> 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > Switch the code over to using the two phase watermark update. The steps
> > generally follow this pattern:
> >
> > 1. Calculate new plane parameters for changed planes
> > 2. Calculate new target and intermediate watermarks
> > 3. Check that both the target and intermediate watermarks are valid
> > 4. Program the hardware with the intermediate watermarks
> > 5. Program the plane registers
> > 6. Arm the vblank watermark update machinery for the next vblank
> > 7. Program the hardware with the target watermarks (after vblank)
> >
> > v2: Rebased, pass intel_crtc around, s/intel_crtc/crtc/
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> This patch is huge. If we bisect any regression to it, we will be
> completely lost and hopeless. Also, my tiny little brain doesn't have
> enough power to do a proper review of this patch with so many changes
> happening all at the same place. I tried, but I gave up in the middle.
> 
> Please try to convert this patch into many smaller patches. I don't
> know if the following idea is actually possible, but it is what I
> could extract from what I read of your patch:
> - I'd start with the way you update watermarks parameters. Start by
> patching ilk_compute_wm_parameters() and making it directly call your
> new update_xxx_params() functions. You can even do separate patches
> for _pri, _cur and _spr patches since it seems the _spr code is
> different for most of your patch due to the old
> intel_update_sprite_watermarks() function.
> - Then you change the way you use to set your parameters (there's a
> comment below mentioning the specific line which I'm talking about
> here)
> - Then you can patch intel_display.c so you will only update the WM
> params when you actually change the HW (the _hw_plane and
> update_cursor functions). Again, you can even split _pri, _cur and
> _spr on separate patches.
> - Then you can introduce the update_cursor_wm() and
> update_primary_wm() functions, but still make them call the old-style
> intel_update_watermarks() or something similar.
> - You can also add the functions to deal with intermediate watermarks,
> but without using them. Or you could, for example, make the
> intermediate watermarks just be the same as the "old" ones, so the
> only real update will be the final one (which, I believe, will mean
> the code still behaves as it does today, no regressions).
> - Then you can add the final piece of the code that uses all the new
> infrastructure to actually generate and use the intermediate
> watermarks. And this would be a much smaller patch.

I guess I can try to chunk it up more. But in that case I'll have to
make all the intermediate stages as impotent as possible since no one
will be testing them. So I fear it's going to be more patches that
essentially do nothing.

> 
> There are still some comments below:
> 
> > ---
> >  drivers/gpu/drm/i915/i915_drv.h      |  14 ++-
> >  drivers/gpu/drm/i915/intel_display.c |  58 ++++++++-
> >  drivers/gpu/drm/i915/intel_drv.h     |  35 ++++--
> >  drivers/gpu/drm/i915/intel_pm.c      | 229 +++++++++++++++++++++++++++--------
> >  drivers/gpu/drm/i915/intel_sprite.c  | 119 ++++++++++++------
> >  5 files changed, 347 insertions(+), 108 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index d4f8ae8..5b1404e 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -405,9 +405,12 @@ struct intel_connector;
> >  struct intel_crtc_config;
> >  struct intel_plane_config;
> >  struct intel_crtc;
> > +struct intel_plane;
> >  struct intel_limit;
> >  struct dpll;
> >  struct intel_crtc_wm_config;
> > +struct intel_plane_wm_parameters;
> > +struct intel_crtc_wm_config;
> >
> >  struct drm_i915_display_funcs {
> >         bool (*fbc_enabled)(struct drm_device *dev);
> > @@ -434,10 +437,13 @@ struct drm_i915_display_funcs {
> >                           struct dpll *match_clock,
> >                           struct dpll *best_clock);
> >         void (*update_wm)(struct drm_crtc *crtc);
> > -       void (*update_sprite_wm)(struct drm_plane *plane,
> > -                                struct drm_crtc *crtc,
> > -                                uint32_t sprite_width, int pixel_size,
> > -                                bool enable, bool scaled);
> > +       int (*update_primary_wm)(struct intel_crtc *crtc,
> > +                                struct intel_crtc_wm_config *config);
> > +       int (*update_cursor_wm)(struct intel_crtc *crtc,
> > +                               struct intel_crtc_wm_config *config);
> > +       int (*update_sprite_wm)(struct intel_plane *plane,
> > +                               struct intel_crtc *crtc,
> > +                               struct intel_crtc_wm_config *config);
> >         void (*program_wm_pre)(struct intel_crtc *crtc,
> >                                const struct intel_crtc_wm_config *config);
> >         void (*program_wm_post)(struct intel_crtc *crtc,
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 408b238..5bf1633 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -2078,6 +2078,19 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
> >         POSTING_READ(reg);
> >  }
> >
> > +static void update_pri_params(struct intel_crtc *crtc,
> > +                             struct intel_plane_wm_parameters *params,
> > +                             bool primary_enabled)
> > +{
> > +       if (!crtc->active || !primary_enabled)
> > +               return;
> > +
> > +       params->horiz_pixels = crtc->config.pipe_src_w;
> > +       params->bytes_per_pixel =
> > +               drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
> > +       params->enabled = true;
> > +}
> 
> You add two copies of this function, one here and one at the very end.

Yeah seems I was lazy and copy pasted the thing to the sprite code.
I'll need to give it a proper name and make it non static.

> 
> Also, the params->bytes_per_pixel used here is different from the one
> originally used at ilk_compute_wm_parameters(). This should be on a
> separate patch with a nice explanation of the differences between
> both.
> 
> > +
> >  /**
> >   * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
> >   * @dev_priv: i915 private structure
> > @@ -2091,6 +2104,8 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
> >  {
> >         struct intel_crtc *intel_crtc =
> >                 to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> > +       struct intel_crtc_wm_config config = {};
> 
> These temporary structs that get created an assigned really bother me,
> especially in these cases where we are just interested in a sub-field
> of the struct. This probably suggests there is something wrong with
> our abstractions. After all this work is merged, we should probably
> try to get rid of these things.

I think many of the temp structs are an artifact of not having a
plane_config struct or nuclear flip. Once we get those the mess
should hopefully clear a bit.

> 
> 
> > +       int ret;
> >         int reg;
> >         u32 val;
> >
> > @@ -2100,14 +2115,24 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
> >         if (intel_crtc->primary_enabled)
> >                 return;
> >
> > +       update_pri_params(intel_crtc, &config.pri, true);
> > +
> > +       ret = intel_update_primary_watermarks(intel_crtc, &config);
> > +       WARN(ret, "primary watermarks invalid\n");
> > +
> >         intel_crtc->primary_enabled = true;
> >
> >         reg = DSPCNTR(plane);
> >         val = I915_READ(reg);
> >         WARN_ON(val & DISPLAY_PLANE_ENABLE);
> >
> > +       intel_crtc->pri_wm = config.pri;
> > +       intel_program_watermarks_pre(intel_crtc, &config);
> > +
> >         I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
> >         intel_flush_primary_plane(dev_priv, plane);
> > +
> > +       intel_program_watermarks_post(intel_crtc, &config);
> >  }
> >
> >  /**
> > @@ -2123,20 +2148,32 @@ static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
> >  {
> >         struct intel_crtc *intel_crtc =
> >                 to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> > +       struct intel_crtc_wm_config config = {};
> > +       int ret;
> >         int reg;
> >         u32 val;
> >
> >         if (!intel_crtc->primary_enabled)
> >                 return;
> >
> > +       update_pri_params(intel_crtc, &config.pri, false);
> > +
> > +       ret = intel_update_primary_watermarks(intel_crtc, &config);
> > +       WARN(ret, "primary watermarks invalid\n");
> > +
> >         intel_crtc->primary_enabled = false;
> >
> >         reg = DSPCNTR(plane);
> >         val = I915_READ(reg);
> >         WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0);
> >
> > +       intel_crtc->pri_wm = config.pri;
> > +       intel_program_watermarks_pre(intel_crtc, &config);
> > +
> >         I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
> >         intel_flush_primary_plane(dev_priv, plane);
> > +
> > +       intel_program_watermarks_post(intel_crtc, &config);
> >  }
> >
> >  static bool need_vtd_wa(struct drm_device *dev)
> > @@ -3989,7 +4026,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
> >          */
> >         intel_crtc_load_lut(crtc);
> >
> > -       intel_update_watermarks(crtc);
> >         intel_enable_pipe(intel_crtc);
> >
> >         if (intel_crtc->config.has_pch_encoder)
> > @@ -4100,7 +4136,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
> >         intel_ddi_set_pipe_settings(crtc);
> >         intel_ddi_enable_transcoder_func(crtc);
> >
> > -       intel_update_watermarks(crtc);
> >         intel_enable_pipe(intel_crtc);
> >
> >         if (intel_crtc->config.has_pch_encoder)
> > @@ -4188,7 +4223,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
> >         }
> >
> >         intel_crtc->active = false;
> > -       intel_update_watermarks(crtc);
> >
> >         mutex_lock(&dev->struct_mutex);
> >         intel_update_fbc(dev);
> > @@ -4236,7 +4270,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
> >         }
> >
> >         intel_crtc->active = false;
> > -       intel_update_watermarks(crtc);
> >
> >         mutex_lock(&dev->struct_mutex);
> >         intel_update_fbc(dev);
> > @@ -7985,11 +8018,13 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >         struct drm_device *dev = crtc->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> >         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > +       struct intel_crtc_wm_config config = {};
> >         int pipe = intel_crtc->pipe;
> >         int x = intel_crtc->cursor_x;
> >         int y = intel_crtc->cursor_y;
> >         u32 base = 0, pos = 0;
> >         bool visible;
> > +       int ret;
> >
> >         if (on)
> >                 base = intel_crtc->cursor_addr;
> > @@ -8022,6 +8057,19 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >         if (!visible && !intel_crtc->cursor_visible)
> >                 return;
> >
> > +       if (visible) {
> > +               /* FIXME should we use the clipped width? */
> > +               config.cur.horiz_pixels = intel_crtc->cursor_width;
> > +               config.cur.bytes_per_pixel = 4;
> > +               config.cur.enabled = true;
> > +       }
> > +
> > +       ret = intel_update_cursor_watermarks(intel_crtc, &config);
> > +       WARN(ret, "cursor watermarks invalid\n");
> > +
> > +       intel_crtc->cur_wm = config.cur;
> > +       intel_program_watermarks_pre(intel_crtc, &config);
> > +
> >         I915_WRITE(CURPOS(pipe), pos);
> >
> >         if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
> > @@ -8030,6 +8078,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
> >                 i845_update_cursor(crtc, base);
> >         else
> >                 i9xx_update_cursor(crtc, base);
> > +
> > +       intel_program_watermarks_post(intel_crtc, &config);
> >  }
> >
> >  static int intel_crtc_cursor_set(struct drm_crtc *crtc,
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 4b59be3..1ec4379 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -358,7 +358,15 @@ struct intel_pipe_wm {
> >         bool sprites_scaled;
> >  };
> >
> > +struct intel_plane_wm_parameters {
> > +       uint32_t horiz_pixels;
> > +       uint8_t bytes_per_pixel;
> > +       bool enabled;
> > +       bool scaled;
> > +};
> > +
> >  struct intel_crtc_wm_config {
> > +       struct intel_plane_wm_parameters pri, spr, cur;
> >         /* target watermarks for the pipe */
> >         struct intel_pipe_wm target;
> >         /* intermediate watermarks for pending/active->target transition */
> > @@ -444,18 +452,14 @@ struct intel_crtc {
> >                 spinlock_t lock;
> >         } wm;
> >
> > +       struct intel_plane_wm_parameters pri_wm;
> > +       struct intel_plane_wm_parameters cur_wm;
> 
> Why isn't this inside "struct wm"?

Eventually these should migrate to plane_config, so I like them sticking
out a bit in the meantime.

> 
> Also please add _params to the name. Every new patch adds a different
> WM struct with a similar name, I am confused.
> 
> > +
> >         wait_queue_head_t vbl_wait;
> >
> >         int scanline_offset;
> >  };
> >
> > -struct intel_plane_wm_parameters {
> > -       uint32_t horiz_pixels;
> > -       uint8_t bytes_per_pixel;
> > -       bool enabled;
> > -       bool scaled;
> > -};
> > -
> >  struct intel_plane {
> >         struct drm_plane base;
> >         int plane;
> > @@ -483,9 +487,11 @@ struct intel_plane {
> >                              int crtc_x, int crtc_y,
> >                              unsigned int crtc_w, unsigned int crtc_h,
> >                              uint32_t x, uint32_t y,
> > -                            uint32_t src_w, uint32_t src_h);
> > +                            uint32_t src_w, uint32_t src_h,
> > +                            const struct intel_crtc_wm_config *config);
> >         void (*disable_plane)(struct drm_plane *plane,
> > -                             struct drm_crtc *crtc);
> > +                             struct drm_crtc *crtc,
> > +                             const struct intel_crtc_wm_config *config);
> >         int (*update_colorkey)(struct drm_plane *plane,
> >                                struct drm_intel_sprite_colorkey *key);
> >         void (*get_colorkey)(struct drm_plane *plane,
> > @@ -969,10 +975,13 @@ void intel_init_clock_gating(struct drm_device *dev);
> >  void intel_suspend_hw(struct drm_device *dev);
> >  int ilk_wm_max_level(const struct drm_device *dev);
> >  void intel_update_watermarks(struct drm_crtc *crtc);
> > -void intel_update_sprite_watermarks(struct drm_plane *plane,
> > -                                   struct drm_crtc *crtc,
> > -                                   uint32_t sprite_width, int pixel_size,
> > -                                   bool enabled, bool scaled);
> > +int intel_update_cursor_watermarks(struct intel_crtc *crtc,
> > +                                  struct intel_crtc_wm_config *config);
> > +int intel_update_primary_watermarks(struct intel_crtc *crtc,
> > +                                  struct intel_crtc_wm_config *config);
> > +int intel_update_sprite_watermarks(struct intel_plane *plane,
> > +                                  struct intel_crtc *crtc,
> > +                                  struct intel_crtc_wm_config *config);
> >  void intel_init_pm(struct drm_device *dev);
> >  void intel_pm_setup(struct drm_device *dev);
> >  bool intel_fbc_enabled(struct drm_device *dev);
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index ccf920a..13366b7 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -2186,13 +2186,9 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
> >         p->active = true;
> >         p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
> >         p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> > -       p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
> > -       p->cur.bytes_per_pixel = 4;
> > -       p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
> > -       p->cur.horiz_pixels = intel_crtc->cursor_width;
> > -       /* TODO: for now, assume primary and cursor planes are always enabled. */
> > -       p->pri.enabled = true;
> > -       p->cur.enabled = true;
> > +
> > +       p->pri = intel_crtc->pri_wm;
> > +       p->cur = intel_crtc->cur_wm;
> >
> >         drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
> >                 struct intel_plane *intel_plane = to_intel_plane(plane);
> > @@ -2292,6 +2288,35 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
> >  }
> >
> >  /*
> > + * Merge two pipe watermark sets.
> > + * Used for computing intermediate watermark levels
> > + * for transitioning between two different configurations.
> > + */
> > +static void ilk_wm_merge_intermediate(struct drm_device *dev,
> > +                                     struct intel_pipe_wm *a,
> > +                                     const struct intel_pipe_wm *b)
> > +{
> > +       int level, max_level = ilk_wm_max_level(dev);
> > +
> > +       a->pipe_enabled |= b->pipe_enabled;
> > +       a->sprites_enabled |= b->sprites_enabled;
> > +       a->sprites_scaled |= b->sprites_scaled;
> > +
> > +       /* Merge _all_ levels including 0 */
> > +       for (level = 0; level <= max_level; level++) {
> > +               struct intel_wm_level *a_wm = &a->wm[level];
> > +               const struct intel_wm_level *b_wm = &b->wm[level];
> > +
> > +               a_wm->enable &= b_wm->enable;
> > +
> > +               a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
> > +               a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
> > +               a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
> > +               a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
> > +       }
> > +}
> 
> Maybe this question don't make much sense, but:
> - What if A was WM calculated with one type of paritioning and/or FBC
> enabled, while B was calculated with the other partitioning and/or FBC
> disabled? Can't we reach a case where the watermarks generated by this
> function are insufficient (due to fbc/partitioning/etc) or don't even
> make sense (values we would never generate with the current BSpec
> algorithms)?

This just merges the target/pending/active watermarks for a single pipe,
which don't yet have any notion of fbc or FIFO splits (apart from
primary vs. sprite). The only things we know about those watermarks is
that the values fit in the registers, and that the first level has been
deemed valid.

> 
> 
> > +
> > +/*
> >   * Merge the watermarks from all active pipes for a specific level.
> >   */
> >  static void ilk_merge_wm_level(struct drm_device *dev,
> > @@ -2844,31 +2869,6 @@ static void ilk_program_watermarks(struct drm_device *dev)
> >         ilk_write_wm_values(dev_priv, &results);
> >  }
> >
> > -static void ilk_update_wm(struct drm_crtc *crtc)
> > -{
> > -       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -       struct drm_device *dev = crtc->dev;
> > -       struct drm_i915_private *dev_priv = dev->dev_private;
> > -       struct ilk_pipe_wm_parameters params = {};
> > -       struct intel_pipe_wm pipe_wm = {};
> > -
> > -       ilk_compute_wm_parameters(crtc, &params);
> > -
> > -       intel_compute_pipe_wm(crtc, &params, &pipe_wm);
> > -
> > -       mutex_lock(&dev_priv->wm.mutex);
> > -
> > -       if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
> > -               goto unlock;
> > -
> > -       intel_crtc->wm.active = pipe_wm;
> > -
> > -       ilk_program_watermarks(dev);
> > -
> > - unlock:
> > -       mutex_unlock(&dev_priv->wm.mutex);
> > -}
> > -
> >  static void ilk_update_watermarks(struct drm_device *dev)
> >  {
> >         bool changed;
> > @@ -2923,6 +2923,71 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *crtc,
> >         spin_unlock_irq(&crtc->wm.lock);
> >  }
> >
> > +static int ilk_pipe_compute_watermarks(struct intel_crtc *crtc,
> > +                                      struct intel_pipe_wm *target,
> > +                                      struct intel_pipe_wm *intm)
> > +{
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct drm_i915_private *dev_priv = dev->dev_private;
> > +       struct intel_pipe_wm intm_pending;
> > +       bool dirty;
> > +
> > +       /* are the target watermarks valid at all? */
> > +       if (!ilk_validate_pipe_wm(dev, target))
> > +               return -EINVAL;
> > +
> > +       /*
> > +        * We need to come up with intermediate watermark levels
> > +        * that will support both the old and new plane configuration
> > +        * since we can't flip over to the final watermarks until
> > +        * the plane configuration has been latched at some future vblank.
> > +        *
> > +        * Additionally if there's already an update pending, we can't
> > +        * yet be sure which plane configuration will be active at the
> > +        * time we apply the intermediate watermarks, so we must account
> > +        * for both possibilities.
> > +        */
> > +       mutex_lock(&dev_priv->wm.mutex);
> > +
> > +       intm_pending = crtc->wm.pending;
> > +       *intm = crtc->wm.active;
> > +
> > +       spin_lock_irq(&crtc->wm.lock);
> > +       dirty = crtc->wm.dirty;
> > +       spin_unlock_irq(&crtc->wm.lock);
> > +
> > +       mutex_unlock(&dev_priv->wm.mutex);
> > +
> > +       /*
> > +        * If the intermediate watermarks aren't valid, we must tell the user to
> > +        * try something a bit different. There are two cases to be considered.
> > +        * 1) there is no pending update:
> > +        *    If the intermediate watermarks for transitioning from the currently
> > +        *    active configuration to the new configuration aren't valid, the
> > +        *    user must choose another configuration as there is no safe way to
> > +        *    transition from the currently active config to the new config.
> 
> Why/how would this happen?

Eg. if there's currently just the primary plane enabled which requires
more than 50% of the LP0 FIFO space available for one pipe, and then
the user wants enable a sprite and disable the primary. Or vice versa.

active: fifo=128 pri=80 spr=0
target: fifo=128 pri=0 spr=40
intermediate: fifo=128 pri=80 spr=40 -> no can do (80>64)

Hmm. Although now I think about it again I guess it shouldn't actually
matter since the FIFO split is automagically changed by the hardware
when the sprite gets enabled. So oversubscribing the intermediate
watermarks like that should be fine. The hardware itself won't be
doing anything wrong as long as the planes go on+off at the same
vblank. But I'd need to revisit the watermark validation code to accept
such configurations, and would need to think a bit more more in case
there is some other scenario that could hit such issues.

Also there is definitely something fishy happening with primary<->sprite
changes. The screen tends to flash black without underruns getting
reported. But IIRC it might be somehow related to the colorkey as well.
I should poke at the hardware again a bit at some point and try to get
to the bottom of this.

> 
> In the worst case, the intermediate watermarks would just disable all
> the LP WMs, go back to 1/2 partitioning, disable FBC, and use the
> maximum register values for level 0. Anything that needs more than
> that is an unsupported mode. By the way, we could get completely rid
> of these intermediate WM calculations if we just used these maximum
> values as the intermediate ones: of course, they would be less
> power-efficient than your current code, but maybe the difference
> wouldn't be noticeable.

Computing the intermediate values is the easy part here, so I don't see
much point in not doing it. Saving power is good.

> 
> Thanks,
> Paulo
> 
> > +        * 2) there is a pending update:
> > +        *    If the intermediate watermarks for transitioning from the ccurrently
> > +        *    pending configuration to the new configuration are valid, we can
> > +        *    simply tell the user to try again after a while.
> > +        */
> > +       if (dirty) {
> > +               ilk_wm_merge_intermediate(dev, &intm_pending, target);
> > +               if (!ilk_validate_pipe_wm(dev, &intm_pending))
> > +                       return -EINVAL;
> > +
> > +               ilk_wm_merge_intermediate(dev, intm, &intm_pending);
> > +               if (!ilk_validate_pipe_wm(dev, intm))
> > +                       return -EAGAIN;
> > +       } else {
> > +               ilk_wm_merge_intermediate(dev, intm, target);
> > +               if (!ilk_validate_pipe_wm(dev, intm))
> > +                       return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static void ilk_watermark_work(struct work_struct *work)
> >  {
> >         struct drm_i915_private *dev_priv =
> > @@ -2964,18 +3029,46 @@ static void ilk_wm_cancel(struct intel_crtc *crtc)
> >         }
> >  }
> >
> > -static void ilk_update_sprite_wm(struct drm_plane *plane,
> > -                                    struct drm_crtc *crtc,
> > -                                    uint32_t sprite_width, int pixel_size,
> > -                                    bool enabled, bool scaled)
> > +static int ilk_update_primary_wm(struct intel_crtc *crtc,
> > +                                struct intel_crtc_wm_config *config)
> > +{
> > +       struct ilk_pipe_wm_parameters params = {};
> > +
> > +       ilk_compute_wm_parameters(&crtc->base, &params);
> > +
> > +       params.pri = config->pri;
> > +
> > +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
> > +
> > +       return ilk_pipe_compute_watermarks(crtc,
> > +                                          &config->target,
> > +                                          &config->intm);
> > +}
> > +
> > +static int ilk_update_cursor_wm(struct intel_crtc *crtc,
> > +                               struct intel_crtc_wm_config *config)
> > +{
> > +       struct ilk_pipe_wm_parameters params = {};
> > +
> > +       ilk_compute_wm_parameters(&crtc->base, &params);
> > +
> > +       params.cur = config->cur;
> > +
> > +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
> > +
> > +       return ilk_pipe_compute_watermarks(crtc,
> > +                                          &config->target,
> > +                                          &config->intm);
> > +}
> > +
> > +static int ilk_update_sprite_wm(struct intel_plane *plane,
> > +                               struct intel_crtc *crtc,
> > +                               struct intel_crtc_wm_config *config)
> >  {
> > -       struct drm_device *dev = plane->dev;
> > -       struct intel_plane *intel_plane = to_intel_plane(plane);
> > +       struct drm_device *dev = crtc->base.dev;
> > +       struct ilk_pipe_wm_parameters params = {};
> >
> > -       intel_plane->wm.enabled = enabled;
> > -       intel_plane->wm.scaled = scaled;
> > -       intel_plane->wm.horiz_pixels = sprite_width;
> > -       intel_plane->wm.bytes_per_pixel = pixel_size;
> > +       ilk_compute_wm_parameters(&crtc->base, &params);
> >
> >         /*
> >          * IVB workaround: must disable low power watermarks for at least
> > @@ -2984,10 +3077,17 @@ static void ilk_update_sprite_wm(struct drm_plane *plane,
> >          *
> >          * WaCxSRDisabledForSpriteScaling:ivb
> >          */
> > -       if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
> > -               intel_wait_for_vblank(dev, intel_plane->pipe);
> > +       if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
> > +               intel_wait_for_vblank(dev, plane->pipe);
> > +
> > +       params.pri = config->pri;
> > +       params.spr = config->spr;
> > +
> > +       intel_compute_pipe_wm(&crtc->base, &params, &config->target);
> >
> > -       ilk_update_wm(crtc);
> > +       return ilk_pipe_compute_watermarks(crtc,
> > +                                          &config->target,
> > +                                          &config->intm);
> >  }
> >
> >  static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
> > @@ -3086,16 +3186,38 @@ void intel_update_watermarks(struct drm_crtc *crtc)
> >                 dev_priv->display.update_wm(crtc);
> >  }
> >
> > -void intel_update_sprite_watermarks(struct drm_plane *plane,
> > -                                   struct drm_crtc *crtc,
> > -                                   uint32_t sprite_width, int pixel_size,
> > -                                   bool enabled, bool scaled)
> > +int intel_update_primary_watermarks(struct intel_crtc *crtc,
> > +                                   struct intel_crtc_wm_config *config)
> >  {
> > -       struct drm_i915_private *dev_priv = plane->dev->dev_private;
> > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +
> > +       if (dev_priv->display.update_primary_wm)
> > +               return dev_priv->display.update_primary_wm(crtc, config);
> > +
> > +       return 0;
> > +}
> > +
> > +int intel_update_cursor_watermarks(struct intel_crtc *crtc,
> > +                                  struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +
> > +       if (dev_priv->display.update_cursor_wm)
> > +               return dev_priv->display.update_cursor_wm(crtc, config);
> > +
> > +       return 0;
> > +}
> > +
> > +int intel_update_sprite_watermarks(struct intel_plane *plane,
> > +                                  struct intel_crtc *crtc,
> > +                                  struct intel_crtc_wm_config *config)
> > +{
> > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> >
> >         if (dev_priv->display.update_sprite_wm)
> > -               dev_priv->display.update_sprite_wm(plane, crtc, sprite_width,
> > -                                                  pixel_size, enabled, scaled);
> > +               return dev_priv->display.update_sprite_wm(plane, crtc, config);
> > +
> > +       return 0;
> >  }
> >
> >  void intel_program_watermarks_pre(struct intel_crtc *crtc,
> > @@ -6653,7 +6775,8 @@ void intel_init_pm(struct drm_device *dev)
> >                      dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
> >                     (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
> >                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
> > -                       dev_priv->display.update_wm = ilk_update_wm;
> > +                       dev_priv->display.update_primary_wm = ilk_update_primary_wm;
> > +                       dev_priv->display.update_cursor_wm = ilk_update_cursor_wm;
> >                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> >                         dev_priv->display.program_wm_pre = ilk_program_wm_pre;
> >                         dev_priv->display.program_wm_post = ilk_program_wm_post;
> > diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> > index d6acd6b..c9b1750 100644
> > --- a/drivers/gpu/drm/i915/intel_sprite.c
> > +++ b/drivers/gpu/drm/i915/intel_sprite.c
> > @@ -131,7 +131,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
> >         struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> >         int reg = DSPCNTR(crtc->plane);
> >
> > -       if (crtc->primary_enabled)
> > +       if (crtc->pri_wm.enabled)
> >                 I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
> >         else
> >                 I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
> > @@ -143,7 +143,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> >                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
> >                  unsigned int crtc_w, unsigned int crtc_h,
> >                  uint32_t x, uint32_t y,
> > -                uint32_t src_w, uint32_t src_h)
> > +                uint32_t src_w, uint32_t src_h,
> > +                const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = dplane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -218,9 +219,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> >
> >         sprctl |= SP_ENABLE;
> >
> > -       intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
> > -                                      src_w != crtc_w || src_h != crtc_h);
> > -
> >         /* Sizes are 0 based */
> >         src_w--;
> >         src_h--;
> > @@ -234,6 +232,10 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> >                                                         fb->pitches[0]);
> >         linear_offset -= sprsurf_offset;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -255,10 +257,13 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> >
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> > +
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static void
> > -vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
> > +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
> > +                 const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = dplane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -269,6 +274,10 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
> >         u32 start_vbl_count;
> >         bool atomic_update;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -283,7 +292,7 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> >
> > -       intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static int
> > @@ -343,7 +352,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
> >                  unsigned int crtc_w, unsigned int crtc_h,
> >                  uint32_t x, uint32_t y,
> > -                uint32_t src_w, uint32_t src_h)
> > +                uint32_t src_w, uint32_t src_h,
> > +                const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = plane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -406,9 +416,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >         if (IS_HASWELL(dev) || IS_BROADWELL(dev))
> >                 sprctl |= SPRITE_PIPE_CSC_ENABLE;
> >
> > -       intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
> > -                                      src_w != crtc_w || src_h != crtc_h);
> > -
> >         /* Sizes are 0 based */
> >         src_w--;
> >         src_h--;
> > @@ -424,6 +431,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                                                pixel_size, fb->pitches[0]);
> >         linear_offset -= sprsurf_offset;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -451,10 +462,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> > +
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static void
> > -ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> > +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> > +                 const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = plane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -464,6 +478,10 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> >         u32 start_vbl_count;
> >         bool atomic_update;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -480,13 +498,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> >
> > -       /*
> > -        * Avoid underruns when disabling the sprite.
> > -        * FIXME remove once watermark updates are done properly.
> > -        */
> > -       intel_wait_for_vblank(dev, pipe);
> > -
> > -       intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static int
> > @@ -549,7 +561,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                  struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
> >                  unsigned int crtc_w, unsigned int crtc_h,
> >                  uint32_t x, uint32_t y,
> > -                uint32_t src_w, uint32_t src_h)
> > +                uint32_t src_w, uint32_t src_h,
> > +                const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = plane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -606,9 +619,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                 dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
> >         dvscntr |= DVS_ENABLE;
> >
> > -       intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
> > -                                      src_w != crtc_w || src_h != crtc_h);
> > -
> >         /* Sizes are 0 based */
> >         src_w--;
> >         src_h--;
> > @@ -625,6 +635,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                                                pixel_size, fb->pitches[0]);
> >         linear_offset -= dvssurf_offset;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -647,10 +661,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> > +
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static void
> > -ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> > +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> > +                 const struct intel_crtc_wm_config *config)
> >  {
> >         struct drm_device *dev = plane->dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -660,6 +677,10 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> >         u32 start_vbl_count;
> >         bool atomic_update;
> >
> > +       intel_crtc->pri_wm = config->pri;
> > +       intel_plane->wm = config->spr;
> > +       intel_program_watermarks_pre(intel_crtc, config);
> > +
> >         atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
> >
> >         intel_update_primary_plane(intel_crtc);
> > @@ -675,13 +696,7 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
> >         if (atomic_update)
> >                 intel_pipe_update_end(intel_crtc, start_vbl_count);
> >
> > -       /*
> > -        * Avoid underruns when disabling the sprite.
> > -        * FIXME remove once watermark updates are done properly.
> > -        */
> > -       intel_wait_for_vblank(dev, pipe);
> > -
> > -       intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
> > +       intel_program_watermarks_post(intel_crtc, config);
> >  }
> >
> >  static void
> > @@ -801,6 +816,19 @@ static bool colorkey_enabled(struct intel_plane *intel_plane)
> >         return key.flags != I915_SET_COLORKEY_NONE;
> >  }
> >
> > +static void update_pri_params(struct intel_crtc *crtc,
> > +                             struct intel_plane_wm_parameters *params,
> > +                             bool primary_enabled)
> > +{
> > +       if (!crtc->active || !primary_enabled)
> > +               return;
> > +
> > +       params->horiz_pixels = crtc->config.pipe_src_w;
> > +       params->bytes_per_pixel =
> > +               drm_format_plane_cpp(crtc->base.primary->fb->pixel_format, 0);
> > +       params->enabled = true;
> > +}
> > +
> >  static int
> >  intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                    struct drm_framebuffer *fb, int crtc_x, int crtc_y,
> > @@ -852,6 +880,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                 .src_w = src_w,
> >                 .src_h = src_h,
> >         };
> > +       struct intel_crtc_wm_config config = {};
> >
> >         /* Don't modify another pipe's plane */
> >         if (intel_plane->pipe != intel_crtc->pipe) {
> > @@ -989,6 +1018,19 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >         primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane);
> >         WARN_ON(!primary_enabled && !visible && intel_crtc->active);
> >
> > +       if (visible) {
> > +               config.spr.horiz_pixels = src_w;
> > +               config.spr.bytes_per_pixel = pixel_size;
> > +               config.spr.enabled = true;
> > +               config.spr.scaled = src_w != crtc_w || src_h != crtc_h;
> > +       }
> > +
> > +       update_pri_params(intel_crtc, &config.pri, primary_enabled);
> > +
> > +       ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
> > +       if (ret)
> > +               return ret;
> > +
> >         mutex_lock(&dev->struct_mutex);
> >
> >         /* Note that this will apply the VT-d workaround for scanouts,
> > @@ -1027,9 +1069,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> >                 if (visible)
> >                         intel_plane->update_plane(plane, crtc, fb, obj,
> >                                                   crtc_x, crtc_y, crtc_w, crtc_h,
> > -                                                 src_x, src_y, src_w, src_h);
> > +                                                 src_x, src_y, src_w, src_h,
> > +                                                 &config);
> >                 else
> > -                       intel_plane->disable_plane(plane, crtc);
> > +                       intel_plane->disable_plane(plane, crtc, &config);
> >
> >                 if (!primary_was_enabled && primary_enabled)
> >                         intel_post_enable_primary(crtc);
> > @@ -1060,6 +1103,8 @@ intel_disable_plane(struct drm_plane *plane)
> >         struct drm_device *dev = plane->dev;
> >         struct intel_plane *intel_plane = to_intel_plane(plane);
> >         struct intel_crtc *intel_crtc;
> > +       struct intel_crtc_wm_config config = {};
> > +       int ret;
> >
> >         if (!plane->fb)
> >                 return 0;
> > @@ -1069,12 +1114,18 @@ intel_disable_plane(struct drm_plane *plane)
> >
> >         intel_crtc = to_intel_crtc(plane->crtc);
> >
> > +       update_pri_params(intel_crtc, &config.pri, true);
> > +
> > +       ret = intel_update_sprite_watermarks(intel_plane, intel_crtc, &config);
> > +       if (ret)
> > +               return ret;
> > +
> >         if (intel_crtc->active) {
> >                 bool primary_was_enabled = intel_crtc->primary_enabled;
> >
> >                 intel_crtc->primary_enabled = true;
> >
> > -               intel_plane->disable_plane(plane, plane->crtc);
> > +               intel_plane->disable_plane(plane, plane->crtc, &config);
> >
> >                 if (!primary_was_enabled && intel_crtc->primary_enabled)
> >                         intel_post_enable_primary(plane->crtc);
> > --
> > 1.8.5.5
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps
  2014-06-09 17:03       ` Ville Syrjälä
@ 2014-06-10 11:46         ` Jani Nikula
  0 siblings, 0 replies; 39+ messages in thread
From: Jani Nikula @ 2014-06-10 11:46 UTC (permalink / raw)
  To: Ville Syrjälä, Daniel Vetter; +Cc: Intel Graphics Development

On Mon, 09 Jun 2014, Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> On Wed, Jun 04, 2014 at 06:22:13PM +0200, Daniel Vetter wrote:
>> On Tue, Jun 03, 2014 at 05:51:01PM -0300, Paulo Zanoni wrote:
>> > 2014-05-22 11:48 GMT-03:00  <ville.syrjala@linux.intel.com>:
>> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> > >
>> > > We need to perform watermark programming before and after changing the
>> > > plane configuration. Add two new vfuncs to do that. The pre phase is
>> > > supposed to switch over to the intermediate watermarks which are
>> > > computed so that they can deal with both the old and new plane
>> > > configurations. The post phase will arm the vblank based update
>> > > systems to switch over to the optimal target watermarks after the
>> > > plane configuration has for sure changed.
>> > >
>> > > v2: Pass around intel_crtc and s/intel_crtc/crtc/
>> > >
>> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> > > ---
>> > >  drivers/gpu/drm/i915/i915_drv.h  |  5 +++
>> > >  drivers/gpu/drm/i915/intel_drv.h | 11 +++++
>> > >  drivers/gpu/drm/i915/intel_pm.c  | 88 ++++++++++++++++++++++++++++++++++++++++
>> > >  3 files changed, 104 insertions(+)
>> > >
>> > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> > > index c90d5ac..d4f8ae8 100644
>> > > --- a/drivers/gpu/drm/i915/i915_drv.h
>> > > +++ b/drivers/gpu/drm/i915/i915_drv.h
>> > > @@ -407,6 +407,7 @@ struct intel_plane_config;
>> > >  struct intel_crtc;
>> > >  struct intel_limit;
>> > >  struct dpll;
>> > > +struct intel_crtc_wm_config;
>> > >
>> > >  struct drm_i915_display_funcs {
>> > >         bool (*fbc_enabled)(struct drm_device *dev);
>> > > @@ -437,6 +438,10 @@ struct drm_i915_display_funcs {
>> > >                                  struct drm_crtc *crtc,
>> > >                                  uint32_t sprite_width, int pixel_size,
>> > >                                  bool enable, bool scaled);
>> > > +       void (*program_wm_pre)(struct intel_crtc *crtc,
>> > > +                              const struct intel_crtc_wm_config *config);
>> > > +       void (*program_wm_post)(struct intel_crtc *crtc,
>> > > +                               const struct intel_crtc_wm_config *config);
>> > >         void (*modeset_global_resources)(struct drm_device *dev);
>> > >         /* Returns the active state of the crtc, and if the crtc is active,
>> > >          * fills out the pipe-config with the hw state. */
>> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> > > index 72f01b1..4b59be3 100644
>> > > --- a/drivers/gpu/drm/i915/intel_drv.h
>> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
>> > > @@ -358,6 +358,13 @@ struct intel_pipe_wm {
>> > >         bool sprites_scaled;
>> > >  };
>> > >
>> > > +struct intel_crtc_wm_config {
>> > > +       /* target watermarks for the pipe */
>> > > +       struct intel_pipe_wm target;
>> > > +       /* intermediate watermarks for pending/active->target transition */
>> > > +       struct intel_pipe_wm intm;
>> > 
>> > It seems you always prefer shorter names such as "intm", and I usually
>> > prefer the longer ones like "intermediate". Looks like this is a
>> > common topic for my bikesheddings on your patches. When I read "intm"
>> > my brain parses it as "Int M" and then aborts execution =P
>> 
>> I agree with Paulo here. Some other name suggestion (since intermediate is
>> so long): transition/transit, merged, pending, ...
>
> The two good names I could think of "intermediate" and "transitional"
> are both really long. I agree that "intm" is a horrible shorthand,
> but I couldn't come up with anything half sane and still reasonably
> short.
>
> "merged" and "pending" already appear in the code with different
> meaning, so I'd rather not confuse the matter by reusing those.
> "transition" seems OK to me, though not that short either.
> "transit" brings up wrong kinds of images in my brain so i don't
> really like it.

interim, transient, temporary, or simly just temp?

BR,
Jani.


>
>> -Daniel
>> 
>> > 
>> > With or without that changed: Reviewed-by: Paulo Zanoni
>> > <paulo.r.zanoni@intel.com>
>> > 
>> > > +};
>> > > +
>> > >  struct intel_crtc {
>> > >         struct drm_crtc base;
>> > >         enum pipe pipe;
>> > > @@ -1001,6 +1008,10 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
>> > >  void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
>> > >  void ilk_wm_get_hw_state(struct drm_device *dev);
>> > >  void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
>> > > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
>> > > +                                 const struct intel_crtc_wm_config *config);
>> > > +void intel_program_watermarks_post(struct intel_crtc *crtc,
>> > > +                                  const struct intel_crtc_wm_config *config);
>> > >
>> > >
>> > >  /* intel_sdvo.c */
>> > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
>> > > index 6fc6416..ccf920a 100644
>> > > --- a/drivers/gpu/drm/i915/intel_pm.c
>> > > +++ b/drivers/gpu/drm/i915/intel_pm.c
>> > > @@ -2950,6 +2950,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
>> > >         spin_unlock(&crtc->wm.lock);
>> > >  }
>> > >
>> > > +static void ilk_wm_cancel(struct intel_crtc *crtc)
>> > > +{
>> > > +       struct drm_device *dev = crtc->base.dev;
>> > > +
>> > > +       assert_spin_locked(&crtc->wm.lock);
>> > > +
>> > > +       crtc->wm.dirty = false;
>> > > +
>> > > +       if (crtc->wm.vblank) {
>> > > +               drm_vblank_put(dev, crtc->pipe);
>> > > +               crtc->wm.vblank = false;
>> > > +       }
>> > > +}
>> > > +
>> > >  static void ilk_update_sprite_wm(struct drm_plane *plane,
>> > >                                      struct drm_crtc *crtc,
>> > >                                      uint32_t sprite_width, int pixel_size,
>> > > @@ -3084,6 +3098,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
>> > >                                                    pixel_size, enabled, scaled);
>> > >  }
>> > >
>> > > +void intel_program_watermarks_pre(struct intel_crtc *crtc,
>> > > +                                 const struct intel_crtc_wm_config *config)
>> > > +{
>> > > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>> > > +
>> > > +       if (dev_priv->display.program_wm_pre)
>> > > +               dev_priv->display.program_wm_pre(crtc, config);
>> > > +}
>> > > +
>> > > +void intel_program_watermarks_post(struct intel_crtc *crtc,
>> > > +                                  const struct intel_crtc_wm_config *config)
>> > > +{
>> > > +       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>> > > +
>> > > +       if (dev_priv->display.program_wm_post)
>> > > +               dev_priv->display.program_wm_post(crtc, config);
>> > > +}
>> > > +
>> > >  static struct drm_i915_gem_object *
>> > >  intel_alloc_context_page(struct drm_device *dev)
>> > >  {
>> > > @@ -6522,6 +6554,60 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
>> > >         pm_runtime_disable(device);
>> > >  }
>> > >
>> > > +static void ilk_program_wm_pre(struct intel_crtc *crtc,
>> > > +                              const struct intel_crtc_wm_config *config)
>> > > +{
>> > > +       struct drm_device *dev = crtc->base.dev;
>> > > +       struct drm_i915_private *dev_priv = dev->dev_private;
>> > > +
>> > > +       mutex_lock(&dev_priv->wm.mutex);
>> > > +
>> > > +       spin_lock_irq(&crtc->wm.lock);
>> > > +       ilk_wm_cancel(crtc);
>> > > +       spin_unlock_irq(&crtc->wm.lock);
>> > > +
>> > > +       /* pending update (if any) got cancelled */
>> > > +       crtc->wm.pending = crtc->wm.active;
>> > > +
>> > > +       if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
>> > > +               goto unlock;
>> > > +
>> > > +       crtc->wm.active = config->intm;
>> > > +
>> > > +       /* use the most up to date watermarks for other pipes */
>> > > +       ilk_refresh_pending_watermarks(dev);
>> > > +
>> > > +       /* switch over to the intermediate watermarks */
>> > > +       ilk_program_watermarks(dev);
>> > > +
>> > > + unlock:
>> > > +       mutex_unlock(&dev_priv->wm.mutex);
>> > > +}
>> > > +
>> > > +static void ilk_program_wm_post(struct intel_crtc *crtc,
>> > > +                               const struct intel_crtc_wm_config *config)
>> > > +{
>> > > +       struct drm_device *dev = crtc->base.dev;
>> > > +       struct drm_i915_private *dev_priv = dev->dev_private;
>> > > +       u32 vbl_count;
>> > > +
>> > > +       /*
>> > > +        * FIXME sample this inside the atomic section to avoid
>> > > +        * needlessly long periods w/ sub-par watermarks
>> > > +        */
>> > > +       vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
>> > > +
>> > > +       mutex_lock(&dev_priv->wm.mutex);
>> > > +
>> > > +       /*
>> > > +        * We can switch over to the target
>> > > +        * watermarks after the next vblank.
>> > > +        */
>> > > +       ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
>> > > +
>> > > +       mutex_unlock(&dev_priv->wm.mutex);
>> > > +}
>> > > +
>> > >  /* Set up chip specific power management-related functions */
>> > >  void intel_init_pm(struct drm_device *dev)
>> > >  {
>> > > @@ -6569,6 +6655,8 @@ void intel_init_pm(struct drm_device *dev)
>> > >                      dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
>> > >                         dev_priv->display.update_wm = ilk_update_wm;
>> > >                         dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
>> > > +                       dev_priv->display.program_wm_pre = ilk_program_wm_pre;
>> > > +                       dev_priv->display.program_wm_post = ilk_program_wm_post;
>> > >                 } else {
>> > >                         DRM_DEBUG_KMS("Failed to read display plane latency. "
>> > >                                       "Disable CxSR\n");
>> > > --
>> > > 1.8.5.5
>> > >
>> > > _______________________________________________
>> > > Intel-gfx mailing list
>> > > Intel-gfx@lists.freedesktop.org
>> > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>> > 
>> > 
>> > 
>> > -- 
>> > Paulo Zanoni
>> > _______________________________________________
>> > Intel-gfx mailing list
>> > Intel-gfx@lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>> 
>> -- 
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
>
> -- 
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes
  2014-06-04  6:00     ` Arun Murthy
@ 2014-06-10 16:22       ` Ville Syrjälä
  0 siblings, 0 replies; 39+ messages in thread
From: Ville Syrjälä @ 2014-06-10 16:22 UTC (permalink / raw)
  To: Arun Murthy; +Cc: intel-gfx

On Wed, Jun 04, 2014 at 11:30:47AM +0530, Arun Murthy wrote:
> On Mon, May 26, 2014 at 7:26 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Thu, May 22, 2014 at 05:48:06PM +0300, ville.syrjala@linux.intel.com wrote:
> >> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>
> >> Because of the upcoming vblank interrupt driven watermark update
> >> mechanism we will have use for vblank interrupts during plane
> >> enabling/disabling. So don't call drm_vblank_off() until planes
> >> are off, and call drm_vblank_on() just before we start to enable
> >> the planes.
> 
> Since watermark and display control registers are double buffered
> both of them get updated on next blank and hence in sync.
> Can you let me know the need for vblank driven watermark updates?

Watermark registers aren't double buffered.

-- 
Ville Syrjälä
Intel OTC

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

end of thread, other threads:[~2014-06-10 16:23 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-22 14:48 [PATCH v2 00/16] drm/i915: Two part watermark update for ILK+, part 2 ville.syrjala
2014-05-22 14:48 ` [PATCH v2 01/16] drm/i915: Keep vblank interrupts enabled while enabling/disabling planes ville.syrjala
2014-05-26 13:56   ` Daniel Vetter
2014-06-04  6:00     ` Arun Murthy
2014-06-10 16:22       ` Ville Syrjälä
2014-05-22 14:48 ` [PATCH 02/16] drm/i915: Leave interrupts enabled while disabling crtcs during suspend ville.syrjala
2014-05-22 14:48 ` [PATCH 03/16] drm/i915: Check hw vs. sw watermark state after programming ville.syrjala
2014-05-22 14:48 ` [PATCH 04/16] drm/i915: Refactor ilk_validate_pipe_wm() ville.syrjala
2014-05-22 14:48 ` [PATCH v2 05/16] drm/i915: Refactor ilk_update_wm ville.syrjala
2014-05-22 14:48 ` [PATCH 06/16] drm/i915: Add dev_priv->wm.mutex ville.syrjala
2014-05-22 14:48 ` [PATCH v2 07/16] drm/i915: Add vblank based delayed watermark update mechanism ville.syrjala
2014-06-03 18:50   ` Paulo Zanoni
2014-06-03 19:32     ` Ville Syrjälä
2014-06-04 14:01       ` Paulo Zanoni
2014-06-04 16:10         ` Daniel Vetter
2014-06-09 15:01           ` Ville Syrjälä
2014-05-22 14:48 ` [PATCH v2 08/16] drm/i915: Split watermark programming into pre and post steps ville.syrjala
2014-06-03 20:51   ` Paulo Zanoni
2014-06-04 16:22     ` Daniel Vetter
2014-06-09 17:03       ` Ville Syrjälä
2014-06-10 11:46         ` Jani Nikula
2014-05-22 14:48 ` [PATCH v2 09/16] drm/i915: Actually perform the watermark update in two phases ville.syrjala
2014-06-03 22:47   ` Paulo Zanoni
2014-06-09 18:28     ` Ville Syrjälä
2014-05-22 14:48 ` [PATCH v2 10/16] drm/i915: Wait for watermark updates to finish before disabling a pipe ville.syrjala
2014-06-04 13:54   ` Paulo Zanoni
2014-05-22 14:48 ` [PATCH 11/16] drm/i915: Refactor get_other_active_crtc() ville.syrjala
2014-06-04 16:59   ` Paulo Zanoni
2014-05-22 14:48 ` [PATCH 12/16] drm/i915: Disable LP1+ watermarks while changing the number of active pipes ville.syrjala
2014-06-04 18:24   ` Paulo Zanoni
2014-06-09 16:51     ` Ville Syrjälä
2014-05-22 14:48 ` [PATCH v2 13/16] drm/i915: Keep track of who disabled LP1+ watermarks ville.syrjala
2014-06-04 18:30   ` Paulo Zanoni
2014-05-22 14:48 ` [PATCH 14/16] drm/i915: Prefer the 5/6 DDB split when primary is disabled ville.syrjala
2014-06-04 18:34   ` Paulo Zanoni
2014-05-22 14:48 ` [PATCH 15/16] drm/i915: Add a workaround for sprite only <-> primary only switching ville.syrjala
2014-06-04 18:44   ` Paulo Zanoni
2014-05-22 14:48 ` [PATCH 16/16] drm/i915: Don't disable LP1+ watermarks for every frame when scaled ville.syrjala
2014-06-04 18:49   ` Paulo Zanoni

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.