On Wed, Jul 23, 2014 at 03:38:14PM -0400, Rob Clark wrote: > 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> [snip] > + if (flags & DRM_MODE_ATOMIC_NOLOCK) > + acquire_flags |= DRM_MODESET_ACQUIRE_NOLOCK; > + if (flags & DRM_MODE_ATOMIC_NONBLOCK) > + acquire_flags |= DRM_MODESET_ACQUIRE_NONBLOCK; Just a very quick reply. Can you please remove the code which does the NOLOCK/NONBLOCK stuff here? It's not really part of the property conversion and I'm still not sold on those concepts. At least I want to review them once we add them, maybe at the very end where everything else is clear. Afaics nothing in this series actually uses this. -Daniel > + > + 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 1ccf5cb..6710de3 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" > > @@ -4056,20 +4057,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) > @@ -4077,38 +4079,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 > @@ -4198,58 +4252,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 0dc57d5..6c6b292 100644 > --- a/drivers/gpu/drm/drm_modeset_lock.c > +++ b/drivers/gpu/drm/drm_modeset_lock.c > @@ -67,9 +67,18 @@ void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, > memset(ctx, 0, sizeof(*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); > +} > + > /** > * drm_modeset_acquire_fini - cleanup acquire context > * @ctx: the acquire context > @@ -77,6 +86,7 @@ EXPORT_SYMBOL(drm_modeset_acquire_init); > 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); > > @@ -89,6 +99,7 @@ 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; > > @@ -97,6 +108,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); > > @@ -106,8 +118,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) { > @@ -119,6 +136,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) { > @@ -222,7 +248,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 95c9435..4cb016b 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 d82e3cb..c7e2ea5a 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> > #include <linux/component.h> > @@ -338,6 +339,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 248c33a..4faefb7 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 a4cc0e6..54fca10 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 4268bf2..46065de 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 0b77039..79826b1 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 abf2248..98decea 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 6e8fe9e..01c5edc 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 88aad95..e939e62 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 0be96fd..e8be7e9 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 83cb43a..c0bfa60 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -1544,6 +1544,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 88db4b6..3054a75 100644 > --- a/drivers/gpu/drm/i915/intel_crt.c > +++ b/drivers/gpu/drm/i915/intel_crt.c > @@ -753,8 +753,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 ae3737c..9f53e10 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -3719,8 +3719,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 c5e2ac4..9145756 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 2422413..a790103 100644 > --- a/drivers/gpu/drm/i915/intel_hdmi.c > +++ b/drivers/gpu/drm/i915/intel_hdmi.c > @@ -1063,8 +1063,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 c511287..4bc01a4 100644 > --- a/drivers/gpu/drm/i915/intel_lvds.c > +++ b/drivers/gpu/drm/i915/intel_lvds.c > @@ -480,8 +480,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 9350edd..12357a8 100644 > --- a/drivers/gpu/drm/i915/intel_sdvo.c > +++ b/drivers/gpu/drm/i915/intel_sdvo.c > @@ -2065,8 +2065,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 e211eef..7ec9bc5 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 74cebb5..60d7e73 100644 > --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c > +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c > @@ -466,7 +466,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 ebe2e60..deb6647 100644 > --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c > +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c > @@ -384,7 +384,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 f3daec4..d560e42 100644 > --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c > +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c > @@ -103,7 +103,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 5984ec2..81531ce1 100644 > --- a/drivers/gpu/drm/msm/msm_drv.c > +++ b/drivers/gpu/drm/msm/msm_drv.c > @@ -858,6 +858,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 8a2c5fd..5c2919c 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 dbdc9ad..95eeea1 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_connector.c > +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c > @@ -441,7 +441,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 5425ffe..54341f6 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_drm.c > +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c > @@ -859,6 +859,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 b8ced08..3dcc70c 100644 > --- a/drivers/gpu/drm/qxl/qxl_display.c > +++ b/drivers/gpu/drm/qxl/qxl_display.c > @@ -823,8 +823,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 c667c43..eb62df4 100644 > --- a/drivers/gpu/drm/radeon/radeon_connectors.c > +++ b/drivers/gpu/drm/radeon/radeon_connectors.c > @@ -409,8 +409,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; > @@ -732,8 +733,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 cb14213..28c15ed 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> > @@ -558,6 +559,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 6be623b..aa62aee 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c > +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c > @@ -514,6 +514,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 7596c14..3806618 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 3775fd4..a422bed 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c > +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c > @@ -207,7 +207,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 e026a9e..6f14aad 100644 > --- a/drivers/gpu/drm/udl/udl_connector.c > +++ b/drivers/gpu/drm/udl/udl_connector.c > @@ -108,9 +108,9 @@ udl_best_single_encoder(struct drm_connector *connector) > return drm_encoder_find(connector->dev, enc_id); > } > > -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 f31a754..b7af574 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c > @@ -1426,6 +1426,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 c181175..bcc1a07 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 991e5c8..a2227cd 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c > @@ -2005,8 +2005,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 9b6a445..350eb2e 100644 > --- a/include/drm/drmP.h > +++ b/include/drm/drmP.h > @@ -946,6 +946,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 e529b68..c8f9c28 100644 > --- a/include/drm/drm_crtc.h > +++ b/include/drm/drm_crtc.h > @@ -219,6 +219,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 > @@ -281,7 +283,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); > }; > > /** > @@ -399,8 +403,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); > }; > @@ -574,7 +579,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 402aa7a..9226c78 100644 > --- a/include/drm/drm_modeset_lock.h > +++ b/include/drm/drm_modeset_lock.h > @@ -32,6 +32,9 @@ struct drm_modeset_lock; > * drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) > * @ww_ctx: base acquire ctx > * @contended: used internally for -EDEADLK handling > + * @nolock: bypass locking (for emergencies) > + * @nonblock: don't block > + * @frozen: for debugging > * @locked: list of held locks > * > * Each thread competing for a set of locks must use one acquire > @@ -42,6 +45,16 @@ 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 > @@ -53,11 +66,23 @@ struct drm_modeset_acquire_ctx { > * list of held locks (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; > }; > > /** > * drm_modeset_lock - used for locking modeset resources. > * @mutex: resource locking > + * @atomic_pending: is this resource part of a still-pending > + * atomic update > * @head: used to hold it's place on state->locked list when > * part of an atomic update > * > @@ -70,16 +95,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); > @@ -93,6 +139,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); > } > > /** > diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h > index def54f9..81b815f 100644 > --- a/include/uapi/drm/drm_mode.h > +++ b/include/uapi/drm/drm_mode.h > @@ -512,4 +512,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 > -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel