7d2c2f2
From c336cf7907da066978af5f2d7d4acd88c78b8c86 Mon Sep 17 00:00:00 2001
7d2c2f2
From: Matt Roper <matthew.d.roper@intel.com>
7d2c2f2
Date: Thu, 12 May 2016 07:06:01 -0700
7d2c2f2
Subject: [PATCH 07/17] drm/i915/gen9: Allow skl_allocate_pipe_ddb() to operate
7d2c2f2
 on in-flight state (v3)
7d2c2f2
7d2c2f2
We eventually want to calculate watermark values at atomic 'check' time
7d2c2f2
instead of atomic 'commit' time so that any requested configurations
7d2c2f2
that result in impossible watermark requirements are properly rejected.
7d2c2f2
The first step along this path is to allocate the DDB at atomic 'check'
7d2c2f2
time.  As we perform this transition, allow the main allocation function
7d2c2f2
to operate successfully on either an in-flight state or an
7d2c2f2
already-commited state.  Once we complete the transition in a future
7d2c2f2
patch, we'll come back and remove the unnecessary logic for the
7d2c2f2
already-committed case.
7d2c2f2
7d2c2f2
v2: Rebase/refactor; we should no longer need to grab extra plane states
7d2c2f2
    while allocating the DDB since we can pull cached data rates and
7d2c2f2
    minimum block counts from the CRTC state for any planes that aren't
7d2c2f2
    being modified by this transaction.
7d2c2f2
7d2c2f2
v3:
7d2c2f2
 - Simplify memsets to clear DDB plane entries.  (Maarten)
7d2c2f2
 - Drop a redundant memset of plane[pipe][PLANE_CURSOR] that was added
7d2c2f2
   by an earlier Coccinelle patch.  (Maarten)
7d2c2f2
 - Assign *num_active at the top of skl_ddb_get_pipe_allocation_limits()
7d2c2f2
   so that no code paths return without setting it.  (kbuild robot)
7d2c2f2
7d2c2f2
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
7d2c2f2
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
7d2c2f2
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
7d2c2f2
Link: http://patchwork.freedesktop.org/patch/msgid/1463061971-19638-8-git-send-email-matthew.d.roper@intel.com
7d2c2f2
---
7d2c2f2
 drivers/gpu/drm/i915/i915_drv.h |   6 ++
7d2c2f2
 drivers/gpu/drm/i915/intel_pm.c | 179 +++++++++++++++++++++++++++++-----------
7d2c2f2
 2 files changed, 139 insertions(+), 46 deletions(-)
7d2c2f2
7d2c2f2
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
7d2c2f2
index 7c334e9..611c128 100644
7d2c2f2
--- a/drivers/gpu/drm/i915/i915_drv.h
7d2c2f2
+++ b/drivers/gpu/drm/i915/i915_drv.h
7d2c2f2
@@ -324,6 +324,12 @@ struct i915_hotplug {
7d2c2f2
 			    &dev->mode_config.plane_list,	\
7d2c2f2
 			    base.head)
7d2c2f2
 
7d2c2f2
+#define for_each_intel_plane_mask(dev, intel_plane, plane_mask)		\
7d2c2f2
+	list_for_each_entry(intel_plane, &dev->mode_config.plane_list,	\
7d2c2f2
+			    base.head)					\
7d2c2f2
+		for_each_if ((plane_mask) &				\
7d2c2f2
+			     (1 << drm_plane_index(&intel_plane->base)))
7d2c2f2
+
7d2c2f2
 #define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane)	\
7d2c2f2
 	list_for_each_entry(intel_plane,				\
7d2c2f2
 			    &(dev)->mode_config.plane_list,		\
7d2c2f2
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
7d2c2f2
index 6c7a048..f009d43 100644
7d2c2f2
--- a/drivers/gpu/drm/i915/intel_pm.c
7d2c2f2
+++ b/drivers/gpu/drm/i915/intel_pm.c
7d2c2f2
@@ -2849,13 +2849,25 @@ skl_wm_plane_id(const struct intel_plane *plane)
7d2c2f2
 static void
7d2c2f2
 skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
7d2c2f2
 				   const struct intel_crtc_state *cstate,
7d2c2f2
-				   const struct intel_wm_config *config,
7d2c2f2
-				   struct skl_ddb_entry *alloc /* out */)
7d2c2f2
+				   struct intel_wm_config *config,
7d2c2f2
+				   struct skl_ddb_entry *alloc, /* out */
7d2c2f2
+				   int *num_active /* out */)
7d2c2f2
 {
7d2c2f2
+	struct drm_atomic_state *state = cstate->base.state;
7d2c2f2
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
7d2c2f2
+	struct drm_i915_private *dev_priv = to_i915(dev);
7d2c2f2
 	struct drm_crtc *for_crtc = cstate->base.crtc;
7d2c2f2
 	struct drm_crtc *crtc;
7d2c2f2
 	unsigned int pipe_size, ddb_size;
7d2c2f2
 	int nth_active_pipe;
7d2c2f2
+	int pipe = to_intel_crtc(for_crtc)->pipe;
7d2c2f2
+
7d2c2f2
+	if (intel_state && intel_state->active_pipe_changes)
7d2c2f2
+		*num_active = hweight32(intel_state->active_crtcs);
7d2c2f2
+	else if (intel_state)
7d2c2f2
+		*num_active = hweight32(dev_priv->active_crtcs);
7d2c2f2
+	else
7d2c2f2
+		*num_active = config->num_pipes_active;
7d2c2f2
 
7d2c2f2
 	if (!cstate->base.active) {
7d2c2f2
 		alloc->start = 0;
7d2c2f2
@@ -2870,25 +2882,56 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
7d2c2f2
 
7d2c2f2
 	ddb_size -= 4; /* 4 blocks for bypass path allocation */
7d2c2f2
 
7d2c2f2
-	nth_active_pipe = 0;
7d2c2f2
-	for_each_crtc(dev, crtc) {
7d2c2f2
-		if (!to_intel_crtc(crtc)->active)
7d2c2f2
-			continue;
7d2c2f2
+	/*
7d2c2f2
+	 * FIXME: At the moment we may be called on either in-flight or fully
7d2c2f2
+	 * committed cstate's.  Once we fully move DDB allocation in the check
7d2c2f2
+	 * phase, we'll only be called on in-flight states and the 'else'
7d2c2f2
+	 * branch here will go away.
7d2c2f2
+	 *
7d2c2f2
+	 * The 'else' branch is slightly racy here, but it was racy to begin
7d2c2f2
+	 * with; since it's going away soon, no effort is made to address that.
7d2c2f2
+	 */
7d2c2f2
+	if (state) {
7d2c2f2
+		/*
7d2c2f2
+		 * If the state doesn't change the active CRTC's, then there's
7d2c2f2
+		 * no need to recalculate; the existing pipe allocation limits
7d2c2f2
+		 * should remain unchanged.  Note that we're safe from racing
7d2c2f2
+		 * commits since any racing commit that changes the active CRTC
7d2c2f2
+		 * list would need to grab _all_ crtc locks, including the one
7d2c2f2
+		 * we currently hold.
7d2c2f2
+		 */
7d2c2f2
+		if (!intel_state->active_pipe_changes) {
7d2c2f2
+			*alloc = dev_priv->wm.skl_hw.ddb.pipe[pipe];
7d2c2f2
+			return;
7d2c2f2
+		}
7d2c2f2
 
7d2c2f2
-		if (crtc == for_crtc)
7d2c2f2
-			break;
7d2c2f2
+		nth_active_pipe = hweight32(intel_state->active_crtcs &
7d2c2f2
+					    (drm_crtc_mask(for_crtc) - 1));
7d2c2f2
+		pipe_size = ddb_size / hweight32(intel_state->active_crtcs);
7d2c2f2
+		alloc->start = nth_active_pipe * ddb_size / *num_active;
7d2c2f2
+		alloc->end = alloc->start + pipe_size;
7d2c2f2
+	} else {
7d2c2f2
+		nth_active_pipe = 0;
7d2c2f2
+		for_each_crtc(dev, crtc) {
7d2c2f2
+			if (!to_intel_crtc(crtc)->active)
7d2c2f2
+				continue;
7d2c2f2
 
7d2c2f2
-		nth_active_pipe++;
7d2c2f2
-	}
7d2c2f2
+			if (crtc == for_crtc)
7d2c2f2
+				break;
7d2c2f2
 
7d2c2f2
-	pipe_size = ddb_size / config->num_pipes_active;
7d2c2f2
-	alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active;
7d2c2f2
-	alloc->end = alloc->start + pipe_size;
7d2c2f2
+			nth_active_pipe++;
7d2c2f2
+		}
7d2c2f2
+
7d2c2f2
+		pipe_size = ddb_size / config->num_pipes_active;
7d2c2f2
+		alloc->start = nth_active_pipe * ddb_size /
7d2c2f2
+			config->num_pipes_active;
7d2c2f2
+		alloc->end = alloc->start + pipe_size;
7d2c2f2
+	}
7d2c2f2
 }
7d2c2f2
 
7d2c2f2
-static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
7d2c2f2
+static unsigned int skl_cursor_allocation(int num_active)
7d2c2f2
 {
7d2c2f2
-	if (config->num_pipes_active == 1)
7d2c2f2
+	if (num_active == 1)
7d2c2f2
 		return 32;
7d2c2f2
 
7d2c2f2
 	return 8;
7d2c2f2
@@ -3054,33 +3097,44 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate)
7d2c2f2
 	return total_data_rate;
7d2c2f2
 }
7d2c2f2
 
7d2c2f2
-static void
7d2c2f2
+static int
7d2c2f2
 skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
7d2c2f2
 		      struct skl_ddb_allocation *ddb /* out */)
7d2c2f2
 {
7d2c2f2
+	struct drm_atomic_state *state = cstate->base.state;
7d2c2f2
 	struct drm_crtc *crtc = cstate->base.crtc;
7d2c2f2
 	struct drm_device *dev = crtc->dev;
7d2c2f2
 	struct drm_i915_private *dev_priv = to_i915(dev);
7d2c2f2
 	struct intel_wm_config *config = &dev_priv->wm.config;
7d2c2f2
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
7d2c2f2
 	struct intel_plane *intel_plane;
7d2c2f2
+	struct drm_plane *plane;
7d2c2f2
+	struct drm_plane_state *pstate;
7d2c2f2
 	enum pipe pipe = intel_crtc->pipe;
7d2c2f2
 	struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
7d2c2f2
 	uint16_t alloc_size, start, cursor_blocks;
7d2c2f2
 	uint16_t *minimum = cstate->wm.skl.minimum_blocks;
7d2c2f2
 	uint16_t *y_minimum = cstate->wm.skl.minimum_y_blocks;
7d2c2f2
 	unsigned int total_data_rate;
7d2c2f2
+	int num_active;
7d2c2f2
+	int id, i;
7d2c2f2
 
7d2c2f2
-	skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
7d2c2f2
+	if (!cstate->base.active) {
7d2c2f2
+		ddb->pipe[pipe].start = ddb->pipe[pipe].end = 0;
7d2c2f2
+		memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
7d2c2f2
+		memset(ddb->y_plane[pipe], 0, sizeof(ddb->y_plane[pipe]));
7d2c2f2
+		return 0;
7d2c2f2
+	}
7d2c2f2
+
7d2c2f2
+	skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc,
7d2c2f2
+					   &num_active);
7d2c2f2
 	alloc_size = skl_ddb_entry_size(alloc);
7d2c2f2
 	if (alloc_size == 0) {
7d2c2f2
 		memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
7d2c2f2
-		memset(&ddb->plane[pipe][PLANE_CURSOR], 0,
7d2c2f2
-		       sizeof(ddb->plane[pipe][PLANE_CURSOR]));
7d2c2f2
-		return;
7d2c2f2
+		return 0;
7d2c2f2
 	}
7d2c2f2
 
7d2c2f2
-	cursor_blocks = skl_cursor_allocation(config);
7d2c2f2
+	cursor_blocks = skl_cursor_allocation(num_active);
7d2c2f2
 	ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - cursor_blocks;
7d2c2f2
 	ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
7d2c2f2
 
7d2c2f2
@@ -3088,21 +3142,55 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
7d2c2f2
 	alloc->end -= cursor_blocks;
7d2c2f2
 
7d2c2f2
 	/* 1. Allocate the mininum required blocks for each active plane */
7d2c2f2
-	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
7d2c2f2
-		struct drm_plane *plane = &intel_plane->base;
7d2c2f2
-		struct drm_framebuffer *fb = plane->state->fb;
7d2c2f2
-		int id = skl_wm_plane_id(intel_plane);
7d2c2f2
+	/*
7d2c2f2
+	 * TODO: Remove support for already-committed state once we
7d2c2f2
+	 * only allocate DDB on in-flight states.
7d2c2f2
+	 */
7d2c2f2
+	if (state) {
7d2c2f2
+		for_each_plane_in_state(state, plane, pstate, i) {
7d2c2f2
+			intel_plane = to_intel_plane(plane);
7d2c2f2
+			id = skl_wm_plane_id(intel_plane);
7d2c2f2
 
7d2c2f2
-		if (!to_intel_plane_state(plane->state)->visible)
7d2c2f2
-			continue;
7d2c2f2
+			if (intel_plane->pipe != pipe)
7d2c2f2
+				continue;
7d2c2f2
 
7d2c2f2
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
7d2c2f2
-			continue;
7d2c2f2
+			if (!to_intel_plane_state(pstate)->visible) {
7d2c2f2
+				minimum[id] = 0;
7d2c2f2
+				y_minimum[id] = 0;
7d2c2f2
+				continue;
7d2c2f2
+			}
7d2c2f2
+			if (plane->type == DRM_PLANE_TYPE_CURSOR) {
7d2c2f2
+				minimum[id] = 0;
7d2c2f2
+				y_minimum[id] = 0;
7d2c2f2
+				continue;
7d2c2f2
+			}
7d2c2f2
+
7d2c2f2
+			minimum[id] = 8;
7d2c2f2
+			if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
7d2c2f2
+				y_minimum[id] = 8;
7d2c2f2
+			else
7d2c2f2
+				y_minimum[id] = 0;
7d2c2f2
+		}
7d2c2f2
+	} else {
7d2c2f2
+		for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
7d2c2f2
+			struct drm_plane *plane = &intel_plane->base;
7d2c2f2
+			struct drm_framebuffer *fb = plane->state->fb;
7d2c2f2
+			int id = skl_wm_plane_id(intel_plane);
7d2c2f2
+
7d2c2f2
+			if (!to_intel_plane_state(plane->state)->visible)
7d2c2f2
+				continue;
7d2c2f2
+
7d2c2f2
+			if (plane->type == DRM_PLANE_TYPE_CURSOR)
7d2c2f2
+				continue;
7d2c2f2
+
7d2c2f2
+			minimum[id] = 8;
7d2c2f2
+			y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
7d2c2f2
+		}
7d2c2f2
+	}
7d2c2f2
 
7d2c2f2
-		minimum[id] = 8;
7d2c2f2
-		alloc_size -= minimum[id];
7d2c2f2
-		y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
7d2c2f2
-		alloc_size -= y_minimum[id];
7d2c2f2
+	for (i = 0; i < PLANE_CURSOR; i++) {
7d2c2f2
+		alloc_size -= minimum[i];
7d2c2f2
+		alloc_size -= y_minimum[i];
7d2c2f2
 	}
7d2c2f2
 
7d2c2f2
 	/*
7d2c2f2
@@ -3113,21 +3201,14 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
7d2c2f2
 	 */
7d2c2f2
 	total_data_rate = skl_get_total_relative_data_rate(cstate);
7d2c2f2
 	if (total_data_rate == 0)
7d2c2f2
-		return;
7d2c2f2
+		return 0;
7d2c2f2
 
7d2c2f2
 	start = alloc->start;
7d2c2f2
 	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
7d2c2f2
-		struct drm_plane *plane = &intel_plane->base;
7d2c2f2
-		struct drm_plane_state *pstate = intel_plane->base.state;
7d2c2f2
 		unsigned int data_rate, y_data_rate;
7d2c2f2
 		uint16_t plane_blocks, y_plane_blocks = 0;
7d2c2f2
 		int id = skl_wm_plane_id(intel_plane);
7d2c2f2
 
7d2c2f2
-		if (!to_intel_plane_state(pstate)->visible)
7d2c2f2
-			continue;
7d2c2f2
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
7d2c2f2
-			continue;
7d2c2f2
-
7d2c2f2
 		data_rate = cstate->wm.skl.plane_data_rate[id];
7d2c2f2
 
7d2c2f2
 		/*
7d2c2f2
@@ -3139,8 +3220,11 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
7d2c2f2
 		plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
7d2c2f2
 					total_data_rate);
7d2c2f2
 
7d2c2f2
-		ddb->plane[pipe][id].start = start;
7d2c2f2
-		ddb->plane[pipe][id].end = start + plane_blocks;
7d2c2f2
+		/* Leave disabled planes at (0,0) */
7d2c2f2
+		if (data_rate) {
7d2c2f2
+			ddb->plane[pipe][id].start = start;
7d2c2f2
+			ddb->plane[pipe][id].end = start + plane_blocks;
7d2c2f2
+		}
7d2c2f2
 
7d2c2f2
 		start += plane_blocks;
7d2c2f2
 
7d2c2f2
@@ -3153,12 +3237,15 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
7d2c2f2
 		y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate,
7d2c2f2
 					total_data_rate);
7d2c2f2
 
7d2c2f2
-		ddb->y_plane[pipe][id].start = start;
7d2c2f2
-		ddb->y_plane[pipe][id].end = start + y_plane_blocks;
7d2c2f2
+		if (y_data_rate) {
7d2c2f2
+			ddb->y_plane[pipe][id].start = start;
7d2c2f2
+			ddb->y_plane[pipe][id].end = start + y_plane_blocks;
7d2c2f2
+		}
7d2c2f2
 
7d2c2f2
 		start += y_plane_blocks;
7d2c2f2
 	}
7d2c2f2
 
7d2c2f2
+	return 0;
7d2c2f2
 }
7d2c2f2
 
7d2c2f2
 static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_state *config)
7d2c2f2
@@ -3649,7 +3736,7 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc,
7d2c2f2
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
7d2c2f2
 	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
7d2c2f2
 
7d2c2f2
-	skl_allocate_pipe_ddb(cstate, ddb);
7d2c2f2
+	WARN_ON(skl_allocate_pipe_ddb(cstate, ddb) != 0);
7d2c2f2
 	skl_build_pipe_wm(cstate, ddb, pipe_wm);
7d2c2f2
 
7d2c2f2
 	if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
7d2c2f2
-- 
7d2c2f2
2.7.4
7d2c2f2