[PATCH 1/4] drm/atomic: Treat a nonblocking commit following a blocking commit as blocking commit

Ville Syrjala ville.syrjala at linux.intel.com
Fri Sep 16 16:33:28 UTC 2022


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

Currently a nonblocking commit will actually block if it is
preceded by a blocking commit. It just happens block on the
mutex rather than on the completion. I shall call these as
not-actually-nonblocking commits.

I would like to make blocking commits execute locklessly,
just as nonblocking commits already do. The main benefit
would that parallel TEST_ONLY commits would not get blocked
on the mutexes until the parallel blocking commit is done.
To achieve that without a significant change in behaviour
for the not-actually-nonblocking commits let's treat them
exactly the same as blocking commit, ie. instead of
returning -EBUSY they will just block.

Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Cc: Rob Clark <robdclark at gmail.com>
Cc: Simon Ser <contact at emersion.fr>
Cc: Pekka Paalanen <pekka.paalanen at collabora.com>
Cc: Jonas Ådahl <jadahl at gmail.com>
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 19 ++++++++++++-------
 include/drm/drm_atomic.h            |  7 +++++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ee5fea48b5cb..bff087674cb5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2109,7 +2109,7 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock)
 			 * Userspace is not allowed to get ahead of the previous
 			 * commit with nonblocking ones.
 			 */
-			if (!completed && nonblock) {
+			if (!completed && nonblock && commit->nonblock) {
 				spin_unlock(&crtc->commit_lock);
 				drm_dbg_atomic(crtc->dev,
 					       "[CRTC:%d:%s] busy with a previous commit\n",
@@ -2152,7 +2152,7 @@ static void release_crtc_commit(struct completion *completion)
 	drm_crtc_commit_put(commit);
 }
 
-static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc)
+static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc, bool nonblock)
 {
 	init_completion(&commit->flip_done);
 	init_completion(&commit->hw_done);
@@ -2160,10 +2160,11 @@ static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc)
 	INIT_LIST_HEAD(&commit->commit_entry);
 	kref_init(&commit->ref);
 	commit->crtc = crtc;
+	commit->nonblock = nonblock;
 }
 
 static struct drm_crtc_commit *
-crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
+crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc, bool nonblock)
 {
 	if (crtc) {
 		struct drm_crtc_state *new_crtc_state;
@@ -2178,7 +2179,7 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
 		if (!state->fake_commit)
 			return NULL;
 
-		init_commit(state->fake_commit, NULL);
+		init_commit(state->fake_commit, NULL, nonblock);
 	}
 
 	return state->fake_commit;
@@ -2250,7 +2251,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		if (!commit)
 			return -ENOMEM;
 
-		init_commit(commit, crtc);
+		init_commit(commit, crtc, nonblock);
 
 		new_crtc_state->commit = commit;
 
@@ -2299,6 +2300,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		 * commit with nonblocking ones.
 		 */
 		if (nonblock && old_conn_state->commit &&
+		    old_conn_state->commit->nonblock &&
 		    !try_wait_for_completion(&old_conn_state->commit->flip_done)) {
 			drm_dbg_atomic(conn->dev,
 				       "[CONNECTOR:%d:%s] busy with a previous commit\n",
@@ -2308,7 +2310,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		}
 
 		/* Always track connectors explicitly for e.g. link retraining. */
-		commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc);
+		commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc,
+					     nonblock);
 		if (!commit)
 			return -ENOMEM;
 
@@ -2321,6 +2324,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		 * commit with nonblocking ones.
 		 */
 		if (nonblock && old_plane_state->commit &&
+		    old_plane_state->commit->nonblock &&
 		    !try_wait_for_completion(&old_plane_state->commit->flip_done)) {
 			drm_dbg_atomic(plane->dev,
 				       "[PLANE:%d:%s] busy with a previous commit\n",
@@ -2330,7 +2334,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		}
 
 		/* Always track planes explicitly for async pageflip support. */
-		commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
+		commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc,
+					     nonblock);
 		if (!commit)
 			return -ENOMEM;
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 10b1990bc1f6..0924c322ddfb 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -155,6 +155,13 @@ struct drm_crtc_commit {
 	 * used by the free code to remove the second reference if commit fails.
 	 */
 	bool abort_completion;
+
+	/**
+	 * @nonblock:
+	 *
+	 * Nonblocking commit?
+	 */
+	bool nonblock;
 };
 
 struct __drm_planes_state {
-- 
2.35.1



More information about the dri-devel mailing list