ec226c2
From 664f87c5bfcc7798bd5b16e14792f1e9ba2956ea Mon Sep 17 00:00:00 2001
ec226c2
From: Matt Roper <matthew.d.roper@intel.com>
ec226c2
Date: Thu, 12 May 2016 15:11:40 -0700
0903551
Subject: [PATCH 15/17] drm/i915/gen9: Calculate watermarks during atomic
0903551
 'check' (v2)
0903551
ec226c2
Moving watermark calculation into the check phase will allow us to to
ec226c2
reject display configurations for which there are no valid watermark
ec226c2
values before we start trying to program the hardware (although those
ec226c2
tests will come in a subsequent patch).
0903551
ec226c2
Another advantage of moving this calculation to the check phase is that
ec226c2
we can calculate the watermarks in a single shot as part of the atomic
ec226c2
transaction.  The watermark interfaces we inherited from our legacy
ec226c2
modesetting days are a bit broken in the atomic design because they use
ec226c2
per-crtc entry points but actually re-calculate and re-program something
ec226c2
that is really more of a global state.  That worked okay in the legacy
ec226c2
modesetting world because operations only ever updated a single CRTC at
ec226c2
a time.  However in the atomic world, a transaction can involve multiple
ec226c2
CRTC's, which means we wind up computing and programming the watermarks
ec226c2
NxN times (where N is the number of CRTC's involved).  With this patch
ec226c2
we eliminate the redundant re-calculation of watermark data for atomic
ec226c2
states (which was the cause of the WARN_ON(!wm_changed) problems that
ec226c2
have plagued us for a while).
0903551
ec226c2
We still need to work on the 'commit' side of watermark handling so that
ec226c2
we aren't doing redundant NxN programming of watermarks, but that's
ec226c2
content for future patches.
0903551
ec226c2
v2:
ec226c2
 - Bail out of skl_write_wm_values() if the CRTC isn't active.  Now that
ec226c2
   we set dirty_pipes to ~0 if the active pipes change (because
ec226c2
   we need to deal with DDB changes), we can now wind up here for
ec226c2
   disabled pipes, whereas we couldn't before.
0903551
ec226c2
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89055
ec226c2
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92181
ec226c2
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
ec226c2
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
ec226c2
Tested-by: Daniel Stone <daniels@collabora.com>
ec226c2
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
ec226c2
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 +-
ec226c2
 drivers/gpu/drm/i915/intel_drv.h     |   2 +-
ec226c2
 drivers/gpu/drm/i915/intel_pm.c      | 140 +++++++++++++----------------------
ec226c2
 3 files changed, 54 insertions(+), 90 deletions(-)
0903551
0903551
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
ec226c2
index 2190bac..a75daac 100644
0903551
--- a/drivers/gpu/drm/i915/intel_display.c
0903551
+++ b/drivers/gpu/drm/i915/intel_display.c
ec226c2
@@ -13627,7 +13627,7 @@ static int intel_atomic_commit(struct drm_device *dev,
0903551
 	drm_atomic_helper_swap_state(dev, state);
ec226c2
 	dev_priv->wm.config = intel_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;
ec226c2
 	intel_shared_dpll_commit(state);
0903551
 
0903551
 	if (intel_state->modeset) {
0903551
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
ec226c2
index 2218290..ab0be7a 100644
0903551
--- a/drivers/gpu/drm/i915/intel_drv.h
0903551
+++ b/drivers/gpu/drm/i915/intel_drv.h
ec226c2
@@ -314,7 +314,7 @@ struct intel_atomic_state {
ec226c2
 	bool skip_intermediate_wm;
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
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
ec226c2
index 342aa66..b072417 100644
0903551
--- a/drivers/gpu/drm/i915/intel_pm.c
0903551
+++ b/drivers/gpu/drm/i915/intel_pm.c
ec226c2
@@ -3221,23 +3221,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,
ec226c2
@@ -3533,6 +3516,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
 
ec226c2
@@ -3716,66 +3701,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
 {
ec226c2
@@ -3783,6 +3711,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
 
ec226c2
@@ -3808,8 +3737,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;
ec226c2
@@ -3818,7 +3749,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
 	}
ec226c2
@@ -3831,8 +3762,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
ec226c2
@@ -3847,10 +3781,45 @@ 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
+
ec226c2
+		intel_cstate->update_wm_pre = true;
0903551
+		skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
0903551
+	}
0903551
+
0903551
 	return 0;
0903551
 }
0903551
 
ec226c2
@@ -3862,26 +3831,21 @@ 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;
ec226c2
-
0903551
-	/* Clear all dirty flags */
0903551
-	results->dirty_pipes = 0;
ec226c2
 
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;
ec226c2
+
ec226c2
+	mutex_lock(&dev_priv->wm.wm_mutex);
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
 
ec226c2
 	/* store the new configuration */
ec226c2
 	dev_priv->wm.skl_hw = *results;
ec226c2
+
ec226c2
+	mutex_unlock(&dev_priv->wm.wm_mutex);
ec226c2
 }
ec226c2
 
ec226c2
 static void ilk_compute_wm_config(struct drm_device *dev,
0903551
-- 
0903551
2.7.4
0903551