The 'atomic' mechanism allows for multiple properties to be updated, checked, and commited atomically. This will be the basis of atomic- modeset and nuclear-pageflip. The basic flow is: state = dev->atomic_begin(); for (... one or more ...) obj->set_property(obj, state, prop, value); if (dev->atomic_check(state)) dev->atomic_commit(state); dev->atomic_end(state); The split of check and commit steps is to allow for ioctls with a test-only flag (which would skip the commit step). Signed-off-by: Rob Clark <robdclark@xxxxxxxxx> --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/armada/armada_crtc.c | 3 +- drivers/gpu/drm/armada/armada_output.c | 3 +- drivers/gpu/drm/armada/armada_overlay.c | 3 +- drivers/gpu/drm/ast/ast_drv.c | 6 + drivers/gpu/drm/ast/ast_drv.h | 1 + drivers/gpu/drm/cirrus/cirrus_drv.c | 6 + drivers/gpu/drm/cirrus/cirrus_drv.h | 1 + drivers/gpu/drm/drm_atomic.c | 274 ++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 149 +++++++++------ drivers/gpu/drm/drm_modeset_lock.c | 28 +++ drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 7 + drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 +- drivers/gpu/drm/gma500/cdv_intel_crt.c | 4 +- drivers/gpu/drm/gma500/cdv_intel_dp.c | 4 +- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 4 +- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 4 +- drivers/gpu/drm/gma500/mdfld_dsi_output.c | 4 +- drivers/gpu/drm/gma500/psb_drv.c | 7 + drivers/gpu/drm/gma500/psb_drv.h | 1 + drivers/gpu/drm/gma500/psb_intel_drv.h | 4 +- drivers/gpu/drm/gma500/psb_intel_lvds.c | 4 +- drivers/gpu/drm/gma500/psb_intel_sdvo.c | 4 +- drivers/gpu/drm/i915/i915_drv.c | 8 + drivers/gpu/drm/i915/intel_crt.c | 4 +- drivers/gpu/drm/i915/intel_dp.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 4 +- drivers/gpu/drm/i915/intel_lvds.c | 4 +- drivers/gpu/drm/i915/intel_sdvo.c | 4 +- drivers/gpu/drm/i915/intel_tv.c | 6 +- drivers/gpu/drm/mgag200/mgag200_drv.c | 7 + drivers/gpu/drm/mgag200/mgag200_drv.h | 1 + drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 3 +- drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | 3 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 3 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 3 +- drivers/gpu/drm/msm/msm_drv.c | 6 + drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/nouveau/dispnv04/overlay.c | 5 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 7 + drivers/gpu/drm/nouveau/nouveau_drm.h | 1 + drivers/gpu/drm/omapdrm/omap_crtc.c | 6 +- drivers/gpu/drm/omapdrm/omap_drv.c | 6 + drivers/gpu/drm/omapdrm/omap_drv.h | 4 +- drivers/gpu/drm/omapdrm/omap_plane.c | 3 +- drivers/gpu/drm/qxl/qxl_display.c | 4 +- drivers/gpu/drm/qxl/qxl_drv.c | 9 + drivers/gpu/drm/radeon/radeon_connectors.c | 9 +- drivers/gpu/drm/radeon/radeon_drv.c | 9 + drivers/gpu/drm/rcar-du/rcar_du_drv.c | 7 + drivers/gpu/drm/rcar-du/rcar_du_plane.c | 4 +- drivers/gpu/drm/shmobile/shmob_drm_drv.c | 7 + drivers/gpu/drm/tilcdc/tilcdc_drv.c | 6 + drivers/gpu/drm/tilcdc/tilcdc_drv.h | 1 + drivers/gpu/drm/tilcdc/tilcdc_slave.c | 3 +- drivers/gpu/drm/udl/udl_connector.c | 6 +- drivers/gpu/drm/udl/udl_drv.c | 8 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 +- include/drm/drmP.h | 80 ++++++++ include/drm/drm_atomic.h | 114 ++++++++++++ include/drm/drm_crtc.h | 15 +- include/drm/drm_modeset_lock.h | 41 +++++ include/uapi/drm/drm_mode.h | 3 + 69 files changed, 867 insertions(+), 103 deletions(-) create mode 100644 drivers/gpu/drm/drm_atomic.c create mode 100644 include/drm/drm_atomic.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index bf4c12d..c1d5f73 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ - drm_plane_helper.o drm_modeset_lock.o + drm_plane_helper.o drm_modeset_lock.o drm_atomic.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 81c34f9..7d3c649 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -961,7 +961,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, static int armada_drm_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { struct armada_private *priv = crtc->dev->dev_private; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); diff --git a/drivers/gpu/drm/armada/armada_output.c b/drivers/gpu/drm/armada/armada_output.c index d685a54..9915306 100644 --- a/drivers/gpu/drm/armada/armada_output.c +++ b/drivers/gpu/drm/armada/armada_output.c @@ -54,7 +54,8 @@ static void armada_drm_connector_destroy(struct drm_connector *conn) } static int armada_drm_connector_set_property(struct drm_connector *conn, - struct drm_property *property, uint64_t value) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { struct armada_connector *dconn = drm_to_armada_conn(conn); diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index c5b06fd..601ba9a 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -283,7 +283,8 @@ static void armada_plane_destroy(struct drm_plane *plane) } static int armada_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { struct armada_private *priv = plane->dev->dev_private; struct armada_plane *dplane = drm_to_armada_plane(plane); diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 2ba39ac..cd81d68 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -215,6 +215,12 @@ static struct drm_driver driver = { .dumb_map_offset = ast_dumb_mmap_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, }; static int __init ast_init(void) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 5d6a875..0d21ff8 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -29,6 +29,7 @@ #define __AST_DRV_H__ #include <drm/drm_fb_helper.h> +#include <drm/drm_atomic.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index 08ce520..023db21 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -137,6 +137,12 @@ static struct drm_driver driver = { .dumb_create = cirrus_dumb_create, .dumb_map_offset = cirrus_dumb_mmap_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, }; static const struct dev_pm_ops cirrus_pm_ops = { diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 117d3ec..f929bc8 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -14,6 +14,7 @@ #include <video/vga.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_atomic.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c new file mode 100644 index 0000000..560fe23 --- /dev/null +++ b/drivers/gpu/drm/drm_atomic.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2014 Red Hat + * Author: Rob Clark <robdclark@xxxxxxxxx> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include <drm/drmP.h> +#include <drm/drm_atomic.h> + +/** + * drm_atomic_begin - start a sequence of atomic updates + * @dev: DRM device + * @flags: the modifier flags that userspace has requested + * + * Begin a sequence of atomic property sets. Returns a driver + * private state object that is passed back into the various + * object's set_property() fxns, and into the remainder of the + * atomic funcs. The state object should accumulate the changes + * from one o more set_property()'s. At the end, the state can + * be checked, and optionally committed. + * + * RETURNS + * a driver state object, which is passed back in to the + * various other atomic fxns, or error (such as -EBUSY if + * there is still a pending async update) + */ +struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev, + uint32_t flags) +{ + struct drm_atomic_state *state; + uint32_t acquire_flags = 0; + int sz; + void *ptr; + + sz = sizeof(*state); + + ptr = kzalloc(sz, GFP_KERNEL); + + state = ptr; + ptr = &state[1]; + + kref_init(&state->refcount); + + if (flags & DRM_MODE_ATOMIC_NOLOCK) + acquire_flags |= DRM_MODESET_ACQUIRE_NOLOCK; + if (flags & DRM_MODE_ATOMIC_NONBLOCK) + acquire_flags |= DRM_MODESET_ACQUIRE_NONBLOCK; + + drm_modeset_acquire_init(&state->acquire_ctx, acquire_flags); + + state->dev = dev; + state->flags = flags; + + return state; +} +EXPORT_SYMBOL(drm_atomic_begin); + +/** + * drm_atomic_set_event - set a pending event on mode object + * @dev: DRM device + * @state: the driver state object + * @obj: the object to set the event on + * @event: the event to send back + * + * Set pending event for an update on the specified object. The + * event is to be sent back to userspace after the update completes. + */ +int drm_atomic_set_event(struct drm_device *dev, + struct drm_atomic_state *state, struct drm_mode_object *obj, + struct drm_pending_vblank_event *event) +{ + return -EINVAL; /* for now */ +} +EXPORT_SYMBOL(drm_atomic_set_event); + +/** + * drm_atomic_check - validate state object + * @dev: DRM device + * @state: the driver state object + * + * Check the state object to see if the requested state is + * physically possible. + * + * RETURNS + * Zero for success or -errno + */ +int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) +{ + struct drm_atomic_state *a = state; + a->acquire_ctx.frozen = true; + return 0; /* for now */ +} +EXPORT_SYMBOL(drm_atomic_check); + +/* Note that we drop and re-acquire the locks w/ ww_mutex directly, + * since we keep the crtc in our list with in_atomic == true. + */ + +static void drop_locks(struct drm_atomic_state *a, + struct ww_acquire_ctx *ww_ctx) +{ + struct drm_modeset_acquire_ctx *ctx = &a->acquire_ctx; + struct drm_modeset_lock *lock; + + mutex_lock(&ctx->mutex); + list_for_each_entry(lock, &ctx->locked, head) + ww_mutex_unlock(&lock->mutex); + mutex_unlock(&ctx->mutex); + + ww_acquire_fini(ww_ctx); +} + +static void grab_locks(struct drm_atomic_state *a, + struct ww_acquire_ctx *ww_ctx) +{ + struct drm_modeset_acquire_ctx *ctx = &a->acquire_ctx; + struct drm_modeset_lock *lock, *slow_locked, *contended; + int ret; + + lock = slow_locked = contended = NULL; + + + ww_acquire_init(ww_ctx, &crtc_ww_class); + + /* + * We need to do proper rain^Hww dance.. another context + * could sneak in a grab the lock in order to check + * crtc->in_atomic, and we get -EDEADLK. But the winner + * will realize the mistake when it sees crtc->in_atomic + * already set, and then drop lock and return -EBUSY. + * So we just need to keep dancing until we win. + */ +retry: + ret = 0; + list_for_each_entry(lock, &ctx->locked, head) { + if (lock == slow_locked) { + slow_locked = NULL; + continue; + } + contended = lock; + ret = ww_mutex_lock(&lock->mutex, ww_ctx); + if (ret) + goto fail; + } + +fail: + if (ret == -EDEADLK) { + /* we lost out in a seqno race, backoff, lock and retry.. */ + + list_for_each_entry(lock, &ctx->locked, head) { + if (lock == contended) + break; + ww_mutex_unlock(&lock->mutex); + } + + if (slow_locked) + ww_mutex_unlock(&slow_locked->mutex); + + ww_mutex_lock_slow(&contended->mutex, ww_ctx); + slow_locked = contended; + goto retry; + } + WARN_ON(ret); /* if we get EALREADY then something is fubar */ +} + +static void commit_locks(struct drm_atomic_state *a, + struct ww_acquire_ctx *ww_ctx) +{ + /* and properly release them (clear in_atomic, remove from list): */ + drm_modeset_drop_locks(&a->acquire_ctx); + ww_acquire_fini(ww_ctx); + a->committed = true; +} + +static int atomic_commit(struct drm_atomic_state *a, + struct ww_acquire_ctx *ww_ctx) +{ + int ret = 0; + + commit_locks(a, ww_ctx); + + return ret; +} + +/** + * drm_atomic_commit - commit state + * @dev: DRM device + * @state: the driver state object + * + * Commit the state. This will only be called if atomic_check() + * succeeds. + * + * RETURNS + * Zero for success or -errno + */ +int drm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *a) +{ + return atomic_commit(a, &a->acquire_ctx.ww_ctx); +} +EXPORT_SYMBOL(drm_atomic_commit); + +/** + * drm_atomic_commit_unlocked - like drm_atomic_commit + * but can be called back by driver in other thread. Manages the lock + * transfer from initiating thread. + */ +int drm_atomic_commit_unlocked(struct drm_device *dev, + struct drm_atomic_state *a) +{ + struct ww_acquire_ctx ww_ctx; + grab_locks(a, &ww_ctx); + return atomic_commit(a, &ww_ctx); +} +EXPORT_SYMBOL(drm_atomic_commit_unlocked); + +/** + * drm_atomic_end - conclude the atomic update + * @dev: DRM device + * @state: the driver state object + * + * Release resources associated with the state object. + */ +void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *a) +{ + /* if commit is happening from another thread, it will + * block grabbing locks until we drop (and not set + * a->committed until after), so this is not a race: + */ + if (!a->committed) + drop_locks(a, &a->acquire_ctx.ww_ctx); + + drm_atomic_state_unreference(a); +} +EXPORT_SYMBOL(drm_atomic_end); + +void _drm_atomic_state_free(struct kref *kref) +{ + struct drm_atomic_state *a = + container_of(kref, struct drm_atomic_state, refcount); + + /* in case we haven't already: */ + if (!a->committed) { + grab_locks(a, &a->acquire_ctx.ww_ctx); + commit_locks(a, &a->acquire_ctx.ww_ctx); + } + + __drm_modeset_acquire_fini(&a->acquire_ctx); + + kfree(a); +} +EXPORT_SYMBOL(_drm_atomic_state_free); + + +const struct drm_atomic_funcs drm_atomic_funcs = { +}; +EXPORT_SYMBOL(drm_atomic_funcs); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 186bed4..a1bb8aa 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -38,6 +38,7 @@ #include <drm/drm_edid.h> #include <drm/drm_fourcc.h> #include <drm/drm_modeset_lock.h> +#include <drm/drm_atomic.h> #include "drm_crtc_internal.h" @@ -3833,20 +3834,21 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); } -static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) +static int drm_mode_connector_set_obj_prop(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { int ret = -EINVAL; - struct drm_connector *connector = obj_to_connector(obj); /* Do DPMS ourselves */ if (property == connector->dev->mode_config.dpms_property) { if (connector->funcs->dpms) (*connector->funcs->dpms)(connector, (int)value); ret = 0; - } else if (connector->funcs->set_property) - ret = connector->funcs->set_property(connector, property, value); + } else if (connector->funcs->set_property) { + ret = connector->funcs->set_property(connector, state, + property, value, blob_data); + } /* store the property value if successful */ if (!ret) @@ -3854,38 +3856,90 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, return ret; } -static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) +static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc, + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { int ret = -EINVAL; - struct drm_crtc *crtc = obj_to_crtc(obj); if (crtc->funcs->set_property) - ret = crtc->funcs->set_property(crtc, property, value); + ret = crtc->funcs->set_property(crtc, state, property, + value, blob_data); if (!ret) - drm_object_property_set_value(obj, property, value); + drm_object_property_set_value(&crtc->base, property, value); return ret; } -static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) +static int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { int ret = -EINVAL; - struct drm_plane *plane = obj_to_plane(obj); if (plane->funcs->set_property) - ret = plane->funcs->set_property(plane, property, value); + ret = plane->funcs->set_property(plane, state, property, + value, blob_data); if (!ret) - drm_object_property_set_value(obj, property, value); + drm_object_property_set_value(&plane->base, property, value); return ret; } +static int drm_mode_set_obj_prop(struct drm_device *dev, + struct drm_mode_object *obj, struct drm_atomic_state *state, + struct drm_property *property, uint64_t value, void *blob_data) +{ + if (drm_property_change_is_valid(property, value)) { + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: + return drm_mode_connector_set_obj_prop(obj_to_connector(obj), + state, property, value, blob_data); + case DRM_MODE_OBJECT_CRTC: + return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj), + state, property, value, blob_data); + case DRM_MODE_OBJECT_PLANE: + return drm_mode_plane_set_obj_prop(obj_to_plane(obj), + state, property, value, blob_data); + } + } + + return -EINVAL; +} + +/* call with mode_config mutex held */ +static int drm_mode_set_obj_prop_id(struct drm_device *dev, + struct drm_atomic_state *state, + uint32_t obj_id, uint32_t obj_type, + uint32_t prop_id, uint64_t value, void *blob_data) +{ + struct drm_mode_object *arg_obj; + struct drm_property *property; + int i; + + arg_obj = drm_mode_object_find(dev, obj_id, obj_type); + if (!arg_obj) + return -ENOENT; + if (!arg_obj->properties) + return -EINVAL; + + for (i = 0; i < arg_obj->properties->count; i++) + if (arg_obj->properties->ids[i] == prop_id) + break; + + if (i == arg_obj->properties->count) + return -EINVAL; + + property = drm_property_find(dev, prop_id); + if (!property) + return -ENOENT; + + return drm_mode_set_obj_prop(dev, arg_obj, state, property, + value, blob_data); +} + /** - * drm_mode_getproperty_ioctl - get the current value of a object's property + * drm_mode_obj_get_properties_ioctl - get the current value of a object's property * @dev: DRM device * @data: ioctl data * @file_priv: DRM file info @@ -3975,58 +4029,41 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_obj_set_property *arg = data; - struct drm_mode_object *arg_obj; - struct drm_mode_object *prop_obj; - struct drm_property *property; + struct drm_mode_config *config = &dev->mode_config; + struct drm_atomic_state *state; int ret = -EINVAL; - int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); +retry: + state = dev->driver->atomic_begin(dev, 0); + if (IS_ERR(state)) + return PTR_ERR(state); - arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!arg_obj) { - ret = -ENOENT; - goto out; - } - if (!arg_obj->properties) + ret = drm_modeset_lock(&config->connection_mutex, &state->acquire_ctx); + if (ret) goto out; - - for (i = 0; i < arg_obj->properties->count; i++) - if (arg_obj->properties->ids[i] == arg->prop_id) - break; - - if (i == arg_obj->properties->count) + ret = drm_modeset_lock_all_crtcs(dev, &state->acquire_ctx); + if (ret) goto out; - prop_obj = drm_mode_object_find(dev, arg->prop_id, - DRM_MODE_OBJECT_PROPERTY); - if (!prop_obj) { - ret = -ENOENT; + ret = drm_mode_set_obj_prop_id(dev, state, + arg->obj_id, arg->obj_type, + arg->prop_id, arg->value, NULL); + if (ret) goto out; - } - property = obj_to_property(prop_obj); - if (!drm_property_change_is_valid(property, arg->value)) + ret = dev->driver->atomic_check(dev, state); + if (ret) goto out; - switch (arg_obj->type) { - case DRM_MODE_OBJECT_CONNECTOR: - ret = drm_mode_connector_set_obj_prop(arg_obj, property, - arg->value); - break; - case DRM_MODE_OBJECT_CRTC: - ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); - break; - case DRM_MODE_OBJECT_PLANE: - ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value); - break; - } + ret = dev->driver->atomic_commit(dev, state); out: - drm_modeset_unlock_all(dev); + dev->driver->atomic_end(dev, state); + if (ret == -EDEADLK) + goto retry; return ret; } diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index edd8508..38a846b 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -31,18 +31,29 @@ void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, { ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); INIT_LIST_HEAD(&ctx->locked); + mutex_init(&ctx->mutex); + ctx->nolock = !!(flags & DRM_MODESET_ACQUIRE_NOLOCK); + ctx->nonblock = !!(flags & DRM_MODESET_ACQUIRE_NONBLOCK); } EXPORT_SYMBOL(drm_modeset_acquire_init); +/* special version for atomic.. which needs to ww_acquire_fini() itself */ +void __drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) +{ + mutex_destroy(&ctx->mutex); +} + void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) { ww_acquire_fini(&ctx->ww_ctx); + __drm_modeset_acquire_fini(ctx); } EXPORT_SYMBOL(drm_modeset_acquire_fini); void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) { WARN_ON(ctx->contended); + mutex_lock(&ctx->mutex); while (!list_empty(&ctx->locked)) { struct drm_modeset_lock *lock; @@ -51,6 +62,7 @@ void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) drm_modeset_unlock(lock); } + mutex_unlock(&ctx->mutex); } EXPORT_SYMBOL(drm_modeset_drop_locks); @@ -60,8 +72,13 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, { int ret; + if (ctx->nolock) + return 0; + + WARN_ON(ctx->frozen); /* all locks should be held by now! */ WARN_ON(ctx->contended); +retry: if (interruptible && slow) { ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); } else if (interruptible) { @@ -73,6 +90,15 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx); } if (!ret) { + if (lock->atomic_pending) { + /* some other pending update with dropped locks */ + ww_mutex_unlock(&lock->mutex); + if (ctx->nonblock) + return -EBUSY; + wait_event(lock->event, !lock->atomic_pending); + goto retry; + } + lock->atomic_pending = true; WARN_ON(!list_empty(&lock->head)); list_add(&lock->head, &ctx->locked); } else if (ret == -EALREADY) { @@ -154,7 +180,9 @@ EXPORT_SYMBOL(drm_modeset_lock_interruptible); void drm_modeset_unlock(struct drm_modeset_lock *lock) { list_del_init(&lock->head); + lock->atomic_pending = false; ww_mutex_unlock(&lock->mutex); + wake_up_all(&lock->event); } EXPORT_SYMBOL(drm_modeset_unlock); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1ef5ab9..2a56973 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -281,8 +281,10 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) } static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct drm_device *dev = crtc->dev; struct exynos_drm_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2d27ba2..318969d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -14,6 +14,7 @@ #include <linux/pm_runtime.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <linux/anon_inodes.h> @@ -341,6 +342,12 @@ static struct drm_driver exynos_drm_driver = { .dumb_create = exynos_drm_gem_dumb_create, .dumb_map_offset = exynos_drm_gem_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = exynos_dmabuf_prime_export, diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 8371cbd..9da0935 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -212,8 +212,10 @@ static void exynos_plane_destroy(struct drm_plane *plane) } static int exynos_plane_set_property(struct drm_plane *plane, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct drm_device *dev = plane->dev; struct exynos_plane *exynos_plane = to_exynos_plane(plane); diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index c18268c..6d637d3 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -205,8 +205,10 @@ static int cdv_intel_crt_get_modes(struct drm_connector *connector) } static int cdv_intel_crt_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { return 0; } diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 9ff30c2..31d872d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -1645,8 +1645,10 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector) static int cdv_intel_dp_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct drm_psb_private *dev_priv = connector->dev->dev_private; struct gma_encoder *encoder = gma_attached_encoder(connector); diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index b99084b..f0e4d78 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -150,8 +150,10 @@ static enum drm_connector_status cdv_hdmi_detect( } static int cdv_hdmi_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct drm_encoder *encoder = connector->encoder; diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 8ecc920..7ffaed4 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -452,8 +452,10 @@ static void cdv_intel_lvds_destroy(struct drm_connector *connector) } static int cdv_intel_lvds_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct drm_encoder *encoder = connector->encoder; diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c index 6e91b20..2318a46 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c @@ -243,8 +243,10 @@ mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) } static int mdfld_dsi_connector_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct drm_encoder *encoder = connector->encoder; diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 59ea45e..f342ae7 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -487,6 +487,13 @@ static struct drm_driver driver = { .disable_vblank = psb_disable_vblank, .get_vblank_counter = psb_get_vblank_counter, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .gem_free_object = psb_gem_free_object, .gem_vm_ops = &psb_gem_vm_ops, diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 55ebe2b..413ea37 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -25,6 +25,7 @@ #include <drm/drmP.h> #include <drm/drm_global.h> #include <drm/gma_drm.h> +#include <drm/drm_atomic.h> #include "psb_reg.h" #include "psb_intel_drv.h" #include "gma_display.h" diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 336bd3a..96e9759 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -254,8 +254,10 @@ extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value); + uint64_t value, + void *blob_data); extern void psb_intel_lvds_destroy(struct drm_connector *connector); extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs; diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index d7778d0..6b64d9d 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -569,8 +569,10 @@ void psb_intel_lvds_destroy(struct drm_connector *connector) } int psb_intel_lvds_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct drm_encoder *encoder = connector->encoder; diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index deeb082..724b525 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1705,8 +1705,10 @@ static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) static int psb_intel_sdvo_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 284e748..a3d1291d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1119,6 +1119,14 @@ static struct drm_driver driver = { .dumb_create = i915_gem_dumb_create, .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = drm_gem_dumb_destroy, + + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .ioctls = i915_ioctls, .fops = &i915_driver_fops, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 33328fc..0e52fc8 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -725,8 +725,10 @@ out: } static int intel_crt_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { return 0; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9926dc1..caa573c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3271,8 +3271,10 @@ intel_dp_detect_audio(struct drm_connector *connector) static int intel_dp_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 824f8ae..8c838e4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -31,6 +31,7 @@ #include "i915_drv.h" #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_fb_helper.h> #include <drm/drm_dp_helper.h> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index b606162..8e160b0 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1044,8 +1044,10 @@ intel_hdmi_detect_audio(struct drm_connector *connector) static int intel_hdmi_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct intel_digital_port *intel_dig_port = diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 1b1541d..4028237 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -486,8 +486,10 @@ static void intel_lvds_destroy(struct drm_connector *connector) } static int intel_lvds_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2bf09e8..4e36ee99 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2052,8 +2052,10 @@ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) static int intel_sdvo_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 97d9fc9..26dc38d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1445,8 +1445,10 @@ intel_tv_destroy(struct drm_connector *connector) static int -intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, - uint64_t val) +intel_tv_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, + struct drm_property *property, + uint64_t val, void *blob_data) { struct drm_device *dev = connector->dev; struct intel_tv *intel_tv = intel_attached_tv(connector); diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index f15ea3c..0425bdd 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -103,6 +103,13 @@ static struct drm_driver driver = { .dumb_create = mgag200_dumb_create, .dumb_map_offset = mgag200_dumb_mmap_offset, .dumb_destroy = drm_gem_dumb_destroy, + + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, }; static struct pci_driver mgag200_pci_driver = { diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index cf11ee6..c4d1600 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -16,6 +16,7 @@ #include <video/vga.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_atomic.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index ef9957d..efa19c8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -468,7 +468,8 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, } static int mdp4_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { // XXX return -EINVAL; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 66f33db..8c064dc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -85,7 +85,8 @@ void mdp4_plane_install_properties(struct drm_plane *plane, } int mdp4_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { // XXX return -EINVAL; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 6ea10bd..ff48944 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -386,7 +386,8 @@ static int mdp5_crtc_page_flip(struct drm_crtc *crtc, } static int mdp5_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { // XXX return -EINVAL; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 47f7bbb..5cbf226 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -100,7 +100,8 @@ void mdp5_plane_install_properties(struct drm_plane *plane, } int mdp5_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { // XXX return -EINVAL; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index afedd8b..36b9273 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -812,6 +812,12 @@ static struct drm_driver msm_driver = { .gem_prime_import_sg_table = msm_gem_prime_import_sg_table, .gem_prime_vmap = msm_gem_prime_vmap, .gem_prime_vunmap = msm_gem_prime_vunmap, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, #ifdef CONFIG_DEBUG_FS .debugfs_init = msm_debugfs_init, .debugfs_cleanup = msm_debugfs_cleanup, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9d10ee0..afc990e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -50,6 +50,7 @@ static inline struct device *msm_iommu_get_ctx(const char *ctx_name) #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_atomic.h> #include <drm/msm_drm.h> struct msm_kms; diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index ab03f77..577e6aa 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -221,8 +221,9 @@ nv10_set_params(struct nouveau_plane *plane) static int nv_set_property(struct drm_plane *plane, - struct drm_property *property, - uint64_t value) + struct drm_atomic_state *state, + struct drm_property *property, + uint64_t value, void *blob_data) { struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index d07ce02..3351e72 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -447,7 +447,8 @@ nouveau_connector_force(struct drm_connector *connector) static int nouveau_connector_set_property(struct drm_connector *connector, - struct drm_property *property, uint64_t value) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { struct nouveau_display *disp = nouveau_display(connector->dev); struct nouveau_connector *nv_connector = nouveau_connector(connector); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ddd8375..9a96d6d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -858,6 +858,13 @@ driver = { .dumb_map_offset = nouveau_display_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .name = DRIVER_NAME, .desc = DRIVER_DESC, #ifdef GIT_REVISION diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 7efbafa..8941696 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -29,6 +29,7 @@ #include <subdev/vm.h> #include <drmP.h> +#include <drm/drm_atomic.h> #include <drm/nouveau_drm.h> #include <drm/ttm/ttm_bo_api.h> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 2d28dc3..a75934d 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -382,7 +382,8 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, } static int omap_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct omap_drm_private *priv = crtc->dev->dev_private; @@ -392,7 +393,8 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); } - return omap_plane_set_property(omap_crtc->plane, property, val); + return omap_plane_set_property(omap_crtc->plane, state, + property, val, blob_data); } static const struct drm_crtc_funcs omap_crtc_funcs = { diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 002b972..fe3983b 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -649,6 +649,12 @@ static struct drm_driver omap_drm_driver = { .dumb_create = omap_gem_dumb_create, .dumb_map_offset = omap_gem_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, .ioctls = ioctls, .num_ioctls = DRM_OMAP_NUM_IOCTLS, .fops = &omapdriver_fops, diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 284b80f..346fc8a 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -25,6 +25,7 @@ #include <linux/types.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <drm/omap_drm.h> #include <linux/platform_data/omap_drm.h> @@ -178,7 +179,8 @@ int omap_plane_mode_set(struct drm_plane *plane, void omap_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); int omap_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val); + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data); struct drm_encoder *omap_encoder_init(struct drm_device *dev, struct omap_dss_device *dssdev); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 3cf31ee..8ae5c49 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -336,7 +336,8 @@ void omap_plane_install_properties(struct drm_plane *plane, } int omap_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_drm_private *priv = plane->dev->dev_private; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 3ab9072..b54c970 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -819,8 +819,10 @@ static enum drm_connector_status qxl_conn_detect( } static int qxl_conn_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { DRM_DEBUG("\n"); return 0; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 6e93663..1984c2c 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -34,6 +34,7 @@ #include "drmP.h" #include "drm/drm.h" #include "drm_crtc_helper.h" +#include "drm_atomic.h" #include "qxl_drv.h" #include "qxl_object.h" @@ -220,6 +221,14 @@ static struct drm_driver qxl_driver = { .dumb_create = qxl_mode_dumb_create, .dumb_map_offset = qxl_mode_dumb_mmap, .dumb_destroy = drm_gem_dumb_destroy, + + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + #if defined(CONFIG_DEBUG_FS) .debugfs_init = qxl_debugfs_init, .debugfs_cleanup = qxl_debugfs_takedown, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index bcfe5d5..b0f75a7 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -360,8 +360,9 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn } } -static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, - uint64_t val) +static int radeon_connector_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; @@ -683,8 +684,10 @@ static void radeon_connector_destroy(struct drm_connector *connector) } static int radeon_lvds_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct drm_device *dev = connector->dev; struct radeon_encoder *radeon_encoder; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 15447a41..745791d 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -34,6 +34,7 @@ #include "radeon_drv.h" #include <drm/drm_pciids.h> +#include <drm/drm_atomic.h> #include <linux/console.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -545,6 +546,14 @@ static struct drm_driver kms_driver = { .dumb_create = radeon_mode_dumb_create, .dumb_map_offset = radeon_mode_dumb_mmap, .dumb_destroy = drm_gem_dumb_destroy, + + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .fops = &radeon_driver_kms_fops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 792fd1d..3f642a8 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -21,6 +21,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> @@ -175,6 +176,12 @@ static struct drm_driver rcar_du_driver = { .dumb_create = rcar_du_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, .fops = &rcar_du_fops, .name = "rcar-du", .desc = "Renesas R-Car Display Unit", diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 3fb69d9..3a5d843 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -397,8 +397,10 @@ done: } static int rcar_du_plane_set_property(struct drm_plane *plane, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t value) + uint64_t value, + void *blob_data) { struct rcar_du_plane *rplane = to_rcar_plane(plane); struct rcar_du_group *rgrp = rplane->group; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 82c84c7..7474ffb 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -21,6 +21,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_gem_cma_helper.h> #include "shmob_drm_crtc.h" @@ -285,6 +286,12 @@ static struct drm_driver shmob_drm_driver = { .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, .fops = &shmob_drm_fops, .name = "shmob-drm", .desc = "Renesas SH Mobile DRM", diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index b20b694..3579b07 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -519,6 +519,12 @@ static struct drm_driver tilcdc_driver = { .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, .debugfs_cleanup = tilcdc_debugfs_cleanup, diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 0938036..1280a65 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -31,6 +31,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c index 595068b..693f3ec 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c @@ -206,7 +206,8 @@ static struct drm_encoder *slave_connector_best_encoder( } static int slave_connector_set_property(struct drm_connector *connector, - struct drm_property *property, uint64_t value) + struct drm_atomic_state *state, struct drm_property *property, + uint64_t value, void *blob_data) { struct drm_encoder *encoder = to_slave_connector(connector)->encoder; return get_slave_funcs(encoder)->set_property(encoder, diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index b44d548..936244d 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -115,9 +115,9 @@ udl_best_single_encoder(struct drm_connector *connector) return encoder; } -static int udl_connector_set_property(struct drm_connector *connector, - struct drm_property *property, - uint64_t val) +static int udl_connector_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, + uint64_t val, void *blob_data) { return 0; } diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 3ddd6cd..52ade41 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <drm/drm_usb.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> #include "udl_drv.h" static struct drm_driver driver; @@ -88,6 +89,13 @@ static struct drm_driver driver = { .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = udl_gem_prime_import, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6bdd15e..3ec6792 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1433,6 +1433,13 @@ static struct drm_driver driver = { .prime_fd_to_handle = vmw_prime_fd_to_handle, .prime_handle_to_fd = vmw_prime_handle_to_fd, + .atomic_begin = drm_atomic_begin, + .atomic_set_event = drm_atomic_set_event, + .atomic_check = drm_atomic_check, + .atomic_commit = drm_atomic_commit, + .atomic_end = drm_atomic_end, + .atomic_funcs = &drm_atomic_funcs, + .fops = &vmwgfx_driver_fops, .name = VMWGFX_DRIVER_NAME, .desc = VMWGFX_DRIVER_DESC, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 6b252a8..b0d6f3a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -30,6 +30,7 @@ #include "vmwgfx_reg.h" #include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/vmwgfx_drm.h> #include <drm/drm_hashtab.h> #include <linux/suspend.h> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8f3edc4..c881ba1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2007,8 +2007,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, } int vmw_du_connector_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + void *blob_data) { return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8d038c3..6b02fdb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -141,8 +141,10 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force); int vmw_du_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); int vmw_du_connector_set_property(struct drm_connector *connector, + struct drm_atomic_state *state, struct drm_property *property, - uint64_t val); + uint64_t val, + void *blob_data); /* diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a9b8a5d..5ac3587 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -948,6 +948,86 @@ struct drm_driver { struct drm_device *dev, uint32_t handle); + /* + * Atomic functions: + */ + + /** + * atomic_begin - start a sequence of atomic updates + * @dev: DRM device + * @flags: the modifier flags that userspace has requested + * + * Begin a sequence of atomic property sets. Returns a driver + * private state object that is passed back into the various + * object's set_property() fxns, and into the remainder of the + * atomic funcs. The state object should accumulate the changes + * from one o more set_property()'s. At the end, the state can + * be checked, and optionally committed. + * + * RETURNS + * a driver state object, which is passed back in to the + * various other atomic fxns, or error (such as -EBUSY if + * there is still a pending async update) + */ + struct drm_atomic_state *(*atomic_begin)(struct drm_device *dev, uint32_t flags); + + /** + * atomic_set_event - set a pending event on mode object + * @dev: DRM device + * @state: the driver state object + * @obj: the object to set the event on + * @event: the event to send back + * + * Set pending event for an update on the specified object. The + * event is to be sent back to userspace after the update completes. + */ + int (*atomic_set_event)(struct drm_device *dev, + struct drm_atomic_state *state, struct drm_mode_object *obj, + struct drm_pending_vblank_event *event); + + /** + * atomic_check - validate state object + * @dev: DRM device + * @state: the driver state object + * + * Check the state object to see if the requested state is + * physically possible. + * + * RETURNS + * Zero for success or -errno + */ + int (*atomic_check)(struct drm_device *dev, + struct drm_atomic_state *state); + + /** + * atomic_commit - commit state + * @dev: DRM device + * @state: the driver state object + * + * Commit the state. This will only be called if atomic_check() + * succeeds. + * + * RETURNS + * Zero for success or -errno + */ + int (*atomic_commit)(struct drm_device *dev, + struct drm_atomic_state *state); + + /** + * atomic_end - conclude the atomic update + * @dev: DRM device + * @state: the driver state object + + * Release resources associated with the state object. + */ + void (*atomic_end)(struct drm_device *dev, + struct drm_atomic_state *state); + + /** + * Funcs used by drm-atomic-helpers + */ + const struct drm_atomic_funcs *atomic_funcs; + /* Driver private ops for this object */ const struct vm_operations_struct *gem_vm_ops; diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h new file mode 100644 index 0000000..ff72b81 --- /dev/null +++ b/include/drm/drm_atomic.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 Red Hat + * Author: Rob Clark <robdclark@xxxxxxxxx> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DRM_ATOMIC_HELPER_H_ +#define DRM_ATOMIC_HELPER_H_ + +/** + * DOC: atomic state helpers + * + * Base helper atomic state and functions. Drivers are free to either + * use these as-is, extend them, or completely replace them, in order + * to implement the atomic KMS API. + * + * A naive driver, with no special constraints or hw support for atomic + * updates may simply add the following to their driver struct: + * + * .atomic_begin = drm_atomic_begin, + * .atomic_set_event = drm_atomic_set_event, + * .atomic_check = drm_atomic_check, + * .atomic_commit = drm_atomic_commit, + * .atomic_end = drm_atomic_end, + * .atomics = &drm_atomic_funcs, + * + * In addition, if you're plane/crtc doesn't already have it's own custom + * properties, then add to your plane/crtc_funcs: + * + * .set_property = drm_atomic_{plane,crtc}_set_property, + * + * Unlike the crtc helpers, it is intended that the atomic helpers can be + * used piecemeal by the drivers, either using all or overriding parts as + * needed. + * + * A driver which can have (for example) conflicting modes across multiple + * crtcs (for example, bandwidth limitations or clock/pll configuration + * restrictions), can simply wrap drm_atomic_check() with their own + * driver specific .atomic_check() function. + * + * A driver which can support true atomic updates can wrap + * drm_atomic_commit(). + * + * A driver with custom properties should override the appropriate get_state(), + * check_state(), and commit_state() functions in .atomics if it uses + * the drm-atomic-helpers. Otherwise it is free to use &drm_atomic_funcs + * as-is. + */ + +/** + * struct drm_atomic_funcs - helper funcs used by the atomic helpers + */ +struct drm_atomic_funcs { + int dummy; /* for now */ +}; + +const extern struct drm_atomic_funcs drm_atomic_funcs; + +struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev, + uint32_t flags); +int drm_atomic_set_event(struct drm_device *dev, + struct drm_atomic_state *state, struct drm_mode_object *obj, + struct drm_pending_vblank_event *event); +int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state); +int drm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state); +int drm_atomic_commit_unlocked(struct drm_device *dev, + struct drm_atomic_state *state); +void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state); + +/** + * struct drm_atomic_state - the state object used by atomic helpers + */ +struct drm_atomic_state { + struct kref refcount; + struct drm_device *dev; + uint32_t flags; + + bool committed; + bool checked; /* just for debugging */ + + struct drm_modeset_acquire_ctx acquire_ctx; +}; + +static inline void +drm_atomic_state_reference(struct drm_atomic_state *state) +{ + kref_get(&state->refcount); +} + +static inline void +drm_atomic_state_unreference(struct drm_atomic_state *state) +{ + void _drm_atomic_state_free(struct kref *kref); + kref_put(&state->refcount, _drm_atomic_state_free); +} + +#endif /* DRM_ATOMIC_HELPER_H_ */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3a3f7da..4963429 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -216,6 +216,8 @@ struct drm_encoder; struct drm_pending_vblank_event; struct drm_plane; struct drm_bridge; +struct drm_atomic_state; +struct drm_atomic_funcs; /** * drm_crtc_funcs - control CRTCs for a given device @@ -278,7 +280,9 @@ struct drm_crtc_funcs { uint32_t flags); int (*set_property)(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val); + struct drm_atomic_state *state, + struct drm_property *property, uint64_t val, + void *blob_data); }; /** @@ -392,8 +396,9 @@ struct drm_connector_funcs { enum drm_connector_status (*detect)(struct drm_connector *connector, bool force); int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); - int (*set_property)(struct drm_connector *connector, struct drm_property *property, - uint64_t val); + int (*set_property)(struct drm_connector *connector, + struct drm_atomic_state *state, + struct drm_property *property, uint64_t val, void *blob_data); void (*destroy)(struct drm_connector *connector); void (*force)(struct drm_connector *connector); }; @@ -562,7 +567,9 @@ struct drm_plane_funcs { void (*destroy)(struct drm_plane *plane); int (*set_property)(struct drm_plane *plane, - struct drm_property *property, uint64_t val); + struct drm_atomic_state *state, + struct drm_property *property, uint64_t val, + void *blob_data); }; enum drm_plane_type { diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index cfb1dc1..39560a4 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -32,6 +32,15 @@ struct drm_modeset_acquire_ctx { struct ww_acquire_ctx ww_ctx; + bool nolock : 1; + bool nonblock : 1; + + /* just for debugging, the context is 'frozen' in drm_atomic_check() + * to catch anyone who might be trying to acquire a lock after it is + * too late. + */ + bool frozen : 1; + /* contended lock: if a lock is contended you should only call * drm_modeset_backoff() which drops locks and slow-locks the * contended lock. @@ -40,6 +49,16 @@ struct drm_modeset_acquire_ctx { /* list of 'struct drm_modeset_lock': */ struct list_head locked; + + /* currently simply for protecting against 'locked' list manipulation + * between original thread calling atomic->end() and driver thread + * calling back drm_atomic_commit_unlocked(). + * + * Other spots are sufficiently synchronized by virtue of holding + * the lock's ww_mutex. But during the lock/resource hand-over to the + * driver thread (drop_locks()/grab_locks()), we cannot rely on this. + */ + struct mutex mutex; }; /** @@ -59,16 +78,37 @@ struct drm_modeset_lock { struct ww_mutex mutex; /** + * Are we busy (pending asynchronous/NONBLOCK update)? Any further + * asynchronous update will return -EBUSY if it also needs to acquire + * this lock. While a synchronous update will block until the pending + * async update completes. + * + * Drivers must ensure the update is completed before sending vblank + * event to userspace. Typically this just means don't send event + * before drm_atomic_commit_unlocked() returns. + */ + bool atomic_pending; + + /** * Resources that are locked as part of an atomic update are added * to a list (so we know what to unlock at the end). */ struct list_head head; + + /** + * For waiting on atomic_pending locks, if not a NONBLOCK operation. + */ + wait_queue_head_t event; }; extern struct ww_class crtc_ww_class; +#define DRM_MODESET_ACQUIRE_NOLOCK 0x0001 +#define DRM_MODESET_ACQUIRE_NONBLOCK 0x0002 + void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, uint32_t flags); +void __drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); @@ -78,6 +118,7 @@ static inline void drm_modeset_lock_init(struct drm_modeset_lock *lock) { ww_mutex_init(&lock->mutex, &crtc_ww_class); INIT_LIST_HEAD(&lock->head); + init_waitqueue_head(&lock->event); } static inline void drm_modeset_lock_fini(struct drm_modeset_lock *lock) diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index ded505e..6421edc 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -511,4 +511,7 @@ struct drm_mode_destroy_dumb { uint32_t handle; }; +#define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +#define DRM_MODE_ATOMIC_NOLOCK 0x8000 /* only used internally */ + #endif -- 1.9.3 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel