Merge git://git.infradead.org/intel-iommu
[cascardo/linux.git] / drivers / gpu / drm / drm_atomic.c
index 8ee1db8..3ff1ed7 100644 (file)
@@ -31,6 +31,8 @@
 #include <drm/drm_mode.h>
 #include <drm/drm_plane_helper.h>
 
+#include "drm_crtc_internal.h"
+
 /**
  * drm_atomic_state_default_release -
  * release memory initialized by drm_atomic_state_init
@@ -142,18 +144,11 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
                if (!connector)
                        continue;
 
-               /*
-                * FIXME: Async commits can race with connector unplugging and
-                * there's currently nothing that prevents cleanup up state for
-                * deleted connectors. As long as the callback doesn't look at
-                * the connector we'll be fine though, so make sure that's the
-                * case by setting all connector pointers to NULL.
-                */
-               state->connector_states[i]->connector = NULL;
-               connector->funcs->atomic_destroy_state(NULL,
+               connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
                state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
+               drm_connector_unreference(connector);
        }
 
        for (i = 0; i < config->num_crtc; i++) {
@@ -261,6 +256,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
        int ret, index = drm_crtc_index(crtc);
        struct drm_crtc_state *crtc_state;
 
+       WARN_ON(!state->acquire_ctx);
+
        crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
        if (crtc_state)
                return crtc_state;
@@ -620,6 +617,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
        int ret, index = drm_plane_index(plane);
        struct drm_plane_state *plane_state;
 
+       WARN_ON(!state->acquire_ctx);
+
        plane_state = drm_atomic_get_existing_plane_state(state, plane);
        if (plane_state)
                return plane_state;
@@ -888,6 +887,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
        struct drm_mode_config *config = &connector->dev->mode_config;
        struct drm_connector_state *connector_state;
 
+       WARN_ON(!state->acquire_ctx);
+
        ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
        if (ret)
                return ERR_PTR(ret);
@@ -924,6 +925,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
        if (!connector_state)
                return ERR_PTR(-ENOMEM);
 
+       drm_connector_reference(connector);
        state->connector_states[index] = connector_state;
        state->connectors[index] = connector;
        connector_state->state = state;
@@ -1158,12 +1160,18 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 {
        struct drm_crtc_state *crtc_state;
 
-       if (conn_state->crtc && conn_state->crtc != crtc) {
+       if (conn_state->crtc == crtc)
+               return 0;
+
+       if (conn_state->crtc) {
                crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state,
                                                                conn_state->crtc);
 
                crtc_state->connector_mask &=
                        ~(1 << drm_connector_index(conn_state->connector));
+
+               drm_connector_unreference(conn_state->connector);
+               conn_state->crtc = NULL;
        }
 
        if (crtc) {
@@ -1173,16 +1181,16 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 
                crtc_state->connector_mask |=
                        1 << drm_connector_index(conn_state->connector);
-       }
 
-       conn_state->crtc = crtc;
+               drm_connector_reference(conn_state->connector);
+               conn_state->crtc = crtc;
 
-       if (crtc)
                DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d:%s]\n",
                                 conn_state, crtc->base.id, crtc->name);
-       else
+       } else {
                DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n",
                                 conn_state);
+       }
 
        return 0;
 }
@@ -1388,7 +1396,7 @@ int drm_atomic_commit(struct drm_atomic_state *state)
 EXPORT_SYMBOL(drm_atomic_commit);
 
 /**
- * drm_atomic_async_commit - atomic&async configuration commit
+ * drm_atomic_nonblocking_commit - atomic&nonblocking configuration commit
  * @state: atomic configuration to check
  *
  * Note that this function can return -EDEADLK if the driver needed to acquire
@@ -1403,7 +1411,7 @@ EXPORT_SYMBOL(drm_atomic_commit);
  * Returns:
  * 0 on success, negative error code on failure.
  */
-int drm_atomic_async_commit(struct drm_atomic_state *state)
+int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
 {
        struct drm_mode_config *config = &state->dev->mode_config;
        int ret;
@@ -1412,11 +1420,11 @@ int drm_atomic_async_commit(struct drm_atomic_state *state)
        if (ret)
                return ret;
 
-       DRM_DEBUG_ATOMIC("commiting %p asynchronously\n", state);
+       DRM_DEBUG_ATOMIC("commiting %p nonblocking\n", state);
 
        return config->funcs->atomic_commit(state->dev, state, true);
 }
-EXPORT_SYMBOL(drm_atomic_async_commit);
+EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
 
 /*
  * The big monstor ioctl
@@ -1614,12 +1622,19 @@ retry:
                }
 
                obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
-               if (!obj || !obj->properties) {
+               if (!obj) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+
+               if (!obj->properties) {
+                       drm_mode_object_unreference(obj);
                        ret = -ENOENT;
                        goto out;
                }
 
                if (get_user(count_props, count_props_ptr + copied_objs)) {
+                       drm_mode_object_unreference(obj);
                        ret = -EFAULT;
                        goto out;
                }
@@ -1632,12 +1647,14 @@ retry:
                        struct drm_property *prop;
 
                        if (get_user(prop_id, props_ptr + copied_props)) {
+                               drm_mode_object_unreference(obj);
                                ret = -EFAULT;
                                goto out;
                        }
 
                        prop = drm_property_find(dev, prop_id);
                        if (!prop) {
+                               drm_mode_object_unreference(obj);
                                ret = -ENOENT;
                                goto out;
                        }
@@ -1645,13 +1662,16 @@ retry:
                        if (copy_from_user(&prop_value,
                                           prop_values_ptr + copied_props,
                                           sizeof(prop_value))) {
+                               drm_mode_object_unreference(obj);
                                ret = -EFAULT;
                                goto out;
                        }
 
                        ret = atomic_set_prop(state, obj, prop, prop_value);
-                       if (ret)
+                       if (ret) {
+                               drm_mode_object_unreference(obj);
                                goto out;
+                       }
 
                        copied_props++;
                }
@@ -1662,6 +1682,7 @@ retry:
                        plane_mask |= (1 << drm_plane_index(plane));
                        plane->old_fb = plane->fb;
                }
+               drm_mode_object_unreference(obj);
        }
 
        if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -1685,7 +1706,7 @@ retry:
                 */
                ret = drm_atomic_check_only(state);
        } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
-               ret = drm_atomic_async_commit(state);
+               ret = drm_atomic_nonblocking_commit(state);
        } else {
                ret = drm_atomic_commit(state);
        }