0d24915
From 664f87c5bfcc7798bd5b16e14792f1e9ba2956ea Mon Sep 17 00:00:00 2001
0d24915
From: Matt Roper <matthew.d.roper@intel.com>
0d24915
Date: Thu, 12 May 2016 15:11:40 -0700
55efec4
Subject: [PATCH 15/17] drm/i915/gen9: Calculate watermarks during atomic
55efec4
 'check' (v2)
55efec4
0d24915
Moving watermark calculation into the check phase will allow us to to
0d24915
reject display configurations for which there are no valid watermark
0d24915
values before we start trying to program the hardware (although those
0d24915
tests will come in a subsequent patch).
55efec4
0d24915
Another advantage of moving this calculation to the check phase is that
0d24915
we can calculate the watermarks in a single shot as part of the atomic
0d24915
transaction.  The watermark interfaces we inherited from our legacy
0d24915
modesetting days are a bit broken in the atomic design because they use
0d24915
per-crtc entry points but actually re-calculate and re-program something
0d24915
that is really more of a global state.  That worked okay in the legacy
0d24915
modesetting world because operations only ever updated a single CRTC at
0d24915
a time.  However in the atomic world, a transaction can involve multiple
0d24915
CRTC's, which means we wind up computing and programming the watermarks
0d24915
NxN times (where N is the number of CRTC's involved).  With this patch
0d24915
we eliminate the redundant re-calculation of watermark data for atomic
0d24915
states (which was the cause of the WARN_ON(!wm_changed) problems that
0d24915
have plagued us for a while).
55efec4
0d24915
We still need to work on the 'commit' side of watermark handling so that
0d24915
we aren't doing redundant NxN programming of watermarks, but that's
0d24915
content for future patches.
55efec4
0d24915
v2:
0d24915
 - Bail out of skl_write_wm_values() if the CRTC isn't active.  Now that
0d24915
   we set dirty_pipes to ~0 if the active pipes change (because
0d24915
   we need to deal with DDB changes), we can now wind up here for
0d24915
   disabled pipes, whereas we couldn't before.
55efec4
0d24915
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89055
0d24915
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92181
0d24915
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
0d24915
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
0d24915
Tested-by: Daniel Stone <daniels@collabora.com>
0d24915
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
0d24915
Link: http://patchwork.freedesktop.org/patch/msgid/1463091100-13747-1-git-send-email-matthew.d.roper@intel.com
55efec4
---
55efec4
 drivers/gpu/drm/i915/intel_display.c |   2 +-
0d24915
 drivers/gpu/drm/i915/intel_drv.h     |   2 +-
0d24915
 drivers/gpu/drm/i915/intel_pm.c      | 140 +++++++++++++----------------------
0d24915
 3 files changed, 54 insertions(+), 90 deletions(-)
55efec4
55efec4
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
0d24915
index 2190bac..a75daac 100644
55efec4
--- a/drivers/gpu/drm/i915/intel_display.c
55efec4
+++ b/drivers/gpu/drm/i915/intel_display.c
0d24915
@@ -13627,7 +13627,7 @@ static int intel_atomic_commit(struct drm_device *dev,
55efec4
 	drm_atomic_helper_swap_state(dev, state);
0d24915
 	dev_priv->wm.config = intel_state->wm_config;
55efec4
 	dev_priv->wm.distrust_bios_wm = false;
55efec4
-	dev_priv->wm.skl_results.ddb = intel_state->ddb;
55efec4
+	dev_priv->wm.skl_results = intel_state->wm_results;
0d24915
 	intel_shared_dpll_commit(state);
55efec4
 
55efec4
 	if (intel_state->modeset) {
55efec4
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
0d24915
index 2218290..ab0be7a 100644
55efec4
--- a/drivers/gpu/drm/i915/intel_drv.h
55efec4
+++ b/drivers/gpu/drm/i915/intel_drv.h
0d24915
@@ -314,7 +314,7 @@ struct intel_atomic_state {
0d24915
 	bool skip_intermediate_wm;
55efec4
 
55efec4
 	/* Gen9+ only */
55efec4
-	struct skl_ddb_allocation ddb;
55efec4
+	struct skl_wm_values wm_results;
55efec4
 };
55efec4
 
55efec4
 struct intel_plane_state {
55efec4
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
0d24915
index 342aa66..b072417 100644
55efec4
--- a/drivers/gpu/drm/i915/intel_pm.c
55efec4
+++ b/drivers/gpu/drm/i915/intel_pm.c
0d24915
@@ -3221,23 +3221,6 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
55efec4
 	return ret;
55efec4
 }
55efec4
 
55efec4
-static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
55efec4
-				       const struct intel_crtc *intel_crtc)
55efec4
-{
55efec4
-	struct drm_device *dev = intel_crtc->base.dev;
55efec4
-	struct drm_i915_private *dev_priv = dev->dev_private;
55efec4
-	const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
55efec4
-
55efec4
-	/*
55efec4
-	 * If ddb allocation of pipes changed, it may require recalculation of
55efec4
-	 * watermarks
55efec4
-	 */
55efec4
-	if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
55efec4
-		return true;
55efec4
-
55efec4
-	return false;
55efec4
-}
55efec4
-
55efec4
 static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
55efec4
 				struct intel_crtc_state *cstate,
55efec4
 				struct intel_plane_state *intel_pstate,
0d24915
@@ -3533,6 +3516,8 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
55efec4
 
55efec4
 		if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
55efec4
 			continue;
55efec4
+		if (!crtc->active)
55efec4
+			continue;
55efec4
 
55efec4
 		I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
55efec4
 
0d24915
@@ -3716,66 +3701,9 @@ static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
55efec4
 	else
55efec4
 		*changed = true;
55efec4
 
55efec4
-	intel_crtc->wm.active.skl = *pipe_wm;
55efec4
-
55efec4
 	return 0;
55efec4
 }
55efec4
 
55efec4
-static void skl_update_other_pipe_wm(struct drm_device *dev,
55efec4
-				     struct drm_crtc *crtc,
55efec4
-				     struct skl_wm_values *r)
55efec4
-{
55efec4
-	struct intel_crtc *intel_crtc;
55efec4
-	struct intel_crtc *this_crtc = to_intel_crtc(crtc);
55efec4
-
55efec4
-	/*
55efec4
-	 * If the WM update hasn't changed the allocation for this_crtc (the
55efec4
-	 * crtc we are currently computing the new WM values for), other
55efec4
-	 * enabled crtcs will keep the same allocation and we don't need to
55efec4
-	 * recompute anything for them.
55efec4
-	 */
55efec4
-	if (!skl_ddb_allocation_changed(&r->ddb, this_crtc))
55efec4
-		return;
55efec4
-
55efec4
-	/*
55efec4
-	 * Otherwise, because of this_crtc being freshly enabled/disabled, the
55efec4
-	 * other active pipes need new DDB allocation and WM values.
55efec4
-	 */
55efec4
-	for_each_intel_crtc(dev, intel_crtc) {
55efec4
-		struct skl_pipe_wm pipe_wm = {};
55efec4
-		bool wm_changed;
55efec4
-
55efec4
-		if (this_crtc->pipe == intel_crtc->pipe)
55efec4
-			continue;
55efec4
-
55efec4
-		if (!intel_crtc->active)
55efec4
-			continue;
55efec4
-
55efec4
-		skl_update_pipe_wm(intel_crtc->base.state,
55efec4
-				   &r->ddb, &pipe_wm, &wm_changed);
55efec4
-
55efec4
-		/*
55efec4
-		 * If we end up re-computing the other pipe WM values, it's
55efec4
-		 * because it was really needed, so we expect the WM values to
55efec4
-		 * be different.
55efec4
-		 */
55efec4
-		WARN_ON(!wm_changed);
55efec4
-
55efec4
-		skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
55efec4
-		r->dirty_pipes |= drm_crtc_mask(&intel_crtc->base);
55efec4
-	}
55efec4
-}
55efec4
-
55efec4
-static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
55efec4
-{
55efec4
-	watermarks->wm_linetime[pipe] = 0;
55efec4
-	memset(watermarks->plane[pipe], 0,
55efec4
-	       sizeof(uint32_t) * 8 * I915_MAX_PLANES);
55efec4
-	memset(watermarks->plane_trans[pipe],
55efec4
-	       0, sizeof(uint32_t) * I915_MAX_PLANES);
55efec4
-	watermarks->plane_trans[pipe][PLANE_CURSOR] = 0;
55efec4
-}
55efec4
-
55efec4
 static int
55efec4
 skl_compute_ddb(struct drm_atomic_state *state)
55efec4
 {
0d24915
@@ -3783,6 +3711,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
55efec4
 	struct drm_i915_private *dev_priv = to_i915(dev);
55efec4
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
55efec4
 	struct intel_crtc *intel_crtc;
55efec4
+	struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
55efec4
 	unsigned realloc_pipes = dev_priv->active_crtcs;
55efec4
 	int ret;
55efec4
 
0d24915
@@ -3808,8 +3737,10 @@ skl_compute_ddb(struct drm_atomic_state *state)
55efec4
 	 * any other display updates race with this transaction, so we need
55efec4
 	 * to grab the lock on *all* CRTC's.
55efec4
 	 */
55efec4
-	if (intel_state->active_pipe_changes)
55efec4
+	if (intel_state->active_pipe_changes) {
55efec4
 		realloc_pipes = ~0;
55efec4
+		intel_state->wm_results.dirty_pipes = ~0;
55efec4
+	}
55efec4
 
55efec4
 	for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) {
55efec4
 		struct intel_crtc_state *cstate;
0d24915
@@ -3818,7 +3749,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
55efec4
 		if (IS_ERR(cstate))
55efec4
 			return PTR_ERR(cstate);
55efec4
 
55efec4
-		ret = skl_allocate_pipe_ddb(cstate, &intel_state->ddb);
55efec4
+		ret = skl_allocate_pipe_ddb(cstate, ddb);
55efec4
 		if (ret)
55efec4
 			return ret;
55efec4
 	}
0d24915
@@ -3831,8 +3762,11 @@ skl_compute_wm(struct drm_atomic_state *state)
55efec4
 {
55efec4
 	struct drm_crtc *crtc;
55efec4
 	struct drm_crtc_state *cstate;
55efec4
-	int ret, i;
55efec4
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
55efec4
+	struct skl_wm_values *results = &intel_state->wm_results;
55efec4
+	struct skl_pipe_wm *pipe_wm;
55efec4
 	bool changed = false;
55efec4
+	int ret, i;
55efec4
 
55efec4
 	/*
55efec4
 	 * If this transaction isn't actually touching any CRTC's, don't
0d24915
@@ -3847,10 +3781,45 @@ skl_compute_wm(struct drm_atomic_state *state)
55efec4
 	if (!changed)
55efec4
 		return 0;
55efec4
 
55efec4
+	/* Clear all dirty flags */
55efec4
+	results->dirty_pipes = 0;
55efec4
+
55efec4
 	ret = skl_compute_ddb(state);
55efec4
 	if (ret)
55efec4
 		return ret;
55efec4
 
55efec4
+	/*
55efec4
+	 * Calculate WM's for all pipes that are part of this transaction.
55efec4
+	 * Note that the DDB allocation above may have added more CRTC's that
55efec4
+	 * weren't otherwise being modified (and set bits in dirty_pipes) if
55efec4
+	 * pipe allocations had to change.
55efec4
+	 *
55efec4
+	 * FIXME:  Now that we're doing this in the atomic check phase, we
55efec4
+	 * should allow skl_update_pipe_wm() to return failure in cases where
55efec4
+	 * no suitable watermark values can be found.
55efec4
+	 */
55efec4
+	for_each_crtc_in_state(state, crtc, cstate, i) {
55efec4
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
55efec4
+		struct intel_crtc_state *intel_cstate =
55efec4
+			to_intel_crtc_state(cstate);
55efec4
+
55efec4
+		pipe_wm = &intel_cstate->wm.skl.optimal;
55efec4
+		ret = skl_update_pipe_wm(cstate, &results->ddb, pipe_wm,
55efec4
+					 &changed);
55efec4
+		if (ret)
55efec4
+			return ret;
55efec4
+
55efec4
+		if (changed)
55efec4
+			results->dirty_pipes |= drm_crtc_mask(crtc);
55efec4
+
55efec4
+		if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
55efec4
+			/* This pipe's WM's did not change */
55efec4
+			continue;
55efec4
+
0d24915
+		intel_cstate->update_wm_pre = true;
55efec4
+		skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
55efec4
+	}
55efec4
+
55efec4
 	return 0;
55efec4
 }
55efec4
 
0d24915
@@ -3862,26 +3831,21 @@ static void skl_update_wm(struct drm_crtc *crtc)
55efec4
 	struct skl_wm_values *results = &dev_priv->wm.skl_results;
55efec4
 	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
55efec4
 	struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
55efec4
-	bool wm_changed;
0d24915
-
55efec4
-	/* Clear all dirty flags */
55efec4
-	results->dirty_pipes = 0;
0d24915
 
55efec4
-	skl_clear_wm(results, intel_crtc->pipe);
55efec4
-
55efec4
-	skl_update_pipe_wm(crtc->state, &results->ddb, pipe_wm, &wm_changed);
55efec4
-	if (!wm_changed)
55efec4
+	if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
55efec4
 		return;
55efec4
 
55efec4
-	skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
55efec4
-	results->dirty_pipes |= drm_crtc_mask(&intel_crtc->base);
55efec4
+	intel_crtc->wm.active.skl = *pipe_wm;
0d24915
+
0d24915
+	mutex_lock(&dev_priv->wm.wm_mutex);
55efec4
 
55efec4
-	skl_update_other_pipe_wm(dev, crtc, results);
55efec4
 	skl_write_wm_values(dev_priv, results);
55efec4
 	skl_flush_wm_values(dev_priv, results);
55efec4
 
0d24915
 	/* store the new configuration */
0d24915
 	dev_priv->wm.skl_hw = *results;
0d24915
+
0d24915
+	mutex_unlock(&dev_priv->wm.wm_mutex);
0d24915
 }
0d24915
 
0d24915
 static void ilk_compute_wm_config(struct drm_device *dev,
55efec4
-- 
55efec4
2.7.4
55efec4