From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> 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@xxxxxxxx> Cc: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> Cc: Rob Clark <robdclark@xxxxxxxxx> Cc: Simon Ser <contact@xxxxxxxxxxx> Cc: Pekka Paalanen <pekka.paalanen@xxxxxxxxxxxxx> Cc: Jonas Ådahl <jadahl@xxxxxxxxx> Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- 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