|
|
0903551 |
From 71136125cc79dab464a0139dbf0c02891aa9ce6e Mon Sep 17 00:00:00 2001
|
|
|
0903551 |
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
|
|
|
0903551 |
Date: Mon, 20 Jun 2016 12:41:46 +0200
|
|
|
0903551 |
Subject: [PATCH 15/17] drm/i915/gen9: Calculate watermarks during atomic
|
|
|
0903551 |
'check' (v2)
|
|
|
0903551 |
|
|
|
0903551 |
Upstream: since drm-intel-next-2016-05-22
|
|
|
0903551 |
commit 734fa01f3a17ac80d2d53cee0b05b246c03df0e4
|
|
|
0903551 |
|
|
|
0903551 |
Author: Matt Roper <matthew.d.roper@intel.com>
|
|
|
0903551 |
AuthorDate: Thu May 12 15:11:40 2016 -0700
|
|
|
0903551 |
Commit: Matt Roper <matthew.d.roper@intel.com>
|
|
|
0903551 |
CommitDate: Fri May 13 07:35:48 2016 -0700
|
|
|
0903551 |
|
|
|
0903551 |
drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)
|
|
|
0903551 |
|
|
|
0903551 |
Moving watermark calculation into the check phase will allow us to to
|
|
|
0903551 |
reject display configurations for which there are no valid watermark
|
|
|
0903551 |
values before we start trying to program the hardware (although those
|
|
|
0903551 |
tests will come in a subsequent patch).
|
|
|
0903551 |
|
|
|
0903551 |
Another advantage of moving this calculation to the check phase is that
|
|
|
0903551 |
we can calculate the watermarks in a single shot as part of the atomic
|
|
|
0903551 |
transaction. The watermark interfaces we inherited from our legacy
|
|
|
0903551 |
modesetting days are a bit broken in the atomic design because they use
|
|
|
0903551 |
per-crtc entry points but actually re-calculate and re-program something
|
|
|
0903551 |
that is really more of a global state. That worked okay in the legacy
|
|
|
0903551 |
modesetting world because operations only ever updated a single CRTC at
|
|
|
0903551 |
a time. However in the atomic world, a transaction can involve multiple
|
|
|
0903551 |
CRTC's, which means we wind up computing and programming the watermarks
|
|
|
0903551 |
NxN times (where N is the number of CRTC's involved). With this patch
|
|
|
0903551 |
we eliminate the redundant re-calculation of watermark data for atomic
|
|
|
0903551 |
states (which was the cause of the WARN_ON(!wm_changed) problems that
|
|
|
0903551 |
have plagued us for a while).
|
|
|
0903551 |
|
|
|
0903551 |
We still need to work on the 'commit' side of watermark handling so that
|
|
|
0903551 |
we aren't doing redundant NxN programming of watermarks, but that's
|
|
|
0903551 |
content for future patches.
|
|
|
0903551 |
|
|
|
0903551 |
v2:
|
|
|
0903551 |
- Bail out of skl_write_wm_values() if the CRTC isn't active. Now that
|
|
|
0903551 |
we set dirty_pipes to ~0 if the active pipes change (because
|
|
|
0903551 |
we need to deal with DDB changes), we can now wind up here for
|
|
|
0903551 |
disabled pipes, whereas we couldn't before.
|
|
|
0903551 |
|
|
|
0903551 |
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89055
|
|
|
0903551 |
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92181
|
|
|
0903551 |
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
|
|
0903551 |
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
|
|
|
0903551 |
Tested-by: Daniel Stone <daniels@collabora.com>
|
|
|
0903551 |
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
|
|
0903551 |
Link: http://patchwork.freedesktop.org/patch/msgid/1463091100-13747-1-git-send-email-matthew.d.roper@intel.com
|
|
|
0903551 |
---
|
|
|
0903551 |
drivers/gpu/drm/i915/intel_display.c | 2 +-
|
|
|
0903551 |
drivers/gpu/drm/i915/intel_drv.h | 14 +++-
|
|
|
0903551 |
drivers/gpu/drm/i915/intel_pm.c | 135 ++++++++++++-----------------------
|
|
|
0903551 |
3 files changed, 61 insertions(+), 90 deletions(-)
|
|
|
0903551 |
|
|
|
0903551 |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
|
|
0903551 |
index 9ac2346..1726ea4 100644
|
|
|
0903551 |
--- a/drivers/gpu/drm/i915/intel_display.c
|
|
|
0903551 |
+++ b/drivers/gpu/drm/i915/intel_display.c
|
|
|
0903551 |
@@ -13522,7 +13522,7 @@ static int intel_atomic_commit(struct drm_device *dev,
|
|
|
0903551 |
drm_atomic_helper_swap_state(dev, state);
|
|
|
0903551 |
dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
|
|
|
0903551 |
dev_priv->wm.distrust_bios_wm = false;
|
|
|
0903551 |
- dev_priv->wm.skl_results.ddb = intel_state->ddb;
|
|
|
0903551 |
+ dev_priv->wm.skl_results = intel_state->wm_results;
|
|
|
0903551 |
|
|
|
0903551 |
if (intel_state->modeset) {
|
|
|
0903551 |
memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
|
|
|
0903551 |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
|
|
|
0903551 |
index 4d6336a..e5543b8 100644
|
|
|
0903551 |
--- a/drivers/gpu/drm/i915/intel_drv.h
|
|
|
0903551 |
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
|
|
0903551 |
@@ -273,7 +273,7 @@ struct intel_atomic_state {
|
|
|
0903551 |
struct intel_wm_config wm_config;
|
|
|
0903551 |
|
|
|
0903551 |
/* Gen9+ only */
|
|
|
0903551 |
- struct skl_ddb_allocation ddb;
|
|
|
0903551 |
+ struct skl_wm_values wm_results;
|
|
|
0903551 |
};
|
|
|
0903551 |
|
|
|
0903551 |
struct intel_plane_state {
|
|
|
0903551 |
@@ -1661,6 +1661,18 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
|
|
|
0903551 |
|
|
|
0903551 |
return to_intel_crtc_state(crtc_state);
|
|
|
0903551 |
}
|
|
|
0903551 |
+
|
|
|
0903551 |
+static inline struct intel_plane_state *
|
|
|
0903551 |
+intel_atomic_get_existing_plane_state(struct drm_atomic_state *state,
|
|
|
0903551 |
+ struct intel_plane *plane)
|
|
|
0903551 |
+{
|
|
|
0903551 |
+ struct drm_plane_state *plane_state;
|
|
|
0903551 |
+
|
|
|
0903551 |
+ plane_state = drm_atomic_get_existing_plane_state(state, &plane->base);
|
|
|
0903551 |
+
|
|
|
0903551 |
+ return to_intel_plane_state(plane_state);
|
|
|
0903551 |
+}
|
|
|
0903551 |
+
|
|
|
0903551 |
int intel_atomic_setup_scalers(struct drm_device *dev,
|
|
|
0903551 |
struct intel_crtc *intel_crtc,
|
|
|
0903551 |
struct intel_crtc_state *crtc_state);
|
|
|
0903551 |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
|
|
|
0903551 |
index ec22d93..73e5242 100644
|
|
|
0903551 |
--- a/drivers/gpu/drm/i915/intel_pm.c
|
|
|
0903551 |
+++ b/drivers/gpu/drm/i915/intel_pm.c
|
|
|
0903551 |
@@ -3160,23 +3160,6 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
|
|
|
0903551 |
return ret;
|
|
|
0903551 |
}
|
|
|
0903551 |
|
|
|
0903551 |
-static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
|
|
|
0903551 |
- const struct intel_crtc *intel_crtc)
|
|
|
0903551 |
-{
|
|
|
0903551 |
- struct drm_device *dev = intel_crtc->base.dev;
|
|
|
0903551 |
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
0903551 |
- const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
|
|
|
0903551 |
-
|
|
|
0903551 |
- /*
|
|
|
0903551 |
- * If ddb allocation of pipes changed, it may require recalculation of
|
|
|
0903551 |
- * watermarks
|
|
|
0903551 |
- */
|
|
|
0903551 |
- if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
|
|
|
0903551 |
- return true;
|
|
|
0903551 |
-
|
|
|
0903551 |
- return false;
|
|
|
0903551 |
-}
|
|
|
0903551 |
-
|
|
|
0903551 |
static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
|
|
|
0903551 |
struct intel_crtc_state *cstate,
|
|
|
0903551 |
struct intel_plane_state *intel_pstate,
|
|
|
0903551 |
@@ -3472,6 +3455,8 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
|
|
|
0903551 |
|
|
|
0903551 |
if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
|
|
|
0903551 |
continue;
|
|
|
0903551 |
+ if (!crtc->active)
|
|
|
0903551 |
+ continue;
|
|
|
0903551 |
|
|
|
0903551 |
I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
|
|
|
0903551 |
|
|
|
0903551 |
@@ -3655,66 +3640,9 @@ static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
|
|
|
0903551 |
else
|
|
|
0903551 |
*changed = true;
|
|
|
0903551 |
|
|
|
0903551 |
- intel_crtc->wm.active.skl = *pipe_wm;
|
|
|
0903551 |
-
|
|
|
0903551 |
return 0;
|
|
|
0903551 |
}
|
|
|
0903551 |
|
|
|
0903551 |
-static void skl_update_other_pipe_wm(struct drm_device *dev,
|
|
|
0903551 |
- struct drm_crtc *crtc,
|
|
|
0903551 |
- struct skl_wm_values *r)
|
|
|
0903551 |
-{
|
|
|
0903551 |
- struct intel_crtc *intel_crtc;
|
|
|
0903551 |
- struct intel_crtc *this_crtc = to_intel_crtc(crtc);
|
|
|
0903551 |
-
|
|
|
0903551 |
- /*
|
|
|
0903551 |
- * If the WM update hasn't changed the allocation for this_crtc (the
|
|
|
0903551 |
- * crtc we are currently computing the new WM values for), other
|
|
|
0903551 |
- * enabled crtcs will keep the same allocation and we don't need to
|
|
|
0903551 |
- * recompute anything for them.
|
|
|
0903551 |
- */
|
|
|
0903551 |
- if (!skl_ddb_allocation_changed(&r->ddb, this_crtc))
|
|
|
0903551 |
- return;
|
|
|
0903551 |
-
|
|
|
0903551 |
- /*
|
|
|
0903551 |
- * Otherwise, because of this_crtc being freshly enabled/disabled, the
|
|
|
0903551 |
- * other active pipes need new DDB allocation and WM values.
|
|
|
0903551 |
- */
|
|
|
0903551 |
- for_each_intel_crtc(dev, intel_crtc) {
|
|
|
0903551 |
- struct skl_pipe_wm pipe_wm = {};
|
|
|
0903551 |
- bool wm_changed;
|
|
|
0903551 |
-
|
|
|
0903551 |
- if (this_crtc->pipe == intel_crtc->pipe)
|
|
|
0903551 |
- continue;
|
|
|
0903551 |
-
|
|
|
0903551 |
- if (!intel_crtc->active)
|
|
|
0903551 |
- continue;
|
|
|
0903551 |
-
|
|
|
0903551 |
- skl_update_pipe_wm(intel_crtc->base.state,
|
|
|
0903551 |
- &r->ddb, &pipe_wm, &wm_changed);
|
|
|
0903551 |
-
|
|
|
0903551 |
- /*
|
|
|
0903551 |
- * If we end up re-computing the other pipe WM values, it's
|
|
|
0903551 |
- * because it was really needed, so we expect the WM values to
|
|
|
0903551 |
- * be different.
|
|
|
0903551 |
- */
|
|
|
0903551 |
- WARN_ON(!wm_changed);
|
|
|
0903551 |
-
|
|
|
0903551 |
- skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
|
|
|
0903551 |
- r->dirty_pipes |= drm_crtc_mask(&intel_crtc->base);
|
|
|
0903551 |
- }
|
|
|
0903551 |
-}
|
|
|
0903551 |
-
|
|
|
0903551 |
-static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
|
|
|
0903551 |
-{
|
|
|
0903551 |
- watermarks->wm_linetime[pipe] = 0;
|
|
|
0903551 |
- memset(watermarks->plane[pipe], 0,
|
|
|
0903551 |
- sizeof(uint32_t) * 8 * I915_MAX_PLANES);
|
|
|
0903551 |
- memset(watermarks->plane_trans[pipe],
|
|
|
0903551 |
- 0, sizeof(uint32_t) * I915_MAX_PLANES);
|
|
|
0903551 |
- watermarks->plane_trans[pipe][PLANE_CURSOR] = 0;
|
|
|
0903551 |
-}
|
|
|
0903551 |
-
|
|
|
0903551 |
static int
|
|
|
0903551 |
skl_compute_ddb(struct drm_atomic_state *state)
|
|
|
0903551 |
{
|
|
|
0903551 |
@@ -3722,6 +3650,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
|
|
|
0903551 |
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
0903551 |
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
|
|
0903551 |
struct intel_crtc *intel_crtc;
|
|
|
0903551 |
+ struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
|
|
|
0903551 |
unsigned realloc_pipes = dev_priv->active_crtcs;
|
|
|
0903551 |
int ret;
|
|
|
0903551 |
|
|
|
0903551 |
@@ -3747,8 +3676,10 @@ skl_compute_ddb(struct drm_atomic_state *state)
|
|
|
0903551 |
* any other display updates race with this transaction, so we need
|
|
|
0903551 |
* to grab the lock on *all* CRTC's.
|
|
|
0903551 |
*/
|
|
|
0903551 |
- if (intel_state->active_pipe_changes)
|
|
|
0903551 |
+ if (intel_state->active_pipe_changes) {
|
|
|
0903551 |
realloc_pipes = ~0;
|
|
|
0903551 |
+ intel_state->wm_results.dirty_pipes = ~0;
|
|
|
0903551 |
+ }
|
|
|
0903551 |
|
|
|
0903551 |
for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) {
|
|
|
0903551 |
struct intel_crtc_state *cstate;
|
|
|
0903551 |
@@ -3757,7 +3688,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
|
|
|
0903551 |
if (IS_ERR(cstate))
|
|
|
0903551 |
return PTR_ERR(cstate);
|
|
|
0903551 |
|
|
|
0903551 |
- ret = skl_allocate_pipe_ddb(cstate, &intel_state->ddb);
|
|
|
0903551 |
+ ret = skl_allocate_pipe_ddb(cstate, ddb);
|
|
|
0903551 |
if (ret)
|
|
|
0903551 |
return ret;
|
|
|
0903551 |
}
|
|
|
0903551 |
@@ -3770,8 +3701,11 @@ skl_compute_wm(struct drm_atomic_state *state)
|
|
|
0903551 |
{
|
|
|
0903551 |
struct drm_crtc *crtc;
|
|
|
0903551 |
struct drm_crtc_state *cstate;
|
|
|
0903551 |
- int ret, i;
|
|
|
0903551 |
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
|
|
0903551 |
+ struct skl_wm_values *results = &intel_state->wm_results;
|
|
|
0903551 |
+ struct skl_pipe_wm *pipe_wm;
|
|
|
0903551 |
bool changed = false;
|
|
|
0903551 |
+ int ret, i;
|
|
|
0903551 |
|
|
|
0903551 |
/*
|
|
|
0903551 |
* If this transaction isn't actually touching any CRTC's, don't
|
|
|
0903551 |
@@ -3786,10 +3720,44 @@ skl_compute_wm(struct drm_atomic_state *state)
|
|
|
0903551 |
if (!changed)
|
|
|
0903551 |
return 0;
|
|
|
0903551 |
|
|
|
0903551 |
+ /* Clear all dirty flags */
|
|
|
0903551 |
+ results->dirty_pipes = 0;
|
|
|
0903551 |
+
|
|
|
0903551 |
ret = skl_compute_ddb(state);
|
|
|
0903551 |
if (ret)
|
|
|
0903551 |
return ret;
|
|
|
0903551 |
|
|
|
0903551 |
+ /*
|
|
|
0903551 |
+ * Calculate WM's for all pipes that are part of this transaction.
|
|
|
0903551 |
+ * Note that the DDB allocation above may have added more CRTC's that
|
|
|
0903551 |
+ * weren't otherwise being modified (and set bits in dirty_pipes) if
|
|
|
0903551 |
+ * pipe allocations had to change.
|
|
|
0903551 |
+ *
|
|
|
0903551 |
+ * FIXME: Now that we're doing this in the atomic check phase, we
|
|
|
0903551 |
+ * should allow skl_update_pipe_wm() to return failure in cases where
|
|
|
0903551 |
+ * no suitable watermark values can be found.
|
|
|
0903551 |
+ */
|
|
|
0903551 |
+ for_each_crtc_in_state(state, crtc, cstate, i) {
|
|
|
0903551 |
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
0903551 |
+ struct intel_crtc_state *intel_cstate =
|
|
|
0903551 |
+ to_intel_crtc_state(cstate);
|
|
|
0903551 |
+
|
|
|
0903551 |
+ pipe_wm = &intel_cstate->wm.skl.optimal;
|
|
|
0903551 |
+ ret = skl_update_pipe_wm(cstate, &results->ddb, pipe_wm,
|
|
|
0903551 |
+ &changed);
|
|
|
0903551 |
+ if (ret)
|
|
|
0903551 |
+ return ret;
|
|
|
0903551 |
+
|
|
|
0903551 |
+ if (changed)
|
|
|
0903551 |
+ results->dirty_pipes |= drm_crtc_mask(crtc);
|
|
|
0903551 |
+
|
|
|
0903551 |
+ if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
|
|
|
0903551 |
+ /* This pipe's WM's did not change */
|
|
|
0903551 |
+ continue;
|
|
|
0903551 |
+
|
|
|
0903551 |
+ skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
|
|
|
0903551 |
+ }
|
|
|
0903551 |
+
|
|
|
0903551 |
return 0;
|
|
|
0903551 |
}
|
|
|
0903551 |
|
|
|
0903551 |
@@ -3801,21 +3769,12 @@ static void skl_update_wm(struct drm_crtc *crtc)
|
|
|
0903551 |
struct skl_wm_values *results = &dev_priv->wm.skl_results;
|
|
|
0903551 |
struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
|
|
|
0903551 |
struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
|
|
|
0903551 |
- bool wm_changed;
|
|
|
0903551 |
|
|
|
0903551 |
- /* Clear all dirty flags */
|
|
|
0903551 |
- results->dirty_pipes = 0;
|
|
|
0903551 |
-
|
|
|
0903551 |
- skl_clear_wm(results, intel_crtc->pipe);
|
|
|
0903551 |
-
|
|
|
0903551 |
- skl_update_pipe_wm(crtc->state, &results->ddb, pipe_wm, &wm_changed);
|
|
|
0903551 |
- if (!wm_changed)
|
|
|
0903551 |
+ if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
|
|
|
0903551 |
return;
|
|
|
0903551 |
|
|
|
0903551 |
- skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
|
|
|
0903551 |
- results->dirty_pipes |= drm_crtc_mask(&intel_crtc->base);
|
|
|
0903551 |
+ intel_crtc->wm.active.skl = *pipe_wm;
|
|
|
0903551 |
|
|
|
0903551 |
- skl_update_other_pipe_wm(dev, crtc, results);
|
|
|
0903551 |
skl_write_wm_values(dev_priv, results);
|
|
|
0903551 |
skl_flush_wm_values(dev_priv, results);
|
|
|
0903551 |
|
|
|
0903551 |
--
|
|
|
0903551 |
2.7.4
|
|
|
0903551 |
|