[PATCH 28/33] drm/i915: Plane granularity for atomic modesetting

Chris Wilson chris at chris-wilson.co.uk
Fri Sep 16 13:47:40 UTC 2016


Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_sw_fence.c |   8 +--
 drivers/gpu/drm/i915/i915_sw_fence.h |   9 +++
 drivers/gpu/drm/i915/intel_display.c | 135 +++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h     |   2 +
 drivers/gpu/drm/i915/intel_sprite.c  |   1 +
 5 files changed, 118 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
index 1fd20b69feea..6a977fc87669 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -38,17 +38,11 @@ static void i915_sw_fence_free(struct kref *kref)
 		kfree(fence);
 }
 
-static void i915_sw_fence_put(struct i915_sw_fence *fence)
+void i915_sw_fence_put(struct i915_sw_fence *fence)
 {
 	kref_put(&fence->kref, i915_sw_fence_free);
 }
 
-static struct i915_sw_fence *i915_sw_fence_get(struct i915_sw_fence *fence)
-{
-	kref_get(&fence->kref);
-	return fence;
-}
-
 static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
 					struct list_head *continuation)
 {
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h
index d221df381ec2..c098164af126 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.h
+++ b/drivers/gpu/drm/i915/i915_sw_fence.h
@@ -43,6 +43,15 @@ typedef int (*i915_sw_fence_notify_t)(struct i915_sw_fence *,
 void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn);
 void i915_sw_fence_commit(struct i915_sw_fence *fence);
 
+static inline struct i915_sw_fence *
+i915_sw_fence_get(struct i915_sw_fence *fence)
+{
+	kref_get(&fence->kref);
+	return fence;
+}
+
+void i915_sw_fence_put(struct i915_sw_fence *fence);
+
 int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
 				 struct i915_sw_fence *after,
 				 wait_queue_t *wq, gfp_t gfp);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 26f4d1acd96e..ae2020c9dd44 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14132,10 +14132,53 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
 		intel_unpin_fb_vma(vma);
 }
 
+static void track_last_commit(struct drm_plane *plane,
+			      struct drm_atomic_state *state)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+	struct i915_sw_fence *fence;
+
+	if (intel_plane->last_commit == &intel_state->commit_done)
+		return;
+
+	i915_sw_fence_get(&intel_state->commit_done);
+
+	spin_lock(&intel_plane->commit_lock);
+	fence = intel_plane->last_commit;
+	intel_plane->last_commit = &intel_state->commit_done;
+	spin_unlock(&intel_plane->commit_lock);
+
+	if (fence) {
+		i915_sw_fence_await_sw_fence(&intel_state->commit_ready, fence,
+					     NULL, GFP_KERNEL);
+		i915_sw_fence_put(fence);
+	}
+}
+
+static void track_last_modeset(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc,
+			       struct drm_crtc_state *crtc_state)
+{
+	struct drm_plane *plane;
+
+	if (!needs_modeset(crtc_state))
+		return;
+
+	drm_for_each_plane(plane, state->dev) {
+		if (to_intel_plane(plane)->pipe != drm_crtc_index(crtc))
+			continue;
+
+		track_last_commit(plane, state);
+	}
+}
+
 static int intel_atomic_commit_prepare_planes(struct drm_atomic_state *state)
 {
 	struct drm_plane *plane;
 	struct drm_plane_state *plane_state;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
 	int i, j, ret;
 
 	ret = mutex_lock_interruptible(&state->dev->struct_mutex);
@@ -14145,16 +14188,23 @@ static int intel_atomic_commit_prepare_planes(struct drm_atomic_state *state)
 	for_each_plane_in_state(state, plane, plane_state, i) {
 		ret = intel_prepare_plane_fb(plane, plane_state);
 		if (ret)
-			break;
+			goto err;
 	}
+	mutex_unlock(&state->dev->struct_mutex);
 
-	if (ret) {
-		for_each_plane_in_state(state, plane, plane_state, j) {
-			if (j >= i)
-				break;
+	for_each_crtc_in_state(state, crtc, crtc_state, i)
+		track_last_modeset(state, crtc, crtc_state);
+	for_each_plane_in_state(state, plane, plane_state, i)
+		track_last_commit(plane, state);
 
-			intel_cleanup_plane_fb(plane, plane_state);
-		}
+	return 0;
+
+err:
+	for_each_plane_in_state(state, plane, plane_state, j) {
+		if (j >= i)
+			break;
+
+		intel_cleanup_plane_fb(plane, plane_state);
 	}
 
 	mutex_unlock(&state->dev->struct_mutex);
@@ -14176,10 +14226,9 @@ static void intel_atomic_commit_cleanup_planes(struct drm_atomic_state *state)
 	mutex_unlock(&state->dev->struct_mutex);
 }
 
-static int intel_atomic_prepare_commit(struct drm_device *dev,
-				       struct drm_atomic_state *state)
+static int intel_atomic_prepare_commit(struct drm_atomic_state *state)
 {
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(state->dev);
 	struct drm_crtc_state *crtc_state;
 	struct drm_crtc *crtc;
 	int i, ret;
@@ -14379,6 +14428,18 @@ static void skl_update_crtcs(struct drm_atomic_state *state,
 	} while (progress);
 }
 
+static void intel_atomic_track_fbs(struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_plane_state;
+	struct drm_plane *plane;
+	int i;
+
+	for_each_plane_in_state(state, plane, old_plane_state, i)
+		i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
+				  intel_fb_obj(plane->state->fb),
+				  to_intel_plane(plane)->frontbuffer_bit);
+}
+
 static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 {
 	struct drm_device *dev = state->dev;
@@ -14392,7 +14453,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	unsigned crtc_vblank_mask = 0;
 	int i;
 
-	drm_atomic_helper_wait_for_dependencies(state);
+	drm_atomic_helper_swap_state(state, false);
+	dev_priv->wm.distrust_bios_wm = false;
+	dev_priv->wm.skl_results = intel_state->wm_results;
+	intel_shared_dpll_commit(state);
+	intel_atomic_track_fbs(state);
 
 	if (intel_state->modeset) {
 		memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
@@ -14517,6 +14582,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	    skl_can_enable_sagv(state))
 		skl_enable_sagv(dev_priv);
 
+	i915_sw_fence_commit(&intel_state->commit_done);
 	drm_atomic_helper_commit_hw_done(state);
 
 	if (intel_state->modeset)
@@ -14559,7 +14625,9 @@ intel_atomic_commit_ready(struct i915_sw_fence *fence,
 
 	switch (notify) {
 	case FENCE_COMPLETE:
-		if (state->base.commit_work.func)
+		if (IS_ERR(state->base.commit_work.func))
+			i915_sw_fence_commit(&state->commit_done);
+		else if (state->base.commit_work.func)
 			queue_work(system_unbound_wq, &state->base.commit_work);
 		break;
 
@@ -14571,16 +14639,23 @@ intel_atomic_commit_ready(struct i915_sw_fence *fence,
 	return NOTIFY_DONE;
 }
 
-static void intel_atomic_track_fbs(struct drm_atomic_state *state)
+static int __i915_sw_fence_call
+intel_atomic_commit_done(struct i915_sw_fence *fence,
+			 enum i915_sw_fence_notify notify)
 {
-	struct drm_plane_state *old_plane_state;
-	struct drm_plane *plane;
-	int i;
+	struct intel_atomic_state *state =
+		container_of(fence, struct intel_atomic_state, commit_done);
 
-	for_each_plane_in_state(state, plane, old_plane_state, i)
-		i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
-				  intel_fb_obj(plane->state->fb),
-				  to_intel_plane(plane)->frontbuffer_bit);
+	switch (notify) {
+	case FENCE_COMPLETE:
+		break;
+
+	case FENCE_FREE:
+		drm_atomic_state_put(&state->base);
+		break;
+	}
+
+	return NOTIFY_DONE;
 }
 
 /**
@@ -14604,15 +14679,14 @@ static int intel_atomic_commit(struct drm_device *dev,
 			       bool nonblock)
 {
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	int ret = 0;
+	int ret;
 
 	if (intel_state->modeset && nonblock) {
 		DRM_DEBUG_KMS("nonblocking commit for modeset not yet implemented.\n");
 		return -EINVAL;
 	}
 
-	ret = drm_atomic_helper_setup_commit(state, nonblock);
+	ret = drm_atomic_helper_setup_commit(state, false);
 	if (ret)
 		return ret;
 
@@ -14620,19 +14694,18 @@ static int intel_atomic_commit(struct drm_device *dev,
 	i915_sw_fence_init(&intel_state->commit_ready,
 			   intel_atomic_commit_ready);
 
-	ret = intel_atomic_prepare_commit(dev, state);
+	drm_atomic_state_get(state);
+	i915_sw_fence_init(&intel_state->commit_done,
+			   intel_atomic_commit_done);
+
+	ret = intel_atomic_prepare_commit(state);
 	if (ret) {
 		DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
+		INIT_WORK(&state->commit_work, ERR_PTR(ret));
 		i915_sw_fence_commit(&intel_state->commit_ready);
 		return ret;
 	}
 
-	drm_atomic_helper_swap_state(state, true);
-	dev_priv->wm.distrust_bios_wm = false;
-	dev_priv->wm.skl_results = intel_state->wm_results;
-	intel_shared_dpll_commit(state);
-	intel_atomic_track_fbs(state);
-
 	drm_atomic_state_get(state);
 	INIT_WORK(&state->commit_work,
 		  nonblock ? intel_atomic_commit_work : NULL);
@@ -14954,6 +15027,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 	if (INTEL_INFO(dev)->gen >= 4)
 		intel_create_rotation_property(dev, primary);
 
+	spin_lock_init(&primary->commit_lock);
 	drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
 
 	return &primary->base;
@@ -15124,6 +15198,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
 	if (INTEL_INFO(dev)->gen >=9)
 		state->scaler_id = -1;
 
+	spin_lock_init(&cursor->commit_lock);
 	drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
 
 	return &cursor->base;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d9599f960e2d..d81335bcfe97 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -363,6 +363,7 @@ struct intel_atomic_state {
 	struct skl_wm_values wm_results;
 
 	struct i915_sw_fence commit_ready;
+	struct i915_sw_fence commit_done;
 };
 
 struct intel_plane_state {
@@ -772,6 +773,7 @@ struct intel_plane {
 	uint32_t frontbuffer_bit;
 
 	struct i915_sw_fence *last_commit;
+	spinlock_t commit_lock;
 
 	/* Since we need to change the watermarks before/after
 	 * enabling/disabling the planes, we need to store the parameters here
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 44da0287c260..5095987d905d 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -1143,6 +1143,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 
 	intel_create_rotation_property(dev, intel_plane);
 
+	spin_lock_init(&intel_plane->commit_lock);
 	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
 
 	return 0;
-- 
2.9.3



More information about the Intel-gfx-trybot mailing list