0903551
From 71136125cc79dab464a0139dbf0c02891aa9ce6e Mon Sep 17 00:00:00 2001
0903551
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
0903551
Date: Mon, 20 Jun 2016 12:41:46 +0200
0903551
Subject: [PATCH 15/17] drm/i915/gen9: Calculate watermarks during atomic
0903551
 'check' (v2)
0903551
0903551
Upstream: since drm-intel-next-2016-05-22
0903551
commit 734fa01f3a17ac80d2d53cee0b05b246c03df0e4
0903551
0903551
Author:     Matt Roper <matthew.d.roper@intel.com>
0903551
AuthorDate: Thu May 12 15:11:40 2016 -0700
0903551
Commit:     Matt Roper <matthew.d.roper@intel.com>
0903551
CommitDate: Fri May 13 07:35:48 2016 -0700
0903551
0903551
    drm/i915/gen9: Calculate watermarks during atomic 'check' (v2)
0903551
0903551
    Moving watermark calculation into the check phase will allow us to to
0903551
    reject display configurations for which there are no valid watermark
0903551
    values before we start trying to program the hardware (although those
0903551
    tests will come in a subsequent patch).
0903551
0903551
    Another advantage of moving this calculation to the check phase is that
0903551
    we can calculate the watermarks in a single shot as part of the atomic
0903551
    transaction.  The watermark interfaces we inherited from our legacy
0903551
    modesetting days are a bit broken in the atomic design because they use
0903551
    per-crtc entry points but actually re-calculate and re-program something
0903551
    that is really more of a global state.  That worked okay in the legacy
0903551
    modesetting world because operations only ever updated a single CRTC at
0903551
    a time.  However in the atomic world, a transaction can involve multiple
0903551
    CRTC's, which means we wind up computing and programming the watermarks
0903551
    NxN times (where N is the number of CRTC's involved).  With this patch
0903551
    we eliminate the redundant re-calculation of watermark data for atomic
0903551
    states (which was the cause of the WARN_ON(!wm_changed) problems that
0903551
    have plagued us for a while).
0903551
0903551
    We still need to work on the 'commit' side of watermark handling so that
0903551
    we aren't doing redundant NxN programming of watermarks, but that's
0903551
    content for future patches.
0903551
0903551
    v2:
0903551
     - Bail out of skl_write_wm_values() if the CRTC isn't active.  Now that
0903551
       we set dirty_pipes to ~0 if the active pipes change (because
0903551
       we need to deal with DDB changes), we can now wind up here for
0903551
       disabled pipes, whereas we couldn't before.
0903551
0903551
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89055
0903551
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92181
0903551
    Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
0903551
    Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
0903551
    Tested-by: Daniel Stone <daniels@collabora.com>
0903551
    Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
0903551
    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 +-
0903551
 drivers/gpu/drm/i915/intel_drv.h     |  14 +++-
0903551
 drivers/gpu/drm/i915/intel_pm.c      | 135 ++++++++++++-----------------------
0903551
 3 files changed, 61 insertions(+), 90 deletions(-)
0903551
0903551
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
0903551
index 9ac2346..1726ea4 100644
0903551
--- a/drivers/gpu/drm/i915/intel_display.c
0903551
+++ b/drivers/gpu/drm/i915/intel_display.c
0903551
@@ -13522,7 +13522,7 @@ static int intel_atomic_commit(struct drm_device *dev,
0903551
 	drm_atomic_helper_swap_state(dev, state);
0903551
 	dev_priv->wm.config = to_intel_atomic_state(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;
0903551
 
0903551
 	if (intel_state->modeset) {
0903551
 		memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
0903551
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
0903551
index 4d6336a..e5543b8 100644
0903551
--- a/drivers/gpu/drm/i915/intel_drv.h
0903551
+++ b/drivers/gpu/drm/i915/intel_drv.h
0903551
@@ -273,7 +273,7 @@ struct intel_atomic_state {
0903551
 	struct intel_wm_config wm_config;
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
@@ -1661,6 +1661,18 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
0903551
 
0903551
 	return to_intel_crtc_state(crtc_state);
0903551
 }
0903551
+
0903551
+static inline struct intel_plane_state *
0903551
+intel_atomic_get_existing_plane_state(struct drm_atomic_state *state,
0903551
+                                     struct intel_plane *plane)
0903551
+{
0903551
+       struct drm_plane_state *plane_state;
0903551
+
0903551
+       plane_state = drm_atomic_get_existing_plane_state(state, &plane->base);
0903551
+
0903551
+       return to_intel_plane_state(plane_state);
0903551
+}
0903551
+
0903551
 int intel_atomic_setup_scalers(struct drm_device *dev,
0903551
 	struct intel_crtc *intel_crtc,
0903551
 	struct intel_crtc_state *crtc_state);
0903551
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
0903551
index ec22d93..73e5242 100644
0903551
--- a/drivers/gpu/drm/i915/intel_pm.c
0903551
+++ b/drivers/gpu/drm/i915/intel_pm.c
0903551
@@ -3160,23 +3160,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,
0903551
@@ -3472,6 +3455,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
 
0903551
@@ -3655,66 +3640,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
 {
0903551
@@ -3722,6 +3650,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
 
0903551
@@ -3747,8 +3676,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;
0903551
@@ -3757,7 +3688,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
 	}
0903551
@@ -3770,8 +3701,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
0903551
@@ -3786,10 +3720,44 @@ 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
+
0903551
+		skl_compute_wm_results(crtc->dev, pipe_wm, results, intel_crtc);
0903551
+	}
0903551
+
0903551
 	return 0;
0903551
 }
0903551
 
0903551
@@ -3801,21 +3769,12 @@ 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;
0903551
 
0903551
-	/* Clear all dirty flags */
0903551
-	results->dirty_pipes = 0;
0903551
-
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;
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
 
0903551
-- 
0903551
2.7.4
0903551