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