[PATCH 2/2] drm/i915: Defer cleanup of active KMS state

Chris Wilson chris at chris-wilson.co.uk
Thu Jun 8 08:32:19 UTC 2017


During cleanup we release the VMA of the previous fraembuffer. This
requires taking a struct_mutex, and potential recursion when handling a
reset. A simple device here is to move that locking into its own work
and we can avoid blocking on it for the reset by waiting on the flip
completion (and not cleanup completion) instead. Ideally this reduces
the duration of a blocking KMS operation by offloading the cleanup.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c | 53 +++++++++++++++++++++++++++++-------
 1 file changed, 43 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 121fdd278fcd..0a1170de96e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12982,7 +12982,23 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work)
 	intel_atomic_helper_free_state(dev_priv);
 }
 
-static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+static void intel_atomic_commit_cleanup(struct work_struct *work)
+{
+	struct drm_atomic_state *state =
+		container_of(work, struct drm_atomic_state, commit_work);
+	struct drm_device *dev = state->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+
+	drm_atomic_helper_cleanup_planes(dev, state);
+	drm_atomic_helper_commit_cleanup_done(state);
+
+	drm_atomic_state_put(state);
+
+	intel_atomic_helper_free_state(dev_priv);
+}
+
+static void intel_atomic_commit_tail(struct drm_atomic_state *state,
+				     bool nonblock)
 {
 	struct drm_device *dev = state->dev;
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
@@ -13134,13 +13150,12 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
 	}
 
-	drm_atomic_helper_cleanup_planes(dev, state);
-
-	drm_atomic_helper_commit_cleanup_done(state);
-
-	drm_atomic_state_put(state);
-
-	intel_atomic_helper_free_state(dev_priv);
+	if (!nonblock) {
+		INIT_WORK(&state->commit_work, intel_atomic_commit_cleanup);
+		schedule_work(&state->commit_work);
+	} else {
+		intel_atomic_commit_cleanup(&state->commit_work);
+	}
 }
 
 static void intel_atomic_commit_work(struct work_struct *work)
@@ -13148,7 +13163,7 @@ static void intel_atomic_commit_work(struct work_struct *work)
 	struct drm_atomic_state *state =
 		container_of(work, struct drm_atomic_state, commit_work);
 
-	intel_atomic_commit_tail(state);
+	intel_atomic_commit_tail(state, true);
 }
 
 static int __i915_sw_fence_call
@@ -13190,6 +13205,23 @@ static void intel_atomic_track_fbs(struct drm_atomic_state *state)
 				  to_intel_plane(plane)->frontbuffer_bit);
 }
 
+static void intel_atomic_state_wait_for_flips(struct intel_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	int i;
+
+	for_each_new_crtc_in_state(&state->base, crtc, crtc_state, i) {
+		struct drm_crtc_commit *commit = state->base.crtcs[i].commit;
+		long ret;
+
+		ret = wait_for_completion_timeout(&commit->flip_done, HZ);
+		if (ret == 0)
+			DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",
+				  crtc->base.id, crtc->name);
+	}
+}
+
 /**
  * intel_atomic_commit - commit validated state object
  * @dev: DRM device
@@ -13265,7 +13297,8 @@ static int intel_atomic_commit(struct drm_device *dev,
 	i915_sw_fence_commit(&intel_state->commit_ready);
 	if (!nonblock) {
 		i915_sw_fence_wait(&intel_state->commit_ready);
-		intel_atomic_commit_tail(state);
+		intel_atomic_commit_tail(state, false);
+		intel_atomic_state_wait_for_flips(intel_state);
 	}
 
 	return 0;
-- 
2.11.0



More information about the Intel-gfx-trybot mailing list