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