diff mbox

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

Message ID 20170608095135.21825-2-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson June 8, 2017, 9:51 a.m. UTC
During cleanup we release the VMA of the previous framebuffer. 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. Once
again we dream of the legendary vblank worker.

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

Patch

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;