drm: Consolidate connector arrays in drm_atomic_state
[cascardo/linux.git] / drivers / gpu / drm / drm_atomic.c
index 8ee1db8..a6395e9 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
@@ -42,7 +44,6 @@
 void drm_atomic_state_default_release(struct drm_atomic_state *state)
 {
        kfree(state->connectors);
-       kfree(state->connector_states);
        kfree(state->crtcs);
        kfree(state->crtc_states);
        kfree(state->planes);
@@ -137,23 +138,16 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
        DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
 
        for (i = 0; i < state->num_connector; i++) {
-               struct drm_connector *connector = state->connectors[i];
+               struct drm_connector *connector = state->connectors[i].ptr;
 
                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,
-                                                      state->connector_states[i]);
-               state->connectors[i] = NULL;
-               state->connector_states[i] = NULL;
+               connector->funcs->atomic_destroy_state(connector,
+                                                      state->connectors[i].state);
+               state->connectors[i].ptr = NULL;
+               state->connectors[i].state = NULL;
+               drm_connector_unreference(connector);
        }
 
        for (i = 0; i < config->num_crtc; i++) {
@@ -261,6 +255,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 +616,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 +886,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);
@@ -895,8 +895,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
        index = drm_connector_index(connector);
 
        if (index >= state->num_connector) {
-               struct drm_connector **c;
-               struct drm_connector_state **cs;
+               struct __drm_connnectors_state *c;
                int alloc = max(index + 1, config->num_connector);
 
                c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
@@ -907,25 +906,19 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
                memset(&state->connectors[state->num_connector], 0,
                       sizeof(*state->connectors) * (alloc - state->num_connector));
 
-               cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL);
-               if (!cs)
-                       return ERR_PTR(-ENOMEM);
-
-               state->connector_states = cs;
-               memset(&state->connector_states[state->num_connector], 0,
-                      sizeof(*state->connector_states) * (alloc - state->num_connector));
                state->num_connector = alloc;
        }
 
-       if (state->connector_states[index])
-               return state->connector_states[index];
+       if (state->connectors[index].state)
+               return state->connectors[index].state;
 
        connector_state = connector->funcs->atomic_duplicate_state(connector);
        if (!connector_state)
                return ERR_PTR(-ENOMEM);
 
-       state->connector_states[index] = connector_state;
-       state->connectors[index] = connector;
+       drm_connector_reference(connector);
+       state->connectors[index].state = connector_state;
+       state->connectors[index].ptr = connector;
        connector_state->state = state;
 
        DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d] %p state to %p\n",
@@ -1158,12 +1151,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 +1172,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 +1387,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 +1402,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 +1411,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 +1613,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 +1638,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 +1653,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 +1673,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 +1697,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);
        }