Merge tag 'drm-misc-next-2018-11-07' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-2.6-block.git] / drivers / gpu / drm / drm_atomic_helper.c
index 6f66777dca4b0e339d1259e038d00d826e3adb29..474b503a73a1694b9b909d976389caf135fd6b12 100644 (file)
@@ -319,6 +319,26 @@ update_connector_routing(struct drm_atomic_state *state,
                return 0;
        }
 
+       crtc_state = drm_atomic_get_new_crtc_state(state,
+                                                  new_connector_state->crtc);
+       /*
+        * For compatibility with legacy users, we want to make sure that
+        * we allow DPMS On->Off modesets on unregistered connectors. Modesets
+        * which would result in anything else must be considered invalid, to
+        * avoid turning on new displays on dead connectors.
+        *
+        * Since the connector can be unregistered at any point during an
+        * atomic check or commit, this is racy. But that's OK: all we care
+        * about is ensuring that userspace can't do anything but shut off the
+        * display on a connector that was destroyed after its been notified,
+        * not before.
+        */
+       if (drm_connector_is_unregistered(connector) && crtc_state->active) {
+               DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n",
+                                connector->base.id, connector->name);
+               return -EINVAL;
+       }
+
        funcs = connector->helper_private;
 
        if (funcs->atomic_best_encoder)
@@ -363,7 +383,6 @@ update_connector_routing(struct drm_atomic_state *state,
 
        set_best_encoder(state, new_connector_state, new_encoder);
 
-       crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);
        crtc_state->connectors_changed = true;
 
        DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
@@ -1420,15 +1439,16 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
 void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
                                          struct drm_atomic_state *old_state)
 {
-       struct drm_crtc_state *new_crtc_state;
        struct drm_crtc *crtc;
        int i;
 
-       for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
-               struct drm_crtc_commit *commit = new_crtc_state->commit;
+       for (i = 0; i < dev->mode_config.num_crtc; i++) {
+               struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
                int ret;
 
-               if (!commit)
+               crtc = old_state->crtcs[i].ptr;
+
+               if (!crtc || !commit)
                        continue;
 
                ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
@@ -1946,6 +1966,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
                drm_crtc_commit_get(commit);
 
                commit->abort_completion = true;
+
+               state->crtcs[i].commit = commit;
+               drm_crtc_commit_get(commit);
        }
 
        for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {