245 lines
9.3 KiB
Diff
245 lines
9.3 KiB
Diff
|
From fbf53d8f1b7d1bcea1411f1f2cd0df6a6cc95332 Mon Sep 17 00:00:00 2001
|
||
|
From: Matt Roper <matthew.d.roper@intel.com>
|
||
|
Date: Thu, 12 May 2016 07:06:03 -0700
|
||
|
Subject: [PATCH 09/17] drm/i915/gen9: Compute DDB allocation at atomic check
|
||
|
time (v4)
|
||
|
|
||
|
Calculate the DDB blocks needed to satisfy the current atomic
|
||
|
transaction at atomic check time. This is a prerequisite to calculating
|
||
|
SKL watermarks during the 'check' phase and rejecting any configurations
|
||
|
that we can't find valid watermarks for.
|
||
|
|
||
|
Due to the nature of DDB allocation, it's possible for the addition of a
|
||
|
new CRTC to make the watermark configuration already in use on another,
|
||
|
unchanged CRTC become invalid. A change in which CRTC's are active
|
||
|
triggers a recompute of the entire DDB, which unfortunately means we
|
||
|
need to disallow any other atomic commits from racing with such an
|
||
|
update. If the active CRTC's change, we need to grab the lock on all
|
||
|
CRTC's and run all CRTC's through their 'check' handler to recompute and
|
||
|
re-check their per-CRTC DDB allocations.
|
||
|
|
||
|
Note that with this patch we only compute the DDB allocation but we
|
||
|
don't actually use the computed values during watermark programming yet.
|
||
|
For ease of review/testing/bisecting, we still recompute the DDB at
|
||
|
watermark programming time and just WARN() if it doesn't match the
|
||
|
precomputed values. A future patch will switch over to using the
|
||
|
precomputed values once we're sure they're being properly computed.
|
||
|
|
||
|
Another clarifying note: DDB allocation itself shouldn't ever fail with
|
||
|
the algorithm we use today (i.e., we have enough DDB blocks on BXT to
|
||
|
support the minimum needs of the worst-case scenario of every pipe/plane
|
||
|
enabled at full size). However the watermarks calculations based on the
|
||
|
DDB may fail and we'll be moving those to the atomic check as well in
|
||
|
future patches.
|
||
|
|
||
|
v2:
|
||
|
- Skip DDB calculations in the rare case where our transaction doesn't
|
||
|
actually touch any CRTC's at all. Assuming at least one CRTC state
|
||
|
is present in our transaction, then it means we can't race with any
|
||
|
transactions that would update dev_priv->active_crtcs (which requires
|
||
|
_all_ CRTC locks).
|
||
|
|
||
|
v3:
|
||
|
- Also calculate DDB during initial hw readout, to prevent using
|
||
|
incorrect bios values. (Maarten)
|
||
|
|
||
|
v4:
|
||
|
- Use new distrust_bios_wm flag instead of skip_initial_wm (which was
|
||
|
never actually set).
|
||
|
- Set intel_state->active_pipe_changes instead of just realloc_pipes
|
||
|
|
||
|
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
||
|
Cc: Lyude Paul <cpaul@redhat.com>
|
||
|
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
|
||
|
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
|
||
|
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
||
|
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
||
|
Link: http://patchwork.freedesktop.org/patch/msgid/1463061971-19638-10-git-send-email-matthew.d.roper@intel.com
|
||
|
---
|
||
|
drivers/gpu/drm/i915/i915_drv.h | 5 +++
|
||
|
drivers/gpu/drm/i915/intel_display.c | 18 ++++++++
|
||
|
drivers/gpu/drm/i915/intel_drv.h | 3 ++
|
||
|
drivers/gpu/drm/i915/intel_pm.c | 79 ++++++++++++++++++++++++++++++++++++
|
||
|
4 files changed, 105 insertions(+)
|
||
|
|
||
|
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
|
||
|
index e21960d..b908a41 100644
|
||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||
|
@@ -339,6 +339,10 @@ struct i915_hotplug {
|
||
|
#define for_each_intel_crtc(dev, intel_crtc) \
|
||
|
list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
|
||
|
|
||
|
+#define for_each_intel_crtc_mask(dev, intel_crtc, crtc_mask) \
|
||
|
+ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) \
|
||
|
+ for_each_if ((crtc_mask) & (1 << drm_crtc_index(&intel_crtc->base)))
|
||
|
+
|
||
|
#define for_each_intel_encoder(dev, intel_encoder) \
|
||
|
list_for_each_entry(intel_encoder, \
|
||
|
&(dev)->mode_config.encoder_list, \
|
||
|
@@ -594,6 +598,7 @@ struct drm_i915_display_funcs {
|
||
|
struct intel_crtc_state *newstate);
|
||
|
void (*initial_watermarks)(struct intel_crtc_state *cstate);
|
||
|
void (*optimize_watermarks)(struct intel_crtc_state *cstate);
|
||
|
+ int (*compute_global_watermarks)(struct drm_atomic_state *state);
|
||
|
void (*update_wm)(struct drm_crtc *crtc);
|
||
|
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
|
||
|
void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
||
|
index a9d2e30..ecad0ef 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_display.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_display.c
|
||
|
@@ -13342,6 +13342,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
|
||
|
static void calc_watermark_data(struct drm_atomic_state *state)
|
||
|
{
|
||
|
struct drm_device *dev = state->dev;
|
||
|
+ struct drm_i915_private *dev_priv = to_i915(dev);
|
||
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
||
|
struct drm_crtc *crtc;
|
||
|
struct drm_crtc_state *cstate;
|
||
|
@@ -13371,6 +13372,10 @@ static void calc_watermark_data(struct drm_atomic_state *state)
|
||
|
pstate->crtc_h != pstate->src_h >> 16)
|
||
|
intel_state->wm_config.sprites_scaled = true;
|
||
|
}
|
||
|
+
|
||
|
+ /* Is there platform-specific watermark information to calculate? */
|
||
|
+ if (dev_priv->display.compute_global_watermarks)
|
||
|
+ dev_priv->display.compute_global_watermarks(state);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -13739,6 +13744,19 @@ static int intel_atomic_commit(struct drm_device *dev,
|
||
|
intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state);
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * Temporary sanity check: make sure our pre-computed DDB matches the
|
||
|
+ * one we actually wind up programming.
|
||
|
+ *
|
||
|
+ * Not a great place to put this, but the easiest place we have access
|
||
|
+ * to both the pre-computed and final DDB's; we'll be removing this
|
||
|
+ * check in the next patch anyway.
|
||
|
+ */
|
||
|
+ WARN(IS_GEN9(dev) &&
|
||
|
+ memcmp(&intel_state->ddb, &dev_priv->wm.skl_results.ddb,
|
||
|
+ sizeof(intel_state->ddb)),
|
||
|
+ "Pre-computed DDB does not match final DDB!\n");
|
||
|
+
|
||
|
if (intel_state->modeset)
|
||
|
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
|
||
|
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
|
||
|
index d19e83e..2218290 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_drv.h
|
||
|
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
||
|
@@ -312,6 +312,9 @@ struct intel_atomic_state {
|
||
|
* don't bother calculating intermediate watermarks.
|
||
|
*/
|
||
|
bool skip_intermediate_wm;
|
||
|
+
|
||
|
+ /* Gen9+ only */
|
||
|
+ struct skl_ddb_allocation ddb;
|
||
|
};
|
||
|
|
||
|
struct intel_plane_state {
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
|
||
|
index a49faa7..cfa4f80 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_pm.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_pm.c
|
||
|
@@ -3812,6 +3812,84 @@ static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
|
||
|
|
||
|
}
|
||
|
|
||
|
+static int
|
||
|
+skl_compute_ddb(struct drm_atomic_state *state)
|
||
|
+{
|
||
|
+ struct drm_device *dev = state->dev;
|
||
|
+ 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;
|
||
|
+ unsigned realloc_pipes = dev_priv->active_crtcs;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If this is our first atomic update following hardware readout,
|
||
|
+ * we can't trust the DDB that the BIOS programmed for us. Let's
|
||
|
+ * pretend that all pipes switched active status so that we'll
|
||
|
+ * ensure a full DDB recompute.
|
||
|
+ */
|
||
|
+ if (dev_priv->wm.distrust_bios_wm)
|
||
|
+ intel_state->active_pipe_changes = ~0;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If the modeset changes which CRTC's are active, we need to
|
||
|
+ * recompute the DDB allocation for *all* active pipes, even
|
||
|
+ * those that weren't otherwise being modified in any way by this
|
||
|
+ * atomic commit. Due to the shrinking of the per-pipe allocations
|
||
|
+ * when new active CRTC's are added, it's possible for a pipe that
|
||
|
+ * we were already using and aren't changing at all here to suddenly
|
||
|
+ * become invalid if its DDB needs exceeds its new allocation.
|
||
|
+ *
|
||
|
+ * Note that if we wind up doing a full DDB recompute, we can't let
|
||
|
+ * 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)
|
||
|
+ realloc_pipes = ~0;
|
||
|
+
|
||
|
+ for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) {
|
||
|
+ struct intel_crtc_state *cstate;
|
||
|
+
|
||
|
+ cstate = intel_atomic_get_crtc_state(state, intel_crtc);
|
||
|
+ if (IS_ERR(cstate))
|
||
|
+ return PTR_ERR(cstate);
|
||
|
+
|
||
|
+ ret = skl_allocate_pipe_ddb(cstate, &intel_state->ddb);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+skl_compute_wm(struct drm_atomic_state *state)
|
||
|
+{
|
||
|
+ struct drm_crtc *crtc;
|
||
|
+ struct drm_crtc_state *cstate;
|
||
|
+ int ret, i;
|
||
|
+ bool changed = false;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If this transaction isn't actually touching any CRTC's, don't
|
||
|
+ * bother with watermark calculation. Note that if we pass this
|
||
|
+ * test, we're guaranteed to hold at least one CRTC state mutex,
|
||
|
+ * which means we can safely use values like dev_priv->active_crtcs
|
||
|
+ * since any racing commits that want to update them would need to
|
||
|
+ * hold _all_ CRTC state mutexes.
|
||
|
+ */
|
||
|
+ for_each_crtc_in_state(state, crtc, cstate, i)
|
||
|
+ changed = true;
|
||
|
+ if (!changed)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ ret = skl_compute_ddb(state);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static void skl_update_wm(struct drm_crtc *crtc)
|
||
|
{
|
||
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||
|
@@ -7384,6 +7462,7 @@ void intel_init_pm(struct drm_device *dev)
|
||
|
if (INTEL_INFO(dev)->gen >= 9) {
|
||
|
skl_setup_wm_latency(dev);
|
||
|
dev_priv->display.update_wm = skl_update_wm;
|
||
|
+ dev_priv->display.compute_global_watermarks = skl_compute_wm;
|
||
|
} else if (HAS_PCH_SPLIT(dev)) {
|
||
|
ilk_setup_wm_latency(dev);
|
||
|
|
||
|
--
|
||
|
2.7.4
|
||
|
|