diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 080a09014..9bb99e274 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -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 @@ -139,21 +141,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i]; - if (!connector || !connector->funcs) + 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; @@ -621,6 +618,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; @@ -889,6 +888,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); @@ -925,6 +926,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; @@ -1159,12 +1161,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) { @@ -1174,16 +1182,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; } @@ -1414,7 +1422,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 @@ -1429,7 +1437,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; @@ -1438,11 +1446,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 @@ -1640,12 +1648,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; } @@ -1658,12 +1673,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; } @@ -1671,13 +1688,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++; } @@ -1688,6 +1708,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) { @@ -1711,7 +1732,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); } |