All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks
@ 2016-07-21 19:23 Lyude
  2016-07-21 19:23   ` Lyude
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: Lyude, Daniel Vetter, Jani Nikula, David Airlie, dri-devel, linux-kernel

To Sebastian Reichel:
	I *think* I may have found the problem. Looked at
	./scripts/get_maintainer.pl and apparently it's defaults aren't
	actually expected to work well with `git send-email`. I've added
	--norolestats and hopefully that should fix the issue. If the email
	format issue still seems to be coming up let me know.

New version of the original patchset from

https://patchwork.freedesktop.org/series/10108/

Notable changes across the patchset (per-patch descriptions noted in each
patch's description):
 - Dropped "drm/i915/skl: Always wait for pipes to update after a flush" -
   turns out it wasn't actually fixing anything (on drm-intel/drm-intel-nightly
   anyway)
 - Dropped "drm/i915/skl: Actually reuse wm values when pipes don't change" -
   this was a silly mistake

Lyude (3):
  drm/i915/skl: Only flush pipes when we change the ddb allocation
  drm/i915/skl: Fix extra whitespace in skl_flush_wm_values()
  drm/i915/skl: Update plane watermarks atomically during plane updates

Matt Roper (1):
  drm/i915/gen9: Only copy WM results for changed pipes to skl_hw

 drivers/gpu/drm/i915/i915_drv.h      |   1 +
 drivers/gpu/drm/i915/intel_display.c |   5 ++
 drivers/gpu/drm/i915/intel_drv.h     |   2 +
 drivers/gpu/drm/i915/intel_pm.c      | 114 +++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_sprite.c  |   2 +
 5 files changed, 105 insertions(+), 19 deletions(-)

-- 
2.7.4

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

* [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw
  2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
@ 2016-07-21 19:23   ` Lyude
  2016-07-21 19:23   ` Lyude
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: Lyude, stable, Maarten Lankhorst, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

From: Matt Roper <matthew.d.roper@intel.com>

When we write watermark values to the hardware, those values are stored
in dev_priv->wm.skl_hw.  However with recent watermark changes, the
results structure we're copying from only contains valid watermark and
DDB values for the pipes that are actually changing; the values for
other pipes remain 0.  Thus a blind copy of the entire skl_wm_values
structure will clobber the values for unchanged pipes...we need to be
more selective and only copy over the values for the changing pipes.

This mistake was hidden until recently due to another bug that caused us
to erroneously re-calculate watermarks for all active pipes rather than
changing pipes.  Only when that bug was fixed was the impact of this bug
discovered (e.g., modesets failing with "Requested display configuration
exceeds system watermark limitations" messages and leaving watermarks
non-functional, even ones initiated by intel_fbdev_restore_mode).

Changes since v1:
 - Add a function for copying a pipe's wm values
   (skl_copy_wm_for_pipe()) so we can reuse this later

Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
Fixes: 9b6130227495 ("drm/i915/gen9: Re-allocate DDB only for changed pipes")
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Cc: stable@vger.kernel.org
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 64d628c..56ddd71 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3946,6 +3946,24 @@ skl_compute_ddb(struct drm_atomic_state *state)
 	return 0;
 }
 
+static void
+skl_copy_wm_for_pipe(struct skl_wm_values *dst,
+		     struct skl_wm_values *src,
+		     enum pipe pipe)
+{
+	dst->wm_linetime[pipe] = src->wm_linetime[pipe];
+	memcpy(dst->plane[pipe], src->plane[pipe],
+	       sizeof(dst->plane[pipe]));
+	memcpy(dst->plane_trans[pipe], src->plane_trans[pipe],
+	       sizeof(dst->plane_trans[pipe]));
+
+	dst->ddb.pipe[pipe] = src->ddb.pipe[pipe];
+	memcpy(dst->ddb.y_plane[pipe], src->ddb.y_plane[pipe],
+	       sizeof(dst->ddb.y_plane[pipe]));
+	memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe],
+	       sizeof(dst->ddb.plane[pipe]));
+}
+
 static int
 skl_compute_wm(struct drm_atomic_state *state)
 {
@@ -4018,8 +4036,10 @@ static void skl_update_wm(struct drm_crtc *crtc)
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct skl_wm_values *results = &dev_priv->wm.skl_results;
+	struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
 	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
+	int pipe;
 
 	if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
 		return;
@@ -4031,8 +4051,12 @@ static void skl_update_wm(struct drm_crtc *crtc)
 	skl_write_wm_values(dev_priv, results);
 	skl_flush_wm_values(dev_priv, results);
 
-	/* store the new configuration */
-	dev_priv->wm.skl_hw = *results;
+	/*
+	 * Store the new configuration (but only for the pipes that have
+	 * changed; the other values weren't recomputed).
+	 */
+	for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
+		skl_copy_wm_for_pipe(hw_vals, results, pipe);
 
 	mutex_unlock(&dev_priv->wm.wm_mutex);
 }
-- 
2.7.4

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

* [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw
@ 2016-07-21 19:23   ` Lyude
  0 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: David Airlie, dri-devel, linux-kernel, stable, Hans de Goede,
	Daniel Vetter

From: Matt Roper <matthew.d.roper@intel.com>

When we write watermark values to the hardware, those values are stored
in dev_priv->wm.skl_hw.  However with recent watermark changes, the
results structure we're copying from only contains valid watermark and
DDB values for the pipes that are actually changing; the values for
other pipes remain 0.  Thus a blind copy of the entire skl_wm_values
structure will clobber the values for unchanged pipes...we need to be
more selective and only copy over the values for the changing pipes.

This mistake was hidden until recently due to another bug that caused us
to erroneously re-calculate watermarks for all active pipes rather than
changing pipes.  Only when that bug was fixed was the impact of this bug
discovered (e.g., modesets failing with "Requested display configuration
exceeds system watermark limitations" messages and leaving watermarks
non-functional, even ones initiated by intel_fbdev_restore_mode).

Changes since v1:
 - Add a function for copying a pipe's wm values
   (skl_copy_wm_for_pipe()) so we can reuse this later

Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
Fixes: 9b6130227495 ("drm/i915/gen9: Re-allocate DDB only for changed pipes")
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Cc: stable@vger.kernel.org
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 64d628c..56ddd71 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3946,6 +3946,24 @@ skl_compute_ddb(struct drm_atomic_state *state)
 	return 0;
 }
 
+static void
+skl_copy_wm_for_pipe(struct skl_wm_values *dst,
+		     struct skl_wm_values *src,
+		     enum pipe pipe)
+{
+	dst->wm_linetime[pipe] = src->wm_linetime[pipe];
+	memcpy(dst->plane[pipe], src->plane[pipe],
+	       sizeof(dst->plane[pipe]));
+	memcpy(dst->plane_trans[pipe], src->plane_trans[pipe],
+	       sizeof(dst->plane_trans[pipe]));
+
+	dst->ddb.pipe[pipe] = src->ddb.pipe[pipe];
+	memcpy(dst->ddb.y_plane[pipe], src->ddb.y_plane[pipe],
+	       sizeof(dst->ddb.y_plane[pipe]));
+	memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe],
+	       sizeof(dst->ddb.plane[pipe]));
+}
+
 static int
 skl_compute_wm(struct drm_atomic_state *state)
 {
@@ -4018,8 +4036,10 @@ static void skl_update_wm(struct drm_crtc *crtc)
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct skl_wm_values *results = &dev_priv->wm.skl_results;
+	struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
 	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
+	int pipe;
 
 	if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
 		return;
@@ -4031,8 +4051,12 @@ static void skl_update_wm(struct drm_crtc *crtc)
 	skl_write_wm_values(dev_priv, results);
 	skl_flush_wm_values(dev_priv, results);
 
-	/* store the new configuration */
-	dev_priv->wm.skl_hw = *results;
+	/*
+	 * Store the new configuration (but only for the pipes that have
+	 * changed; the other values weren't recomputed).
+	 */
+	for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
+		skl_copy_wm_for_pipe(hw_vals, results, pipe);
 
 	mutex_unlock(&dev_priv->wm.wm_mutex);
 }
-- 
2.7.4

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

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

* [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation
  2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
@ 2016-07-21 19:23   ` Lyude
  2016-07-21 19:23   ` Lyude
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: Lyude, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

Manual pipe flushes are only necessary in order to make sure that we prevent
pipes with changed ddb allocations from overlapping from one another at
any point in time. Additionally, forcing us to wait for the next vblank
every time we have to update the watermark values because the cursor was
moving between screens will introduce a rather noticable lag for users.

Signed-off-by: Lyude <cpaul@redhat.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h |  1 +
 drivers/gpu/drm/i915/intel_pm.c | 31 +++++++++++++++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c97724d..9e1e045 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1597,6 +1597,7 @@ struct skl_ddb_allocation {
 
 struct skl_wm_values {
 	unsigned dirty_pipes;
+	bool ddb_changed;
 	struct skl_ddb_allocation ddb;
 	uint32_t wm_linetime[I915_MAX_PIPES];
 	uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8];
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 56ddd71..55237ea 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3789,6 +3789,12 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
 	new_ddb = &new_values->ddb;
 	cur_ddb = &dev_priv->wm.skl_hw.ddb;
 
+	/* We only ever need to flush when the ddb allocations change */
+	if (!new_values->ddb_changed)
+		return;
+
+	new_values->ddb_changed = false;
+
 	/*
 	 * First pass: flush the pipes with the new allocation contained into
 	 * the old space.
@@ -3893,6 +3899,22 @@ pipes_modified(struct drm_atomic_state *state)
 	return ret;
 }
 
+static bool
+skl_pipe_ddb_changed(struct skl_ddb_allocation *old,
+		     struct skl_ddb_allocation *new,
+		     enum pipe pipe)
+{
+	if (memcmp(&old->pipe[pipe], &new->pipe[pipe],
+		   sizeof(old->pipe[pipe])) != 0 ||
+	    memcmp(&old->plane[pipe], &new->plane[pipe],
+		   sizeof(old->plane[pipe])) != 0 ||
+	    memcmp(&old->y_plane[pipe], &new->y_plane[pipe],
+		   sizeof(old->y_plane[pipe])) != 0)
+		return true;
+
+	return false;
+}
+
 static int
 skl_compute_ddb(struct drm_atomic_state *state)
 {
@@ -3900,7 +3922,8 @@ skl_compute_ddb(struct drm_atomic_state *state)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct intel_crtc *intel_crtc;
-	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
+	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+	struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
 	uint32_t realloc_pipes = pipes_modified(state);
 	int ret;
 
@@ -3938,9 +3961,13 @@ skl_compute_ddb(struct drm_atomic_state *state)
 		if (IS_ERR(cstate))
 			return PTR_ERR(cstate);
 
-		ret = skl_allocate_pipe_ddb(cstate, ddb);
+		ret = skl_allocate_pipe_ddb(cstate, new_ddb);
 		if (ret)
 			return ret;
+
+		if (!intel_state->wm_results.ddb_changed &&
+		    skl_pipe_ddb_changed(old_ddb, new_ddb, intel_crtc->pipe))
+			intel_state->wm_results.ddb_changed = true;
 	}
 
 	return 0;
-- 
2.7.4

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

* [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation
@ 2016-07-21 19:23   ` Lyude
  0 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: David Airlie, dri-devel, linux-kernel, stable, Hans de Goede,
	Daniel Vetter

Manual pipe flushes are only necessary in order to make sure that we prevent
pipes with changed ddb allocations from overlapping from one another at
any point in time. Additionally, forcing us to wait for the next vblank
every time we have to update the watermark values because the cursor was
moving between screens will introduce a rather noticable lag for users.

Signed-off-by: Lyude <cpaul@redhat.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h |  1 +
 drivers/gpu/drm/i915/intel_pm.c | 31 +++++++++++++++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c97724d..9e1e045 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1597,6 +1597,7 @@ struct skl_ddb_allocation {
 
 struct skl_wm_values {
 	unsigned dirty_pipes;
+	bool ddb_changed;
 	struct skl_ddb_allocation ddb;
 	uint32_t wm_linetime[I915_MAX_PIPES];
 	uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8];
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 56ddd71..55237ea 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3789,6 +3789,12 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
 	new_ddb = &new_values->ddb;
 	cur_ddb = &dev_priv->wm.skl_hw.ddb;
 
+	/* We only ever need to flush when the ddb allocations change */
+	if (!new_values->ddb_changed)
+		return;
+
+	new_values->ddb_changed = false;
+
 	/*
 	 * First pass: flush the pipes with the new allocation contained into
 	 * the old space.
@@ -3893,6 +3899,22 @@ pipes_modified(struct drm_atomic_state *state)
 	return ret;
 }
 
+static bool
+skl_pipe_ddb_changed(struct skl_ddb_allocation *old,
+		     struct skl_ddb_allocation *new,
+		     enum pipe pipe)
+{
+	if (memcmp(&old->pipe[pipe], &new->pipe[pipe],
+		   sizeof(old->pipe[pipe])) != 0 ||
+	    memcmp(&old->plane[pipe], &new->plane[pipe],
+		   sizeof(old->plane[pipe])) != 0 ||
+	    memcmp(&old->y_plane[pipe], &new->y_plane[pipe],
+		   sizeof(old->y_plane[pipe])) != 0)
+		return true;
+
+	return false;
+}
+
 static int
 skl_compute_ddb(struct drm_atomic_state *state)
 {
@@ -3900,7 +3922,8 @@ skl_compute_ddb(struct drm_atomic_state *state)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct intel_crtc *intel_crtc;
-	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
+	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+	struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
 	uint32_t realloc_pipes = pipes_modified(state);
 	int ret;
 
@@ -3938,9 +3961,13 @@ skl_compute_ddb(struct drm_atomic_state *state)
 		if (IS_ERR(cstate))
 			return PTR_ERR(cstate);
 
-		ret = skl_allocate_pipe_ddb(cstate, ddb);
+		ret = skl_allocate_pipe_ddb(cstate, new_ddb);
 		if (ret)
 			return ret;
+
+		if (!intel_state->wm_results.ddb_changed &&
+		    skl_pipe_ddb_changed(old_ddb, new_ddb, intel_crtc->pipe))
+			intel_state->wm_results.ddb_changed = true;
 	}
 
 	return 0;
-- 
2.7.4

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

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

* [PATCH v2 3/4] drm/i915/skl: Fix extra whitespace in skl_flush_wm_values()
  2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
@ 2016-07-21 19:23   ` Lyude
  2016-07-21 19:23   ` Lyude
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: Lyude, Daniel Vetter, Jani Nikula, David Airlie, dri-devel, linux-kernel

Similar to how a vehicle will travel faster if you paint flames on it,
cleaning up this extra whitespace is guaranteed to provide additional
stability while updating watermark values.

Signed-off-by: Lyude <cpaul@redhat.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 55237ea..9421d92 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3817,7 +3817,6 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
 		reallocated[pipe] = true;
 	}
 
-
 	/*
 	 * Second pass: flush the pipes that are having their allocation
 	 * reduced, but overlapping with a previous allocation.
-- 
2.7.4

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

* [PATCH v2 3/4] drm/i915/skl: Fix extra whitespace in skl_flush_wm_values()
@ 2016-07-21 19:23   ` Lyude
  0 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: David Airlie, linux-kernel, dri-devel, Daniel Vetter

Similar to how a vehicle will travel faster if you paint flames on it,
cleaning up this extra whitespace is guaranteed to provide additional
stability while updating watermark values.

Signed-off-by: Lyude <cpaul@redhat.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 55237ea..9421d92 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3817,7 +3817,6 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
 		reallocated[pipe] = true;
 	}
 
-
 	/*
 	 * Second pass: flush the pipes that are having their allocation
 	 * reduced, but overlapping with a previous allocation.
-- 
2.7.4

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

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

* [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates
  2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
@ 2016-07-21 19:23   ` Lyude
  2016-07-21 19:23   ` Lyude
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: Lyude, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

Thanks to Ville for suggesting this as a potential solution to pipe
underruns on Skylake.

On Skylake all of the registers for configuring planes, including the
registers for configuring their watermarks, are double buffered. New
values written to them won't take effect until said registers are
"armed", which is done by writing to the PLANE_SURF (or in the case of
cursor planes, the CURBASE register) register.

With this in mind, up until now we've been updating watermarks on skl
like this:

  non-modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - intel_pre_plane_update:
        - intel_update_watermarks()
     - {vblank happens; new watermarks + old plane values => underrun }
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - end vblank evasion
  }

  or

  modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - crtc_enable:
        - intel_update_watermarks()
     - {vblank happens; new watermarks + old plane values => underrun }
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - end vblank evasion
  }

Now we update watermarks atomically like this:

  non-modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - intel_pre_plane_update:
        - intel_update_watermarks() (wm values aren't written yet)
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - write new wm values
        - end vblank evasion
  }

  modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - crtc_enable:
        - intel_update_watermarks() (actual wm values aren't written
          yet)
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
	- write new wm values
        - end vblank evasion
  }

So this patch moves all of the watermark writes into the right place;
inside of the vblank evasion where we update all of the registers for
each plane. While this patch doesn't fix everything, it does allow us to
update the watermark values in the way the hardware expects us to.

Changes since original patch series:
 - Remove mutex_lock/mutex_unlock since they don't do anything and we're
   not touching global state
 - Move skl_write_cursor_wm/skl_write_plane_wm functions into
   intel_pm.c, make externally visible
 - Add skl_write_plane_wm calls to skl_update_plane
 - Fix conditional for for loop in skl_write_plane_wm (level < max_level
   should be level <= max_level)
 - Make diagram in commit more accurate to what's actually happening
 - Add Fixes:

Changes since v1:
 - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
   then just Skylake
 - Update description to make it clear this patch doesn't fix everything
 - Check if pipes were actually changed before writing watermarks

Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |  5 ++++
 drivers/gpu/drm/i915/intel_drv.h     |  2 ++
 drivers/gpu/drm/i915/intel_pm.c      | 54 ++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_sprite.c  |  2 ++
 4 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 78beb7e..d93d014 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3031,6 +3031,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
 	intel_crtc->adjusted_x = x_offset;
 	intel_crtc->adjusted_y = y_offset;
 
+	skl_write_plane_wm(intel_crtc, 0);
+
 	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
 	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
 	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
@@ -10242,6 +10244,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
 	int pipe = intel_crtc->pipe;
 	uint32_t cntl = 0;
 
+	if (IS_GEN9(dev_priv))
+		skl_write_cursor_wm(intel_crtc);
+
 	if (plane_state && plane_state->visible) {
 		cntl = MCURSOR_GAMMA_ENABLE;
 		switch (plane_state->base.crtc_w) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e74d851..f1f54d9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1709,6 +1709,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
 void skl_wm_get_hw_state(struct drm_device *dev);
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 			  struct skl_ddb_allocation *ddb /* out */);
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc);
+void skl_write_plane_wm(struct intel_crtc *intel_crtc, int plane);
 uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
 bool ilk_disable_lp_wm(struct drm_device *dev);
 int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 9421d92..41f379b 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3680,6 +3680,45 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
 		I915_WRITE(reg, 0);
 }
 
+void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+			int plane)
+{
+	struct drm_crtc *crtc = &intel_crtc->base;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+	int level, max_level = ilk_wm_max_level(dev);
+	enum pipe pipe = intel_crtc->pipe;
+
+	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
+		return;
+
+	for (level = 0; level <= max_level; level++) {
+		I915_WRITE(PLANE_WM(pipe, plane, level),
+			   wm->plane[pipe][plane][level]);
+	}
+	I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
+}
+
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc)
+{
+	struct drm_crtc *crtc = &intel_crtc->base;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+	int level, max_level = ilk_wm_max_level(dev);
+	enum pipe pipe = intel_crtc->pipe;
+
+	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
+		return;
+
+	for (level = 0; level <= max_level; level++) {
+		I915_WRITE(CUR_WM(pipe, level),
+			   wm->plane[pipe][PLANE_CURSOR][level]);
+	}
+	I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
+}
+
 static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 				const struct skl_wm_values *new)
 {
@@ -3687,7 +3726,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 	struct intel_crtc *crtc;
 
 	for_each_intel_crtc(dev, crtc) {
-		int i, level, max_level = ilk_wm_max_level(dev);
+		int i;
 		enum pipe pipe = crtc->pipe;
 
 		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
@@ -3697,19 +3736,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 
 		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
 
-		for (level = 0; level <= max_level; level++) {
-			for (i = 0; i < intel_num_planes(crtc); i++)
-				I915_WRITE(PLANE_WM(pipe, i, level),
-					   new->plane[pipe][i][level]);
-			I915_WRITE(CUR_WM(pipe, level),
-				   new->plane[pipe][PLANE_CURSOR][level]);
-		}
-		for (i = 0; i < intel_num_planes(crtc); i++)
-			I915_WRITE(PLANE_WM_TRANS(pipe, i),
-				   new->plane_trans[pipe][i]);
-		I915_WRITE(CUR_WM_TRANS(pipe),
-			   new->plane_trans[pipe][PLANE_CURSOR]);
-
 		for (i = 0; i < intel_num_planes(crtc); i++) {
 			skl_ddb_entry_write(dev_priv,
 					    PLANE_BUF_CFG(pipe, i),
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 0de935a..50026f1 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -238,6 +238,8 @@ skl_update_plane(struct drm_plane *drm_plane,
 	crtc_w--;
 	crtc_h--;
 
+	skl_write_plane_wm(to_intel_crtc(crtc_state->base.crtc), plane);
+
 	if (key->flags) {
 		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
 		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
-- 
2.7.4

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

* [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates
@ 2016-07-21 19:23   ` Lyude
  0 siblings, 0 replies; 19+ messages in thread
From: Lyude @ 2016-07-21 19:23 UTC (permalink / raw)
  To: intel-gfx, Matt Roper
  Cc: David Airlie, dri-devel, linux-kernel, stable, Hans de Goede,
	Daniel Vetter

Thanks to Ville for suggesting this as a potential solution to pipe
underruns on Skylake.

On Skylake all of the registers for configuring planes, including the
registers for configuring their watermarks, are double buffered. New
values written to them won't take effect until said registers are
"armed", which is done by writing to the PLANE_SURF (or in the case of
cursor planes, the CURBASE register) register.

With this in mind, up until now we've been updating watermarks on skl
like this:

  non-modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - intel_pre_plane_update:
        - intel_update_watermarks()
     - {vblank happens; new watermarks + old plane values => underrun }
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - end vblank evasion
  }

  or

  modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - crtc_enable:
        - intel_update_watermarks()
     - {vblank happens; new watermarks + old plane values => underrun }
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - end vblank evasion
  }

Now we update watermarks atomically like this:

  non-modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - intel_pre_plane_update:
        - intel_update_watermarks() (wm values aren't written yet)
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
        - write new wm values
        - end vblank evasion
  }

  modeset {
   - calculate (during atomic check phase)
   - finish_atomic_commit:
     - crtc_enable:
        - intel_update_watermarks() (actual wm values aren't written
          yet)
     - drm_atomic_helper_commit_planes_on_crtc:
        - start vblank evasion
        - write new plane registers
	- write new wm values
        - end vblank evasion
  }

So this patch moves all of the watermark writes into the right place;
inside of the vblank evasion where we update all of the registers for
each plane. While this patch doesn't fix everything, it does allow us to
update the watermark values in the way the hardware expects us to.

Changes since original patch series:
 - Remove mutex_lock/mutex_unlock since they don't do anything and we're
   not touching global state
 - Move skl_write_cursor_wm/skl_write_plane_wm functions into
   intel_pm.c, make externally visible
 - Add skl_write_plane_wm calls to skl_update_plane
 - Fix conditional for for loop in skl_write_plane_wm (level < max_level
   should be level <= max_level)
 - Make diagram in commit more accurate to what's actually happening
 - Add Fixes:

Changes since v1:
 - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
   then just Skylake
 - Update description to make it clear this patch doesn't fix everything
 - Check if pipes were actually changed before writing watermarks

Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |  5 ++++
 drivers/gpu/drm/i915/intel_drv.h     |  2 ++
 drivers/gpu/drm/i915/intel_pm.c      | 54 ++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_sprite.c  |  2 ++
 4 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 78beb7e..d93d014 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3031,6 +3031,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
 	intel_crtc->adjusted_x = x_offset;
 	intel_crtc->adjusted_y = y_offset;
 
+	skl_write_plane_wm(intel_crtc, 0);
+
 	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
 	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
 	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
@@ -10242,6 +10244,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
 	int pipe = intel_crtc->pipe;
 	uint32_t cntl = 0;
 
+	if (IS_GEN9(dev_priv))
+		skl_write_cursor_wm(intel_crtc);
+
 	if (plane_state && plane_state->visible) {
 		cntl = MCURSOR_GAMMA_ENABLE;
 		switch (plane_state->base.crtc_w) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e74d851..f1f54d9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1709,6 +1709,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
 void skl_wm_get_hw_state(struct drm_device *dev);
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 			  struct skl_ddb_allocation *ddb /* out */);
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc);
+void skl_write_plane_wm(struct intel_crtc *intel_crtc, int plane);
 uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
 bool ilk_disable_lp_wm(struct drm_device *dev);
 int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 9421d92..41f379b 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3680,6 +3680,45 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
 		I915_WRITE(reg, 0);
 }
 
+void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+			int plane)
+{
+	struct drm_crtc *crtc = &intel_crtc->base;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+	int level, max_level = ilk_wm_max_level(dev);
+	enum pipe pipe = intel_crtc->pipe;
+
+	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
+		return;
+
+	for (level = 0; level <= max_level; level++) {
+		I915_WRITE(PLANE_WM(pipe, plane, level),
+			   wm->plane[pipe][plane][level]);
+	}
+	I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
+}
+
+void skl_write_cursor_wm(struct intel_crtc *intel_crtc)
+{
+	struct drm_crtc *crtc = &intel_crtc->base;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+	int level, max_level = ilk_wm_max_level(dev);
+	enum pipe pipe = intel_crtc->pipe;
+
+	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
+		return;
+
+	for (level = 0; level <= max_level; level++) {
+		I915_WRITE(CUR_WM(pipe, level),
+			   wm->plane[pipe][PLANE_CURSOR][level]);
+	}
+	I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
+}
+
 static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 				const struct skl_wm_values *new)
 {
@@ -3687,7 +3726,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 	struct intel_crtc *crtc;
 
 	for_each_intel_crtc(dev, crtc) {
-		int i, level, max_level = ilk_wm_max_level(dev);
+		int i;
 		enum pipe pipe = crtc->pipe;
 
 		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
@@ -3697,19 +3736,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
 
 		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
 
-		for (level = 0; level <= max_level; level++) {
-			for (i = 0; i < intel_num_planes(crtc); i++)
-				I915_WRITE(PLANE_WM(pipe, i, level),
-					   new->plane[pipe][i][level]);
-			I915_WRITE(CUR_WM(pipe, level),
-				   new->plane[pipe][PLANE_CURSOR][level]);
-		}
-		for (i = 0; i < intel_num_planes(crtc); i++)
-			I915_WRITE(PLANE_WM_TRANS(pipe, i),
-				   new->plane_trans[pipe][i]);
-		I915_WRITE(CUR_WM_TRANS(pipe),
-			   new->plane_trans[pipe][PLANE_CURSOR]);
-
 		for (i = 0; i < intel_num_planes(crtc); i++) {
 			skl_ddb_entry_write(dev_priv,
 					    PLANE_BUF_CFG(pipe, i),
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 0de935a..50026f1 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -238,6 +238,8 @@ skl_update_plane(struct drm_plane *drm_plane,
 	crtc_w--;
 	crtc_h--;
 
+	skl_write_plane_wm(to_intel_crtc(crtc_state->base.crtc), plane);
+
 	if (key->flags) {
 		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
 		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
-- 
2.7.4

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

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

* Re: [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation
  2016-07-21 19:23   ` Lyude
@ 2016-07-21 20:48     ` Matt Roper
  -1 siblings, 0 replies; 19+ messages in thread
From: Matt Roper @ 2016-07-21 20:48 UTC (permalink / raw)
  To: Lyude
  Cc: intel-gfx, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

On Thu, Jul 21, 2016 at 03:23:38PM -0400, Lyude wrote:
> Manual pipe flushes are only necessary in order to make sure that we prevent
> pipes with changed ddb allocations from overlapping from one another at
> any point in time. Additionally, forcing us to wait for the next vblank
> every time we have to update the watermark values because the cursor was
> moving between screens will introduce a rather noticable lag for users.
> 
> Signed-off-by: Lyude <cpaul@redhat.com>
> Cc: stable@vger.kernel.org
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h |  1 +
>  drivers/gpu/drm/i915/intel_pm.c | 31 +++++++++++++++++++++++++++++--
>  2 files changed, 30 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c97724d..9e1e045 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1597,6 +1597,7 @@ struct skl_ddb_allocation {
>  
>  struct skl_wm_values {
>  	unsigned dirty_pipes;
> +	bool ddb_changed;
>  	struct skl_ddb_allocation ddb;
>  	uint32_t wm_linetime[I915_MAX_PIPES];
>  	uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8];
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 56ddd71..55237ea 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3789,6 +3789,12 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
>  	new_ddb = &new_values->ddb;
>  	cur_ddb = &dev_priv->wm.skl_hw.ddb;
>  
> +	/* We only ever need to flush when the ddb allocations change */

I'd expand the comment a bit here since the logic is non-obvious.  In
general, we could still have WM changes (which need a flush) even if the
DDB doesn't change.  However in such cases, we'll be doing a normal
flush as part of update_plane, update_primary_plane, or update_cursor so
there's no need to do an extra, early flush here.  The whole three-step
flush dance is only needed to ensure proper inter-pipe ordering when the
inter-pipe DDB allocation changes; the three-step handling we have here
still isn't happening at the right time during the atomic commit, but
fixing that up is something that one of your later patches will
presumably address.

> +	if (!new_values->ddb_changed)
> +		return;
> +
> +	new_values->ddb_changed = false;
> +
>  	/*
>  	 * First pass: flush the pipes with the new allocation contained into
>  	 * the old space.
> @@ -3893,6 +3899,22 @@ pipes_modified(struct drm_atomic_state *state)
>  	return ret;
>  }
>  
> +static bool
> +skl_pipe_ddb_changed(struct skl_ddb_allocation *old,
> +		     struct skl_ddb_allocation *new,
> +		     enum pipe pipe)
> +{
> +	if (memcmp(&old->pipe[pipe], &new->pipe[pipe],
> +		   sizeof(old->pipe[pipe])) != 0 ||
> +	    memcmp(&old->plane[pipe], &new->plane[pipe],
> +		   sizeof(old->plane[pipe])) != 0 ||
> +	    memcmp(&old->y_plane[pipe], &new->y_plane[pipe],
> +		   sizeof(old->y_plane[pipe])) != 0)
> +		return true;

I think I may have misled you when we talked on IRC the other day.
Given the assumption that proper flushing happens during vblank evasion
(via the update_{primary,plane,cursor} functions) that should cover all
of our flushing needs except for the intra-pipe DDB changes where we
need special ordering.  So given that this patch isn't yet tackling the
problems with inter-pipe DDB and is only concerned with cases where the
list of active CRTC's isn't changing, I believe you only need to test
the pipe allocation here and the {plane,y_plane} allocations shouldn't
really matter.  Even if the plane allocations change, I think we should
still have a sequence of:

        update_wm() {
                write WM's
                write DDB
        }
        flush_wm_values() {
                skip flushing because DDB pipe[] alloc didn't change
        }
        vblank evasion {
                update_*() {
                        write plane registers
                        flush (plane, WM, and DDB)
                }
        }

Actually, I feel we could almost drop the skl_flush_wm_values() function
completely in this patch.  Even in the cross-pipe allocation change case
all pipes would get flushed they'd just be flushed in the wrong order,
possibly causing underruns.  However the way we're handling flushing
right now is already wrong and can/will cause underruns, so we wouldn't
really be making the situation worse than it already is, just a
different kind of wrong.  Then it would be simpler to follow up with
another patch that handles all of the pipe updates in the proper order
to solve that final problem.


Matt

> +
> +	return false;
> +}
> +
>  static int
>  skl_compute_ddb(struct drm_atomic_state *state)
>  {
> @@ -3900,7 +3922,8 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
>  	struct intel_crtc *intel_crtc;
> -	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
> +	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> +	struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
>  	uint32_t realloc_pipes = pipes_modified(state);
>  	int ret;
>  
> @@ -3938,9 +3961,13 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  		if (IS_ERR(cstate))
>  			return PTR_ERR(cstate);
>  
> -		ret = skl_allocate_pipe_ddb(cstate, ddb);
> +		ret = skl_allocate_pipe_ddb(cstate, new_ddb);
>  		if (ret)
>  			return ret;
> +
> +		if (!intel_state->wm_results.ddb_changed &&
> +		    skl_pipe_ddb_changed(old_ddb, new_ddb, intel_crtc->pipe))
> +			intel_state->wm_results.ddb_changed = true;
>  	}
>  
>  	return 0;
> -- 
> 2.7.4
> 

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* Re: [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation
@ 2016-07-21 20:48     ` Matt Roper
  0 siblings, 0 replies; 19+ messages in thread
From: Matt Roper @ 2016-07-21 20:48 UTC (permalink / raw)
  To: Lyude
  Cc: intel-gfx, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

On Thu, Jul 21, 2016 at 03:23:38PM -0400, Lyude wrote:
> Manual pipe flushes are only necessary in order to make sure that we prevent
> pipes with changed ddb allocations from overlapping from one another at
> any point in time. Additionally, forcing us to wait for the next vblank
> every time we have to update the watermark values because the cursor was
> moving between screens will introduce a rather noticable lag for users.
> 
> Signed-off-by: Lyude <cpaul@redhat.com>
> Cc: stable@vger.kernel.org
> Cc: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h |  1 +
>  drivers/gpu/drm/i915/intel_pm.c | 31 +++++++++++++++++++++++++++++--
>  2 files changed, 30 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c97724d..9e1e045 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1597,6 +1597,7 @@ struct skl_ddb_allocation {
>  
>  struct skl_wm_values {
>  	unsigned dirty_pipes;
> +	bool ddb_changed;
>  	struct skl_ddb_allocation ddb;
>  	uint32_t wm_linetime[I915_MAX_PIPES];
>  	uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8];
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 56ddd71..55237ea 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3789,6 +3789,12 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
>  	new_ddb = &new_values->ddb;
>  	cur_ddb = &dev_priv->wm.skl_hw.ddb;
>  
> +	/* We only ever need to flush when the ddb allocations change */

I'd expand the comment a bit here since the logic is non-obvious.  In
general, we could still have WM changes (which need a flush) even if the
DDB doesn't change.  However in such cases, we'll be doing a normal
flush as part of update_plane, update_primary_plane, or update_cursor so
there's no need to do an extra, early flush here.  The whole three-step
flush dance is only needed to ensure proper inter-pipe ordering when the
inter-pipe DDB allocation changes; the three-step handling we have here
still isn't happening at the right time during the atomic commit, but
fixing that up is something that one of your later patches will
presumably address.

> +	if (!new_values->ddb_changed)
> +		return;
> +
> +	new_values->ddb_changed = false;
> +
>  	/*
>  	 * First pass: flush the pipes with the new allocation contained into
>  	 * the old space.
> @@ -3893,6 +3899,22 @@ pipes_modified(struct drm_atomic_state *state)
>  	return ret;
>  }
>  
> +static bool
> +skl_pipe_ddb_changed(struct skl_ddb_allocation *old,
> +		     struct skl_ddb_allocation *new,
> +		     enum pipe pipe)
> +{
> +	if (memcmp(&old->pipe[pipe], &new->pipe[pipe],
> +		   sizeof(old->pipe[pipe])) != 0 ||
> +	    memcmp(&old->plane[pipe], &new->plane[pipe],
> +		   sizeof(old->plane[pipe])) != 0 ||
> +	    memcmp(&old->y_plane[pipe], &new->y_plane[pipe],
> +		   sizeof(old->y_plane[pipe])) != 0)
> +		return true;

I think I may have misled you when we talked on IRC the other day.
Given the assumption that proper flushing happens during vblank evasion
(via the update_{primary,plane,cursor} functions) that should cover all
of our flushing needs except for the intra-pipe DDB changes where we
need special ordering.  So given that this patch isn't yet tackling the
problems with inter-pipe DDB and is only concerned with cases where the
list of active CRTC's isn't changing, I believe you only need to test
the pipe allocation here and the {plane,y_plane} allocations shouldn't
really matter.  Even if the plane allocations change, I think we should
still have a sequence of:

        update_wm() {
                write WM's
                write DDB
        }
        flush_wm_values() {
                skip flushing because DDB pipe[] alloc didn't change
        }
        vblank evasion {
                update_*() {
                        write plane registers
                        flush (plane, WM, and DDB)
                }
        }

Actually, I feel we could almost drop the skl_flush_wm_values() function
completely in this patch.  Even in the cross-pipe allocation change case
all pipes would get flushed they'd just be flushed in the wrong order,
possibly causing underruns.  However the way we're handling flushing
right now is already wrong and can/will cause underruns, so we wouldn't
really be making the situation worse than it already is, just a
different kind of wrong.  Then it would be simpler to follow up with
another patch that handles all of the pipe updates in the proper order
to solve that final problem.


Matt

> +
> +	return false;
> +}
> +
>  static int
>  skl_compute_ddb(struct drm_atomic_state *state)
>  {
> @@ -3900,7 +3922,8 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
>  	struct intel_crtc *intel_crtc;
> -	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
> +	struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> +	struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
>  	uint32_t realloc_pipes = pipes_modified(state);
>  	int ret;
>  
> @@ -3938,9 +3961,13 @@ skl_compute_ddb(struct drm_atomic_state *state)
>  		if (IS_ERR(cstate))
>  			return PTR_ERR(cstate);
>  
> -		ret = skl_allocate_pipe_ddb(cstate, ddb);
> +		ret = skl_allocate_pipe_ddb(cstate, new_ddb);
>  		if (ret)
>  			return ret;
> +
> +		if (!intel_state->wm_results.ddb_changed &&
> +		    skl_pipe_ddb_changed(old_ddb, new_ddb, intel_crtc->pipe))
> +			intel_state->wm_results.ddb_changed = true;
>  	}
>  
>  	return 0;
> -- 
> 2.7.4
> 

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* Re: [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates
  2016-07-21 19:23   ` Lyude
  (?)
@ 2016-07-21 20:57     ` Matt Roper
  -1 siblings, 0 replies; 19+ messages in thread
From: Matt Roper @ 2016-07-21 20:57 UTC (permalink / raw)
  To: Lyude
  Cc: intel-gfx, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

On Thu, Jul 21, 2016 at 03:23:40PM -0400, Lyude wrote:
> Thanks to Ville for suggesting this as a potential solution to pipe
> underruns on Skylake.
> 
> On Skylake all of the registers for configuring planes, including the
> registers for configuring their watermarks, are double buffered. New
> values written to them won't take effect until said registers are
> "armed", which is done by writing to the PLANE_SURF (or in the case of
> cursor planes, the CURBASE register) register.
> 
> With this in mind, up until now we've been updating watermarks on skl
> like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
>   or
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
> Now we update watermarks atomically like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks() (wm values aren't written yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - write new wm values
>         - end vblank evasion
>   }
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks() (actual wm values aren't written
>           yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
> 	- write new wm values
>         - end vblank evasion
>   }
> 
> So this patch moves all of the watermark writes into the right place;
> inside of the vblank evasion where we update all of the registers for
> each plane. While this patch doesn't fix everything, it does allow us to
> update the watermark values in the way the hardware expects us to.
> 
> Changes since original patch series:
>  - Remove mutex_lock/mutex_unlock since they don't do anything and we're
>    not touching global state
>  - Move skl_write_cursor_wm/skl_write_plane_wm functions into
>    intel_pm.c, make externally visible
>  - Add skl_write_plane_wm calls to skl_update_plane
>  - Fix conditional for for loop in skl_write_plane_wm (level < max_level
>    should be level <= max_level)
>  - Make diagram in commit more accurate to what's actually happening
>  - Add Fixes:
> 
> Changes since v1:
>  - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
>    then just Skylake
>  - Update description to make it clear this patch doesn't fix everything
>  - Check if pipes were actually changed before writing watermarks
> 
> Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
> Signed-off-by: Lyude <cpaul@redhat.com>
> Cc: stable@vger.kernel.org
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c |  5 ++++
>  drivers/gpu/drm/i915/intel_drv.h     |  2 ++
>  drivers/gpu/drm/i915/intel_pm.c      | 54 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/intel_sprite.c  |  2 ++
>  4 files changed, 49 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 78beb7e..d93d014 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3031,6 +3031,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  	intel_crtc->adjusted_x = x_offset;
>  	intel_crtc->adjusted_y = y_offset;
>  
> +	skl_write_plane_wm(intel_crtc, 0);
> +
>  	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
>  	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
>  	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
> @@ -10242,6 +10244,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
>  	int pipe = intel_crtc->pipe;
>  	uint32_t cntl = 0;
>  
> +	if (IS_GEN9(dev_priv))
> +		skl_write_cursor_wm(intel_crtc);
> +
>  	if (plane_state && plane_state->visible) {
>  		cntl = MCURSOR_GAMMA_ENABLE;
>  		switch (plane_state->base.crtc_w) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e74d851..f1f54d9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1709,6 +1709,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
>  void skl_wm_get_hw_state(struct drm_device *dev);
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
>  			  struct skl_ddb_allocation *ddb /* out */);
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc);
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc, int plane);
>  uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
>  bool ilk_disable_lp_wm(struct drm_device *dev);
>  int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 9421d92..41f379b 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3680,6 +3680,45 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
>  		I915_WRITE(reg, 0);
>  }
>  
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> +			int plane)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(PLANE_WM(pipe, plane, level),
> +			   wm->plane[pipe][plane][level]);
> +	}
> +	I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);

I think we might as well write the DDB changes in this function too.
The DDB and WM's really need to be written in the same vblank, and our
three-step pipe flushing isn't really doing the right thing yet anyway.

After that we'd just need a final patch #5 of this series to change our
pipe iteration order (and include the necessary pipe vblank waits).

> +}
> +
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(CUR_WM(pipe, level),
> +			   wm->plane[pipe][PLANE_CURSOR][level]);
> +	}
> +	I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
> +}
> +
>  static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  				const struct skl_wm_values *new)
>  {
> @@ -3687,7 +3726,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  	struct intel_crtc *crtc;
>  
>  	for_each_intel_crtc(dev, crtc) {
> -		int i, level, max_level = ilk_wm_max_level(dev);
> +		int i;
>  		enum pipe pipe = crtc->pipe;
>  
>  		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
> @@ -3697,19 +3736,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  
>  		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);

This probably needs to be moved under vblank evasion as well, otherwise
it can get updated vblank(s) earlier than the rest of the registers are
updated.


Matt

>  
> -		for (level = 0; level <= max_level; level++) {
> -			for (i = 0; i < intel_num_planes(crtc); i++)
> -				I915_WRITE(PLANE_WM(pipe, i, level),
> -					   new->plane[pipe][i][level]);
> -			I915_WRITE(CUR_WM(pipe, level),
> -				   new->plane[pipe][PLANE_CURSOR][level]);
> -		}
> -		for (i = 0; i < intel_num_planes(crtc); i++)
> -			I915_WRITE(PLANE_WM_TRANS(pipe, i),
> -				   new->plane_trans[pipe][i]);
> -		I915_WRITE(CUR_WM_TRANS(pipe),
> -			   new->plane_trans[pipe][PLANE_CURSOR]);
> -
>  		for (i = 0; i < intel_num_planes(crtc); i++) {
>  			skl_ddb_entry_write(dev_priv,
>  					    PLANE_BUF_CFG(pipe, i),
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 0de935a..50026f1 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -238,6 +238,8 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	crtc_w--;
>  	crtc_h--;
>  
> +	skl_write_plane_wm(to_intel_crtc(crtc_state->base.crtc), plane);
> +
>  	if (key->flags) {
>  		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
>  		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
> -- 
> 2.7.4
> 

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* Re: [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates
@ 2016-07-21 20:57     ` Matt Roper
  0 siblings, 0 replies; 19+ messages in thread
From: Matt Roper @ 2016-07-21 20:57 UTC (permalink / raw)
  To: Lyude
  Cc: intel-gfx, stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

On Thu, Jul 21, 2016 at 03:23:40PM -0400, Lyude wrote:
> Thanks to Ville for suggesting this as a potential solution to pipe
> underruns on Skylake.
> 
> On Skylake all of the registers for configuring planes, including the
> registers for configuring their watermarks, are double buffered. New
> values written to them won't take effect until said registers are
> "armed", which is done by writing to the PLANE_SURF (or in the case of
> cursor planes, the CURBASE register) register.
> 
> With this in mind, up until now we've been updating watermarks on skl
> like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
>   or
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
> Now we update watermarks atomically like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks() (wm values aren't written yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - write new wm values
>         - end vblank evasion
>   }
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks() (actual wm values aren't written
>           yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
> 	- write new wm values
>         - end vblank evasion
>   }
> 
> So this patch moves all of the watermark writes into the right place;
> inside of the vblank evasion where we update all of the registers for
> each plane. While this patch doesn't fix everything, it does allow us to
> update the watermark values in the way the hardware expects us to.
> 
> Changes since original patch series:
>  - Remove mutex_lock/mutex_unlock since they don't do anything and we're
>    not touching global state
>  - Move skl_write_cursor_wm/skl_write_plane_wm functions into
>    intel_pm.c, make externally visible
>  - Add skl_write_plane_wm calls to skl_update_plane
>  - Fix conditional for for loop in skl_write_plane_wm (level < max_level
>    should be level <= max_level)
>  - Make diagram in commit more accurate to what's actually happening
>  - Add Fixes:
> 
> Changes since v1:
>  - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
>    then just Skylake
>  - Update description to make it clear this patch doesn't fix everything
>  - Check if pipes were actually changed before writing watermarks
> 
> Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
> Signed-off-by: Lyude <cpaul@redhat.com>
> Cc: stable@vger.kernel.org
> Cc: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c |  5 ++++
>  drivers/gpu/drm/i915/intel_drv.h     |  2 ++
>  drivers/gpu/drm/i915/intel_pm.c      | 54 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/intel_sprite.c  |  2 ++
>  4 files changed, 49 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 78beb7e..d93d014 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3031,6 +3031,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  	intel_crtc->adjusted_x = x_offset;
>  	intel_crtc->adjusted_y = y_offset;
>  
> +	skl_write_plane_wm(intel_crtc, 0);
> +
>  	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
>  	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
>  	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
> @@ -10242,6 +10244,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
>  	int pipe = intel_crtc->pipe;
>  	uint32_t cntl = 0;
>  
> +	if (IS_GEN9(dev_priv))
> +		skl_write_cursor_wm(intel_crtc);
> +
>  	if (plane_state && plane_state->visible) {
>  		cntl = MCURSOR_GAMMA_ENABLE;
>  		switch (plane_state->base.crtc_w) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e74d851..f1f54d9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1709,6 +1709,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
>  void skl_wm_get_hw_state(struct drm_device *dev);
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
>  			  struct skl_ddb_allocation *ddb /* out */);
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc);
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc, int plane);
>  uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
>  bool ilk_disable_lp_wm(struct drm_device *dev);
>  int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 9421d92..41f379b 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3680,6 +3680,45 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
>  		I915_WRITE(reg, 0);
>  }
>  
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> +			int plane)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(PLANE_WM(pipe, plane, level),
> +			   wm->plane[pipe][plane][level]);
> +	}
> +	I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);

I think we might as well write the DDB changes in this function too.
The DDB and WM's really need to be written in the same vblank, and our
three-step pipe flushing isn't really doing the right thing yet anyway.

After that we'd just need a final patch #5 of this series to change our
pipe iteration order (and include the necessary pipe vblank waits).

> +}
> +
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(CUR_WM(pipe, level),
> +			   wm->plane[pipe][PLANE_CURSOR][level]);
> +	}
> +	I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
> +}
> +
>  static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  				const struct skl_wm_values *new)
>  {
> @@ -3687,7 +3726,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  	struct intel_crtc *crtc;
>  
>  	for_each_intel_crtc(dev, crtc) {
> -		int i, level, max_level = ilk_wm_max_level(dev);
> +		int i;
>  		enum pipe pipe = crtc->pipe;
>  
>  		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
> @@ -3697,19 +3736,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  
>  		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);

This probably needs to be moved under vblank evasion as well, otherwise
it can get updated vblank(s) earlier than the rest of the registers are
updated.


Matt

>  
> -		for (level = 0; level <= max_level; level++) {
> -			for (i = 0; i < intel_num_planes(crtc); i++)
> -				I915_WRITE(PLANE_WM(pipe, i, level),
> -					   new->plane[pipe][i][level]);
> -			I915_WRITE(CUR_WM(pipe, level),
> -				   new->plane[pipe][PLANE_CURSOR][level]);
> -		}
> -		for (i = 0; i < intel_num_planes(crtc); i++)
> -			I915_WRITE(PLANE_WM_TRANS(pipe, i),
> -				   new->plane_trans[pipe][i]);
> -		I915_WRITE(CUR_WM_TRANS(pipe),
> -			   new->plane_trans[pipe][PLANE_CURSOR]);
> -
>  		for (i = 0; i < intel_num_planes(crtc); i++) {
>  			skl_ddb_entry_write(dev_priv,
>  					    PLANE_BUF_CFG(pipe, i),
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 0de935a..50026f1 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -238,6 +238,8 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	crtc_w--;
>  	crtc_h--;
>  
> +	skl_write_plane_wm(to_intel_crtc(crtc_state->base.crtc), plane);
> +
>  	if (key->flags) {
>  		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
>  		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
> -- 
> 2.7.4
> 

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* Re: [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates
@ 2016-07-21 20:57     ` Matt Roper
  0 siblings, 0 replies; 19+ messages in thread
From: Matt Roper @ 2016-07-21 20:57 UTC (permalink / raw)
  To: Lyude
  Cc: dri-devel, Radhakrishna Sripada, intel-gfx, linux-kernel, stable,
	Hans de Goede, Daniel Vetter

On Thu, Jul 21, 2016 at 03:23:40PM -0400, Lyude wrote:
> Thanks to Ville for suggesting this as a potential solution to pipe
> underruns on Skylake.
> 
> On Skylake all of the registers for configuring planes, including the
> registers for configuring their watermarks, are double buffered. New
> values written to them won't take effect until said registers are
> "armed", which is done by writing to the PLANE_SURF (or in the case of
> cursor planes, the CURBASE register) register.
> 
> With this in mind, up until now we've been updating watermarks on skl
> like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
>   or
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks()
>      - {vblank happens; new watermarks + old plane values => underrun }
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - end vblank evasion
>   }
> 
> Now we update watermarks atomically like this:
> 
>   non-modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - intel_pre_plane_update:
>         - intel_update_watermarks() (wm values aren't written yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
>         - write new wm values
>         - end vblank evasion
>   }
> 
>   modeset {
>    - calculate (during atomic check phase)
>    - finish_atomic_commit:
>      - crtc_enable:
>         - intel_update_watermarks() (actual wm values aren't written
>           yet)
>      - drm_atomic_helper_commit_planes_on_crtc:
>         - start vblank evasion
>         - write new plane registers
> 	- write new wm values
>         - end vblank evasion
>   }
> 
> So this patch moves all of the watermark writes into the right place;
> inside of the vblank evasion where we update all of the registers for
> each plane. While this patch doesn't fix everything, it does allow us to
> update the watermark values in the way the hardware expects us to.
> 
> Changes since original patch series:
>  - Remove mutex_lock/mutex_unlock since they don't do anything and we're
>    not touching global state
>  - Move skl_write_cursor_wm/skl_write_plane_wm functions into
>    intel_pm.c, make externally visible
>  - Add skl_write_plane_wm calls to skl_update_plane
>  - Fix conditional for for loop in skl_write_plane_wm (level < max_level
>    should be level <= max_level)
>  - Make diagram in commit more accurate to what's actually happening
>  - Add Fixes:
> 
> Changes since v1:
>  - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
>    then just Skylake
>  - Update description to make it clear this patch doesn't fix everything
>  - Check if pipes were actually changed before writing watermarks
> 
> Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
> Signed-off-by: Lyude <cpaul@redhat.com>
> Cc: stable@vger.kernel.org
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c |  5 ++++
>  drivers/gpu/drm/i915/intel_drv.h     |  2 ++
>  drivers/gpu/drm/i915/intel_pm.c      | 54 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/intel_sprite.c  |  2 ++
>  4 files changed, 49 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 78beb7e..d93d014 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3031,6 +3031,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  	intel_crtc->adjusted_x = x_offset;
>  	intel_crtc->adjusted_y = y_offset;
>  
> +	skl_write_plane_wm(intel_crtc, 0);
> +
>  	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
>  	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
>  	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
> @@ -10242,6 +10244,9 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
>  	int pipe = intel_crtc->pipe;
>  	uint32_t cntl = 0;
>  
> +	if (IS_GEN9(dev_priv))
> +		skl_write_cursor_wm(intel_crtc);
> +
>  	if (plane_state && plane_state->visible) {
>  		cntl = MCURSOR_GAMMA_ENABLE;
>  		switch (plane_state->base.crtc_w) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e74d851..f1f54d9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1709,6 +1709,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
>  void skl_wm_get_hw_state(struct drm_device *dev);
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
>  			  struct skl_ddb_allocation *ddb /* out */);
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc);
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc, int plane);
>  uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
>  bool ilk_disable_lp_wm(struct drm_device *dev);
>  int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 9421d92..41f379b 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3680,6 +3680,45 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
>  		I915_WRITE(reg, 0);
>  }
>  
> +void skl_write_plane_wm(struct intel_crtc *intel_crtc,
> +			int plane)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(PLANE_WM(pipe, plane, level),
> +			   wm->plane[pipe][plane][level]);
> +	}
> +	I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);

I think we might as well write the DDB changes in this function too.
The DDB and WM's really need to be written in the same vblank, and our
three-step pipe flushing isn't really doing the right thing yet anyway.

After that we'd just need a final patch #5 of this series to change our
pipe iteration order (and include the necessary pipe vblank waits).

> +}
> +
> +void skl_write_cursor_wm(struct intel_crtc *intel_crtc)
> +{
> +	struct drm_crtc *crtc = &intel_crtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct skl_wm_values *wm = &dev_priv->wm.skl_results;
> +	int level, max_level = ilk_wm_max_level(dev);
> +	enum pipe pipe = intel_crtc->pipe;
> +
> +	if (!(wm->dirty_pipes & drm_crtc_mask(crtc)))
> +		return;
> +
> +	for (level = 0; level <= max_level; level++) {
> +		I915_WRITE(CUR_WM(pipe, level),
> +			   wm->plane[pipe][PLANE_CURSOR][level]);
> +	}
> +	I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
> +}
> +
>  static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  				const struct skl_wm_values *new)
>  {
> @@ -3687,7 +3726,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  	struct intel_crtc *crtc;
>  
>  	for_each_intel_crtc(dev, crtc) {
> -		int i, level, max_level = ilk_wm_max_level(dev);
> +		int i;
>  		enum pipe pipe = crtc->pipe;
>  
>  		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
> @@ -3697,19 +3736,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
>  
>  		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);

This probably needs to be moved under vblank evasion as well, otherwise
it can get updated vblank(s) earlier than the rest of the registers are
updated.


Matt

>  
> -		for (level = 0; level <= max_level; level++) {
> -			for (i = 0; i < intel_num_planes(crtc); i++)
> -				I915_WRITE(PLANE_WM(pipe, i, level),
> -					   new->plane[pipe][i][level]);
> -			I915_WRITE(CUR_WM(pipe, level),
> -				   new->plane[pipe][PLANE_CURSOR][level]);
> -		}
> -		for (i = 0; i < intel_num_planes(crtc); i++)
> -			I915_WRITE(PLANE_WM_TRANS(pipe, i),
> -				   new->plane_trans[pipe][i]);
> -		I915_WRITE(CUR_WM_TRANS(pipe),
> -			   new->plane_trans[pipe][PLANE_CURSOR]);
> -
>  		for (i = 0; i < intel_num_planes(crtc); i++) {
>  			skl_ddb_entry_write(dev_priv,
>  					    PLANE_BUF_CFG(pipe, i),
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 0de935a..50026f1 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -238,6 +238,8 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	crtc_w--;
>  	crtc_h--;
>  
> +	skl_write_plane_wm(to_intel_crtc(crtc_state->base.crtc), plane);
> +
>  	if (key->flags) {
>  		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
>  		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
> -- 
> 2.7.4
> 

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* ✓ Ro.CI.BAT: success for drm/i915/skl: Finally fix watermarks (rev2)
  2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
                   ` (3 preceding siblings ...)
  2016-07-21 19:23   ` Lyude
@ 2016-07-22  7:09 ` Patchwork
  4 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2016-07-22  7:09 UTC (permalink / raw)
  To: cpaul; +Cc: intel-gfx

== Series Details ==

Series: drm/i915/skl: Finally fix watermarks (rev2)
URL   : https://patchwork.freedesktop.org/series/10108/
State : success

== Summary ==

Series 10108v2 drm/i915/skl: Finally fix watermarks
http://patchwork.freedesktop.org/api/1.0/series/10108/revisions/2/mbox


fi-hsw-i7-4770k  total:244  pass:216  dwarn:0   dfail:0   fail:8   skip:20 
fi-kbl-qkkr      total:244  pass:180  dwarn:29  dfail:0   fail:8   skip:27 
fi-skl-i5-6260u  total:244  pass:224  dwarn:0   dfail:0   fail:8   skip:12 
fi-skl-i7-6700k  total:244  pass:210  dwarn:0   dfail:0   fail:8   skip:26 
fi-snb-i7-2600   total:244  pass:196  dwarn:0   dfail:0   fail:8   skip:40 
ro-bdw-i5-5250u  total:244  pass:219  dwarn:4   dfail:0   fail:8   skip:13 
ro-bdw-i7-5557U  total:244  pass:220  dwarn:3   dfail:0   fail:8   skip:13 
ro-bdw-i7-5600u  total:244  pass:204  dwarn:0   dfail:0   fail:8   skip:32 
ro-bsw-n3050     total:218  pass:173  dwarn:0   dfail:0   fail:2   skip:42 
ro-byt-n2820     total:244  pass:197  dwarn:0   dfail:0   fail:9   skip:38 
ro-hsw-i3-4010u  total:244  pass:212  dwarn:0   dfail:0   fail:8   skip:24 
ro-hsw-i7-4770r  total:244  pass:212  dwarn:0   dfail:0   fail:8   skip:24 
ro-ilk-i7-620lm  total:244  pass:172  dwarn:0   dfail:0   fail:9   skip:63 
ro-ilk1-i5-650   total:239  pass:172  dwarn:0   dfail:0   fail:9   skip:58 
ro-ivb-i7-3770   total:244  pass:203  dwarn:0   dfail:0   fail:8   skip:33 
ro-skl3-i5-6260u total:244  pass:224  dwarn:0   dfail:0   fail:8   skip:12 
ro-snb-i7-2620M  total:244  pass:193  dwarn:0   dfail:0   fail:9   skip:42 

Results at /archive/results/CI_IGT_test/RO_Patchwork_1568/

cf82f46 drm-intel-nightly: 2016y-07m-21d-20h-43m-36s UTC integration manifest
a57d649 drm/i915/skl: Update plane watermarks atomically during plane updates
798089f drm/i915/skl: Fix extra whitespace in skl_flush_wm_values()
c44b984 drm/i915/skl: Only flush pipes when we change the ddb allocation
39e9b52 drm/i915/gen9: Only copy WM results for changed pipes to skl_hw

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

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

* Re: [Intel-gfx] [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation
  2016-07-21 19:23   ` Lyude
  (?)
  (?)
@ 2016-07-25  7:34   ` Maarten Lankhorst
  -1 siblings, 0 replies; 19+ messages in thread
From: Maarten Lankhorst @ 2016-07-25  7:34 UTC (permalink / raw)
  To: Lyude, intel-gfx, Matt Roper
  Cc: David Airlie, dri-devel, linux-kernel, stable, Hans de Goede,
	Daniel Vetter

Op 21-07-16 om 21:23 schreef Lyude:
> Manual pipe flushes are only necessary in order to make sure that we prevent
> pipes with changed ddb allocations from overlapping from one another at
> any point in time. Additionally, forcing us to wait for the next vblank
> every time we have to update the watermark values because the cursor was
> moving between screens will introduce a rather noticable lag for users.
This screams for a testcase in kms_cursor_legacy, when does this happen exactly?

I'm guessing it needs 2 screens, page flip on both and cursor update on both, one hiding the cursor other screen making it reappear..

~Maarten

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

* Re: [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw
  2016-07-21 19:23   ` Lyude
  (?)
@ 2016-07-25 13:01   ` Maarten Lankhorst
  -1 siblings, 0 replies; 19+ messages in thread
From: Maarten Lankhorst @ 2016-07-25 13:01 UTC (permalink / raw)
  To: Lyude, intel-gfx, Matt Roper
  Cc: stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

Op 21-07-16 om 21:23 schreef Lyude:
> From: Matt Roper <matthew.d.roper@intel.com>
>
> When we write watermark values to the hardware, those values are stored
> in dev_priv->wm.skl_hw.  However with recent watermark changes, the
> results structure we're copying from only contains valid watermark and
> DDB values for the pipes that are actually changing; the values for
> other pipes remain 0.  Thus a blind copy of the entire skl_wm_values
> structure will clobber the values for unchanged pipes...we need to be
> more selective and only copy over the values for the changing pipes.
>
> This mistake was hidden until recently due to another bug that caused us
> to erroneously re-calculate watermarks for all active pipes rather than
> changing pipes.  Only when that bug was fixed was the impact of this bug
> discovered (e.g., modesets failing with "Requested display configuration
> exceeds system watermark limitations" messages and leaving watermarks
> non-functional, even ones initiated by intel_fbdev_restore_mode).
>
> Changes since v1:
>  - Add a function for copying a pipe's wm values
>    (skl_copy_wm_for_pipe()) so we can reuse this later
Looks like I can hit this when I wrote some tests for patch 2 in this series.

testcase will be kms_cursor_legacy.2x-flip-vs-cursor-legacy, but I haven't committed the changes yet.

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

* Re: [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw
  2016-07-21 19:23   ` Lyude
@ 2016-07-26 14:21     ` Maarten Lankhorst
  -1 siblings, 0 replies; 19+ messages in thread
From: Maarten Lankhorst @ 2016-07-26 14:21 UTC (permalink / raw)
  To: Lyude, intel-gfx, Matt Roper
  Cc: stable, Ville Syrjälä,
	Daniel Vetter, Radhakrishna Sripada, Hans de Goede, Jani Nikula,
	David Airlie, dri-devel, linux-kernel

Op 21-07-16 om 21:23 schreef Lyude:
> From: Matt Roper <matthew.d.roper@intel.com>
>
> When we write watermark values to the hardware, those values are stored
> in dev_priv->wm.skl_hw.  However with recent watermark changes, the
> results structure we're copying from only contains valid watermark and
> DDB values for the pipes that are actually changing; the values for
> other pipes remain 0.  Thus a blind copy of the entire skl_wm_values
> structure will clobber the values for unchanged pipes...we need to be
> more selective and only copy over the values for the changing pipes.
>
> This mistake was hidden until recently due to another bug that caused us
> to erroneously re-calculate watermarks for all active pipes rather than
> changing pipes.  Only when that bug was fixed was the impact of this bug
> discovered (e.g., modesets failing with "Requested display configuration
> exceeds system watermark limitations" messages and leaving watermarks
> non-functional, even ones initiated by intel_fbdev_restore_mode).
>
> Changes since v1:
>  - Add a function for copying a pipe's wm values
>    (skl_copy_wm_for_pipe()) so we can reuse this later
>
> Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
> Fixes: 9b6130227495 ("drm/i915/gen9: Re-allocate DDB only for changed pipes")
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Lyude <cpaul@redhat.com>
> Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
> Cc: stable@vger.kernel.org
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
Testcase: kms_cursor_legacy.2x-flip-vs-cursor-legacy

For patch 2/4 too probably.

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

* Re: [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw
@ 2016-07-26 14:21     ` Maarten Lankhorst
  0 siblings, 0 replies; 19+ messages in thread
From: Maarten Lankhorst @ 2016-07-26 14:21 UTC (permalink / raw)
  To: Lyude, intel-gfx, Matt Roper
  Cc: Radhakrishna Sripada, dri-devel, linux-kernel, Hans de Goede,
	stable, Daniel Vetter

Op 21-07-16 om 21:23 schreef Lyude:
> From: Matt Roper <matthew.d.roper@intel.com>
>
> When we write watermark values to the hardware, those values are stored
> in dev_priv->wm.skl_hw.  However with recent watermark changes, the
> results structure we're copying from only contains valid watermark and
> DDB values for the pipes that are actually changing; the values for
> other pipes remain 0.  Thus a blind copy of the entire skl_wm_values
> structure will clobber the values for unchanged pipes...we need to be
> more selective and only copy over the values for the changing pipes.
>
> This mistake was hidden until recently due to another bug that caused us
> to erroneously re-calculate watermarks for all active pipes rather than
> changing pipes.  Only when that bug was fixed was the impact of this bug
> discovered (e.g., modesets failing with "Requested display configuration
> exceeds system watermark limitations" messages and leaving watermarks
> non-functional, even ones initiated by intel_fbdev_restore_mode).
>
> Changes since v1:
>  - Add a function for copying a pipe's wm values
>    (skl_copy_wm_for_pipe()) so we can reuse this later
>
> Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
> Fixes: 9b6130227495 ("drm/i915/gen9: Re-allocate DDB only for changed pipes")
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Lyude <cpaul@redhat.com>
> Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
> Cc: stable@vger.kernel.org
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
> Cc: Hans de Goede <hdegoede@redhat.com>
Testcase: kms_cursor_legacy.2x-flip-vs-cursor-legacy

For patch 2/4 too probably.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2016-07-26 14:23 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-21 19:23 [PATCH v2 0/4] drm/i915/skl: Finally fix watermarks Lyude
2016-07-21 19:23 ` [PATCH v2 1/4] drm/i915/gen9: Only copy WM results for changed pipes to skl_hw Lyude
2016-07-21 19:23   ` Lyude
2016-07-25 13:01   ` Maarten Lankhorst
2016-07-26 14:21   ` Maarten Lankhorst
2016-07-26 14:21     ` Maarten Lankhorst
2016-07-21 19:23 ` [PATCH v2 2/4] drm/i915/skl: Only flush pipes when we change the ddb allocation Lyude
2016-07-21 19:23   ` Lyude
2016-07-21 20:48   ` Matt Roper
2016-07-21 20:48     ` Matt Roper
2016-07-25  7:34   ` [Intel-gfx] " Maarten Lankhorst
2016-07-21 19:23 ` [PATCH v2 3/4] drm/i915/skl: Fix extra whitespace in skl_flush_wm_values() Lyude
2016-07-21 19:23   ` Lyude
2016-07-21 19:23 ` [PATCH v2 4/4] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
2016-07-21 19:23   ` Lyude
2016-07-21 20:57   ` Matt Roper
2016-07-21 20:57     ` Matt Roper
2016-07-21 20:57     ` Matt Roper
2016-07-22  7:09 ` ✓ Ro.CI.BAT: success for drm/i915/skl: Finally fix watermarks (rev2) Patchwork

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.