|
@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
|
|
|
new_crtc_state->event->base.completion = &commit->flip_done;
|
|
|
new_crtc_state->event->base.completion_release = release_crtc_commit;
|
|
|
drm_crtc_commit_get(commit);
|
|
|
+
|
|
|
+ commit->abort_completion = true;
|
|
|
}
|
|
|
|
|
|
for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
|
|
@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
|
|
|
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
|
|
|
{
|
|
|
if (state->commit) {
|
|
|
+ /*
|
|
|
+ * In the event that a non-blocking commit returns
|
|
|
+ * -ERESTARTSYS before the commit_tail work is queued, we will
|
|
|
+ * have an extra reference to the commit object. Release it, if
|
|
|
+ * the event has not been consumed by the worker.
|
|
|
+ *
|
|
|
+ * state->event may be freed, so we can't directly look at
|
|
|
+ * state->event->base.completion.
|
|
|
+ */
|
|
|
+ if (state->event && state->commit->abort_completion)
|
|
|
+ drm_crtc_commit_put(state->commit);
|
|
|
+
|
|
|
kfree(state->commit->event);
|
|
|
state->commit->event = NULL;
|
|
|
+
|
|
|
drm_crtc_commit_put(state->commit);
|
|
|
}
|
|
|
|