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