* [PATCH 0/6] drm/i915/skl: Finally fix watermarks
@ 2016-07-20 20:59 Lyude
2016-07-20 20:59 ` [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Lyude @ 2016-07-20 20:59 UTC (permalink / raw)
To: intel-gfx
Cc: Lyude, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Hans de Goede, Matt Roper, Jani Nikula,
David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
To Sebastian Reichel:
If this e-mail has the bizarre email address formatting issue you
noticed in the last patch series I sent please let me know. I haven't
gotten a chance to properly look at the e-mail you forwarded to me to
see what's causing the problem, but I double checked the Cc: line for
this e-mail manually before sending it out so hopefully I should be
good for now…
Anyway, onto the actual patch series:
Unfortunately as a few of you are aware, Skylake is still very prone to pipe
underruns. Most of this comes from not doing things atomically enough (e.g.
needing to ensure that we update watermarks with other plane attributes, not
forcefully flushing pipes until we need to, etc.). Now that I've finally got a
grasp on how double buffered registers, arming registers, etc. works on skl,
I've written up patches that fix all of the pipe underruns on Skylake I was
able to reproduce.
Of course, one of the prerequisites for this patch series to actually fix all
of the pipe underruns is the patch I previously submitted that added support
for Skylake's SAGV.
Originally this patch series left behind the issue of running into pipe
underruns when we disabled pipes, however I've now managed to fix that behavior
as well. As such I've renamed the patch series appropriately instead of just
incrementing the version.
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>
Lyude (5):
drm/i915/skl: Update plane watermarks atomically during plane updates
drm/i915/skl: Actually reuse wm values when pipes don't change
drm/i915/skl: Always wait for pipes to update after a flush
drm/i915/skl: Only flush pipes when we change the ddb allocation
drm/i915/skl: Fix extra whitespace in skl_flush_wm_values()
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 | 133 +++++++++++++++++++++++++++++------
drivers/gpu/drm/i915/intel_sprite.c | 2 +
5 files changed, 120 insertions(+), 23 deletions(-)
--
2.7.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates
2016-07-20 20:59 [PATCH 0/6] drm/i915/skl: Finally fix watermarks Lyude
@ 2016-07-20 20:59 ` Lyude
2016-07-20 23:12 ` Matt Roper
2016-07-20 20:59 ` [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change Lyude
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Lyude @ 2016-07-20 20:59 UTC (permalink / raw)
To: intel-gfx
Cc: Lyude, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Matt Roper, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
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
}
Which is more of a step in the right direction to fixing all of the
underrun issues we're currently seeing with skl
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:
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> <cpaul@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 | 48 +++++++++++++++++++++++++-----------
drivers/gpu/drm/i915/intel_sprite.c | 2 ++
4 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 78beb7e..c0d2074 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_SKYLAKE(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 64d628c..fa86bea 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3680,6 +3680,39 @@ 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;
+
+ 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;
+
+ 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 +3720,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 +3730,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] 9+ messages in thread
* [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change
2016-07-20 20:59 [PATCH 0/6] drm/i915/skl: Finally fix watermarks Lyude
2016-07-20 20:59 ` [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
@ 2016-07-20 20:59 ` Lyude
2016-07-20 23:26 ` Matt Roper
2016-07-20 21:00 ` [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush Lyude
2016-07-20 21:00 ` [PATCH 5/6] drm/i915/skl: Only flush pipes when we change the ddb allocation Lyude
3 siblings, 1 reply; 9+ messages in thread
From: Lyude @ 2016-07-20 20:59 UTC (permalink / raw)
To: intel-gfx
Cc: Lyude, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Matt Roper, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
Up until now we've actually been making the mistake of leaving the
watermark results for each pipe completely blank in skl_compute_wm()
when they haven't changed, fix this.
Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
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> <cpaul@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
---
drivers/gpu/drm/i915/intel_pm.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b7d4af1..788db86 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3987,10 +3987,13 @@ skl_copy_wm_for_pipe(struct skl_wm_values *dst,
static int
skl_compute_wm(struct drm_atomic_state *state)
{
+ struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_crtc *crtc;
struct drm_crtc_state *cstate;
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct skl_wm_values *results = &intel_state->wm_results;
+ struct skl_wm_values *hw_wm = &dev_priv->wm.skl_hw;
struct skl_pipe_wm *pipe_wm;
bool changed = false;
int ret, i;
@@ -4039,12 +4042,14 @@ skl_compute_wm(struct drm_atomic_state *state)
if (changed)
results->dirty_pipes |= drm_crtc_mask(crtc);
- if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
+ if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0) {
/* This pipe's WM's did not change */
+ skl_copy_wm_for_pipe(results, hw_wm, intel_crtc->pipe);
continue;
+ }
intel_cstate->update_wm_pre = true;
- skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
+ skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
}
return 0;
--
2.7.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush
2016-07-20 20:59 [PATCH 0/6] drm/i915/skl: Finally fix watermarks Lyude
2016-07-20 20:59 ` [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
2016-07-20 20:59 ` [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change Lyude
@ 2016-07-20 21:00 ` Lyude
2016-07-21 0:27 ` Matt Roper
2016-07-20 21:00 ` [PATCH 5/6] drm/i915/skl: Only flush pipes when we change the ddb allocation Lyude
3 siblings, 1 reply; 9+ messages in thread
From: Lyude @ 2016-07-20 21:00 UTC (permalink / raw)
To: intel-gfx
Cc: Lyude, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Matt Roper, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
As we've learned, all watermark updates on Skylake have to be strictly
atomic or things fail. While the bspec doesn't mandate that we need to
wait for pipes to finish after the third iteration of flushes, not doing
so gives us the opportunity to break this atomicity later. This example
assumes that we're lucky enough not to be interrupted by the scheduler
at any point during this:
- Start with pipe A and pipe B enabled
- Enable pipe C
- Flush pipe A in pass 1, wait until update finishes
- Flush pipe B in pass 3, continue without waiting for next vblank
- Start another wm update
- We enter the next vblank for pipe B before we finish writing all the
vm values
- *Underrun*
As such, we always need to wait for each pipe we flush to update so as
to never break this atomicity.
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
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> <cpaul@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
---
drivers/gpu/drm/i915/intel_pm.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 788db86..2e31df4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3859,8 +3859,11 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
/*
* Third pass: flush the pipes that got more space allocated.
*
- * We don't need to actively wait for the update here, next vblank
- * will just get more DDB space with the correct WM values.
+ * While the hardware doesn't require to wait for the next vblank here,
+ * continuing before the pipe finishes updating could result in us
+ * trying to update the wm values again before the pipe finishes
+ * updating, which results in the hardware using intermediate wm values
+ * and subsequently underrunning pipes.
*/
for_each_intel_crtc(dev, crtc) {
if (!crtc->active)
@@ -3876,6 +3879,16 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
continue;
skl_wm_flush_pipe(dev_priv, pipe, 3);
+
+ /*
+ * The only time we can get away with not waiting for an update
+ * is when we just enabled the pipe, e.g. when it doesn't have
+ * vblanks enabled anyway.
+ */
+ if (drm_crtc_vblank_get(&crtc->base) == 0) {
+ intel_wait_for_vblank(dev, pipe);
+ drm_crtc_vblank_put(&crtc->base);
+ }
}
}
--
2.7.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/6] drm/i915/skl: Only flush pipes when we change the ddb allocation
2016-07-20 20:59 [PATCH 0/6] drm/i915/skl: Finally fix watermarks Lyude
` (2 preceding siblings ...)
2016-07-20 21:00 ` [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush Lyude
@ 2016-07-20 21:00 ` Lyude
3 siblings, 0 replies; 9+ messages in thread
From: Lyude @ 2016-07-20 21:00 UTC (permalink / raw)
To: intel-gfx
Cc: Lyude, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Matt Roper, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
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> <cpaul@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 2e31df4..4178bdd 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3809,6 +3809,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.
@@ -3926,6 +3932,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)
{
@@ -3933,7 +3955,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;
@@ -3971,9 +3994,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] 9+ messages in thread
* Re: [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates
2016-07-20 20:59 ` [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
@ 2016-07-20 23:12 ` Matt Roper
0 siblings, 0 replies; 9+ messages in thread
From: Matt Roper @ 2016-07-20 23:12 UTC (permalink / raw)
To: Lyude
Cc: intel-gfx, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
On Wed, Jul 20, 2016 at 04:59:57PM -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
> }
>
> Which is more of a step in the right direction to fixing all of the
> underrun issues we're currently seeing with skl
So my understanding of this patch is that it moves watermark value
writes to the right place (inside the vblank evasion where we write the
rest of the plane registers), but we aren't tackling the problems with
DDB writes & flushing order yet, so we don't expect everything to be
fixed yet, right? You might want to clarify that slightly in the commit
message here.
One other comment inline below.
>
> 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:
>
> 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> <cpaul@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 | 48 +++++++++++++++++++++++++-----------
> drivers/gpu/drm/i915/intel_sprite.c | 2 ++
> 4 files changed, 43 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 78beb7e..c0d2074 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_SKYLAKE(dev_priv))
I believe this should be IS_GEN9 so that it applies to BXT and KBL too.
Matt
> + 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 64d628c..fa86bea 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3680,6 +3680,39 @@ 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;
> +
> + 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;
> +
> + 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 +3720,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 +3730,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
>
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change
2016-07-20 20:59 ` [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change Lyude
@ 2016-07-20 23:26 ` Matt Roper
0 siblings, 0 replies; 9+ messages in thread
From: Matt Roper @ 2016-07-20 23:26 UTC (permalink / raw)
To: Lyude
Cc: intel-gfx, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
On Wed, Jul 20, 2016 at 04:59:59PM -0400, Lyude wrote:
> Up until now we've actually been making the mistake of leaving the
> watermark results for each pipe completely blank in skl_compute_wm()
> when they haven't changed, fix this.
Should this be moved before patch #1? With the existing code we don't
try to re-write watermark registers if they aren't changing, so leaving
them at zero should be safe. I think we want to make this change before
we start re-writing non-dirty watermarks. Alternatively, we could just
add the dirty bit test to the appropriate places in patch #1 and not
worry about copying over the unchanged values.
Matt
>
> Fixes: 734fa01f3a17 ("drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)")
> 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> <cpaul@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Lyude <cpaul@redhat.com>
> ---
> drivers/gpu/drm/i915/intel_pm.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index b7d4af1..788db86 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3987,10 +3987,13 @@ skl_copy_wm_for_pipe(struct skl_wm_values *dst,
> static int
> skl_compute_wm(struct drm_atomic_state *state)
> {
> + struct drm_device *dev = state->dev;
> + struct drm_i915_private *dev_priv = to_i915(dev);
> struct drm_crtc *crtc;
> struct drm_crtc_state *cstate;
> struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> struct skl_wm_values *results = &intel_state->wm_results;
> + struct skl_wm_values *hw_wm = &dev_priv->wm.skl_hw;
> struct skl_pipe_wm *pipe_wm;
> bool changed = false;
> int ret, i;
> @@ -4039,12 +4042,14 @@ skl_compute_wm(struct drm_atomic_state *state)
> if (changed)
> results->dirty_pipes |= drm_crtc_mask(crtc);
>
> - if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
> + if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0) {
> /* This pipe's WM's did not change */
> + skl_copy_wm_for_pipe(results, hw_wm, intel_crtc->pipe);
> continue;
> + }
>
> intel_cstate->update_wm_pre = true;
> - skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
> + skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
> }
>
> return 0;
> --
> 2.7.4
>
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush
2016-07-20 21:00 ` [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush Lyude
@ 2016-07-21 0:27 ` Matt Roper
2016-07-21 17:01 ` Lyude Paul
0 siblings, 1 reply; 9+ messages in thread
From: Matt Roper @ 2016-07-21 0:27 UTC (permalink / raw)
To: Lyude
Cc: intel-gfx, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
On Wed, Jul 20, 2016 at 05:00:00PM -0400, Lyude wrote:
> As we've learned, all watermark updates on Skylake have to be strictly
> atomic or things fail. While the bspec doesn't mandate that we need to
> wait for pipes to finish after the third iteration of flushes, not doing
> so gives us the opportunity to break this atomicity later. This example
> assumes that we're lucky enough not to be interrupted by the scheduler
> at any point during this:
>
> - Start with pipe A and pipe B enabled
> - Enable pipe C
> - Flush pipe A in pass 1, wait until update finishes
> - Flush pipe B in pass 3, continue without waiting for next vblank
> - Start another wm update
> - We enter the next vblank for pipe B before we finish writing all the
> vm values
> - *Underrun*
>
> As such, we always need to wait for each pipe we flush to update so as
> to never break this atomicity.
I'm not sure I follow this commit. If we're enabling a new pipe, the
the allocation for A and B are generally going to shrink, so they'll
usually be flushed in passes 1 and 2, not 3.
My understanding is that the problem that still remains (now that your
first three patches have made progress towards fixing underruns) is that
our DDB updates and flushes (which come from update_watermarks) happen
pre-evasion, whereas the watermarks themselves now happen under evasion.
We really want both the new DDB value and the new watermark value to be
written together and take effect on the same vblank. I think the
problem is that you might have a shrinking DDB allocation (e.g., because
a new pipe was added or you changed a mode that changed the DDB balance)
which some of the existing WM values exceed. You can have a sequence
like this:
- update_wm:
- write new (smaller) DDB
- flush DDB
- vblank happens, old (big) wm + new (small) ddb = underrun
- vblank evasion:
- write new plane regs and WM's
- flush
- post-evasion vblank happens, underrun is corrected
I think ultimately we want to move the DDB register writes into the
update functions that happen under evasion, just like you did for the WM
registers. However just doing this the straightforward way won't
satisfy our requirements about pipe update ordering (the three passes
you see today in skl_flush_wm_values). To make that work, I think the
general approach is that we need to basically replace the
for_each_crtc_in_state() loop in intel_atomic_commit_tail() with some
new CRTC iterator that processes CRTC's in a more intelligent ordering.
We've computed our DDB changes during the atomic check phase, so we
already know which allocations are shrinking, growing, etc. and we
should be able to calculate an appropriate CRTC ordering at the same
time.
With an intelligent CRTC iterator that follows the pre-computed pipe
ordering rules (and adds the necessary vblank waits between each
"phase"), I think we should be able to just write both DDB and WM values
in the skl_update_primary_plane() and similar functions and let the
existing flushes that happen take care of flushing them out at the
appropriate time. Of course I've kicked that idea around in my head for
a while, but haven't had time to actually write any code for it, so I
may be completely overlooking some stumbling block that makes it much
more complicated than I'm envisioning.
Matt
>
> Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
> 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> <cpaul@redhat.com>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> ---
> drivers/gpu/drm/i915/intel_pm.c | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 788db86..2e31df4 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3859,8 +3859,11 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
> /*
> * Third pass: flush the pipes that got more space allocated.
> *
> - * We don't need to actively wait for the update here, next vblank
> - * will just get more DDB space with the correct WM values.
> + * While the hardware doesn't require to wait for the next vblank here,
> + * continuing before the pipe finishes updating could result in us
> + * trying to update the wm values again before the pipe finishes
> + * updating, which results in the hardware using intermediate wm values
> + * and subsequently underrunning pipes.
> */
> for_each_intel_crtc(dev, crtc) {
> if (!crtc->active)
> @@ -3876,6 +3879,16 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
> continue;
>
> skl_wm_flush_pipe(dev_priv, pipe, 3);
> +
> + /*
> + * The only time we can get away with not waiting for an update
> + * is when we just enabled the pipe, e.g. when it doesn't have
> + * vblanks enabled anyway.
> + */
> + if (drm_crtc_vblank_get(&crtc->base) == 0) {
> + intel_wait_for_vblank(dev, pipe);
> + drm_crtc_vblank_put(&crtc->base);
> + }
> }
> }
>
> --
> 2.7.4
>
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush
2016-07-21 0:27 ` Matt Roper
@ 2016-07-21 17:01 ` Lyude Paul
0 siblings, 0 replies; 9+ messages in thread
From: Lyude Paul @ 2016-07-21 17:01 UTC (permalink / raw)
To: Matt Roper
Cc: intel-gfx, stable, Ville Syrjälä, Daniel Vetter,
Radhakrishna Sripada, Jani Nikula, David Airlie,
open list:INTEL DRM DRIVERS (excluding Poulsbo, Moorestow...), linux-kernel@vger.kernel.org (open list)
Two things for this one:
1. I completely messed up the description on this patchset, this was for fixing
underruns on pipe disablement. I'm impressed I wrote up that whole description
without realizing that at all, lol.
2. This patch may not actually be necessary. On the original git branch I was
testing this on it was required to prevent underruns on pipe disables, but
trying this on nightly I don't seem to reproduce those underruns even when I
remove this patch, so I guess we can drop this from the series
On Wed, 2016-07-20 at 17:27 -0700, Matt Roper wrote:
> On Wed, Jul 20, 2016 at 05:00:00PM -0400, Lyude wrote:
> >
> > As we've learned, all watermark updates on Skylake have to be strictly
> > atomic or things fail. While the bspec doesn't mandate that we need to
> > wait for pipes to finish after the third iteration of flushes, not doing
> > so gives us the opportunity to break this atomicity later. This example
> > assumes that we're lucky enough not to be interrupted by the scheduler
> > at any point during this:
> >
> > - Start with pipe A and pipe B enabled
> > - Enable pipe C
> > - Flush pipe A in pass 1, wait until update finishes
> > - Flush pipe B in pass 3, continue without waiting for next vblank
> > - Start another wm update
> > - We enter the next vblank for pipe B before we finish writing all the
> > vm values
> > - *Underrun*
> >
> > As such, we always need to wait for each pipe we flush to update so as
> > to never break this atomicity.
>
> I'm not sure I follow this commit. If we're enabling a new pipe, the
> the allocation for A and B are generally going to shrink, so they'll
> usually be flushed in passes 1 and 2, not 3.
>
> My understanding is that the problem that still remains (now that your
> first three patches have made progress towards fixing underruns) is that
> our DDB updates and flushes (which come from update_watermarks) happen
> pre-evasion, whereas the watermarks themselves now happen under evasion.
> We really want both the new DDB value and the new watermark value to be
> written together and take effect on the same vblank. I think the
> problem is that you might have a shrinking DDB allocation (e.g., because
> a new pipe was added or you changed a mode that changed the DDB balance)
> which some of the existing WM values exceed. You can have a sequence
> like this:
>
> - update_wm:
> - write new (smaller) DDB
> - flush DDB
> - vblank happens, old (big) wm + new (small) ddb = underrun
> - vblank evasion:
> - write new plane regs and WM's
> - flush
> - post-evasion vblank happens, underrun is corrected
>
> I think ultimately we want to move the DDB register writes into the
> update functions that happen under evasion, just like you did for the WM
> registers. However just doing this the straightforward way won't
> satisfy our requirements about pipe update ordering (the three passes
> you see today in skl_flush_wm_values). To make that work, I think the
> general approach is that we need to basically replace the
> for_each_crtc_in_state() loop in intel_atomic_commit_tail() with some
> new CRTC iterator that processes CRTC's in a more intelligent ordering.
> We've computed our DDB changes during the atomic check phase, so we
> already know which allocations are shrinking, growing, etc. and we
> should be able to calculate an appropriate CRTC ordering at the same
> time.
>
> With an intelligent CRTC iterator that follows the pre-computed pipe
> ordering rules (and adds the necessary vblank waits between each
> "phase"), I think we should be able to just write both DDB and WM values
> in the skl_update_primary_plane() and similar functions and let the
> existing flushes that happen take care of flushing them out at the
> appropriate time. Of course I've kicked that idea around in my head for
> a while, but haven't had time to actually write any code for it, so I
> may be completely overlooking some stumbling block that makes it much
> more complicated than I'm envisioning.
>
>
> Matt
>
> >
> >
> > Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
> > 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> <cpaul@redhat.com>
> > Cc: Matt Roper <matthew.d.roper@intel.com>
> > ---
> > drivers/gpu/drm/i915/intel_pm.c | 17 +++++++++++++++--
> > 1 file changed, 15 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c
> > b/drivers/gpu/drm/i915/intel_pm.c
> > index 788db86..2e31df4 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -3859,8 +3859,11 @@ static void skl_flush_wm_values(struct
> > drm_i915_private *dev_priv,
> > /*
> > * Third pass: flush the pipes that got more space allocated.
> > *
> > - * We don't need to actively wait for the update here, next vblank
> > - * will just get more DDB space with the correct WM values.
> > + * While the hardware doesn't require to wait for the next vblank
> > here,
> > + * continuing before the pipe finishes updating could result in us
> > + * trying to update the wm values again before the pipe finishes
> > + * updating, which results in the hardware using intermediate wm
> > values
> > + * and subsequently underrunning pipes.
> > */
> > for_each_intel_crtc(dev, crtc) {
> > if (!crtc->active)
> > @@ -3876,6 +3879,16 @@ static void skl_flush_wm_values(struct
> > drm_i915_private *dev_priv,
> > continue;
> >
> > skl_wm_flush_pipe(dev_priv, pipe, 3);
> > +
> > + /*
> > + * The only time we can get away with not waiting for an
> > update
> > + * is when we just enabled the pipe, e.g. when it doesn't
> > have
> > + * vblanks enabled anyway.
> > + */
> > + if (drm_crtc_vblank_get(&crtc->base) == 0) {
> > + intel_wait_for_vblank(dev, pipe);
> > + drm_crtc_vblank_put(&crtc->base);
> > + }
> > }
> > }
> >
> > --
> > 2.7.4
> >
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2016-07-21 17:01 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-20 20:59 [PATCH 0/6] drm/i915/skl: Finally fix watermarks Lyude
2016-07-20 20:59 ` [PATCH 1/6] drm/i915/skl: Update plane watermarks atomically during plane updates Lyude
2016-07-20 23:12 ` Matt Roper
2016-07-20 20:59 ` [PATCH 3/6] drm/i915/skl: Actually reuse wm values when pipes don't change Lyude
2016-07-20 23:26 ` Matt Roper
2016-07-20 21:00 ` [PATCH 4/6] drm/i915/skl: Always wait for pipes to update after a flush Lyude
2016-07-21 0:27 ` Matt Roper
2016-07-21 17:01 ` Lyude Paul
2016-07-20 21:00 ` [PATCH 5/6] drm/i915/skl: Only flush pipes when we change the ddb allocation Lyude
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).