From patchwork Mon Sep 10 03:03:14 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 1429151 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id D3183402E1 for ; Mon, 10 Sep 2012 03:04:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B992C9E9FB for ; Sun, 9 Sep 2012 20:04:48 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-oa0-f49.google.com (mail-oa0-f49.google.com [209.85.219.49]) by gabe.freedesktop.org (Postfix) with ESMTP id EFEDC9E95D for ; Sun, 9 Sep 2012 20:04:00 -0700 (PDT) Received: by oagh1 with SMTP id h1so375504oag.36 for ; Sun, 09 Sep 2012 20:04:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=POsJEGnGweEoUiXNOEC0U8JUMgKvBCM1RgbVjbG9O4M=; b=NOUBXn62EKW110z+mxFwZ6CZNmMmHqbuVU0uZPX/BhiodyraqcAgA/oFSK15NjYB8A nclUmLMdLtjv6f3ANFgylZmJ00xgZy7bY5kVhkeFFoepL5T4/ln3vsWDG+eA4+0kdD35 tGHqvgaTDBchg/3Ylx74IQ7hjh5PznqT68ChFPnOGayvJO6jnuVynmqiQCN0Hxx1L3NX 8YFI1990YtBsJ6CsK4kfMsCqab0ejmZOphRdDimU+JwymgJInGTOVxUNBkdhfJBZT2V8 GDiP1075FvxDATifVJMXZZINvQme93O5ASedGvfMZqnsJ83flfNmiy67TkjUo9ZtfjkZ PtuQ== Received: by 10.60.25.226 with SMTP id f2mr12425910oeg.53.1347246240248; Sun, 09 Sep 2012 20:04:00 -0700 (PDT) Received: from localhost (ppp-70-129-131-42.dsl.rcsntx.swbell.net. [70.129.131.42]) by mx.google.com with ESMTPS id a20sm9657652oei.2.2012.09.09.20.03.58 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 09 Sep 2012 20:03:59 -0700 (PDT) From: Rob Clark To: dri-devel@lists.freedesktop.org Subject: [RFC 1/9] drm: add atomic fxns Date: Sun, 9 Sep 2012 22:03:14 -0500 Message-Id: <1347246202-24249-2-git-send-email-rob.clark@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1347246202-24249-1-git-send-email-rob.clark@linaro.org> References: <1347246202-24249-1-git-send-email-rob.clark@linaro.org> Cc: daniel.vetter@ffwll.ch, Rob Clark , patches@linaro.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org From: Rob Clark 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, event); 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). The atomic functions are mandatory, as they will end up getting called from enough places that it is easier not to have to bother with if-null checks everywhere. TODO: + add some stub atomic functions that can be used by drivers until they are updated to support atomic operations natively + roll-back previous property values if check/commit fails, so userspace doesn't see incorrect values. --- drivers/gpu/drm/drm_crtc.c | 126 +++++++++++++++++++++++++++----------------- include/drm/drmP.h | 32 +++++++++++ include/drm/drm_crtc.h | 8 +-- 3 files changed, 115 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7552675..40a3f21 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3227,12 +3227,11 @@ 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, +static int drm_mode_connector_set_obj_prop(struct drm_connector *connector, + void *state, struct drm_property *property, uint64_t value) { int ret = -EINVAL; - struct drm_connector *connector = obj_to_connector(obj); /* Do DPMS ourselves */ if (property == connector->dev->mode_config.dpms_property) { @@ -3240,7 +3239,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, (*connector->funcs->dpms)(connector, (int)value); ret = 0; } else if (connector->funcs->set_property) - ret = connector->funcs->set_property(connector, property, value); + ret = connector->funcs->set_property(connector, state, property, value); /* store the property value if successful */ if (!ret) @@ -3248,36 +3247,87 @@ 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, +static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc, + void *state, struct drm_property *property, uint64_t value) { 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); 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, +static int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + void *state, struct drm_property *property, uint64_t value) { 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); 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, void *state, + struct drm_property *property, uint64_t value) +{ + 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); + case DRM_MODE_OBJECT_CRTC: + return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj), + state, property, value); + case DRM_MODE_OBJECT_PLANE: + return drm_mode_plane_set_obj_prop(obj_to_plane(obj), + state, property, value); + } + } + + return -EINVAL; +} + +/* call with mode_config mutex held */ +static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state, + uint32_t obj_id, uint32_t obj_type, + uint32_t prop_id, uint64_t value) +{ + struct drm_mode_object *arg_obj; + struct drm_mode_object *prop_obj; + struct drm_property *property; + int i; + + arg_obj = drm_mode_object_find(dev, obj_id, obj_type); + if (!arg_obj) + return -EINVAL; + 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; + + prop_obj = drm_mode_object_find(dev, prop_id, + DRM_MODE_OBJECT_PROPERTY); + if (!prop_obj) + return -EINVAL; + property = obj_to_property(prop_obj); + + return drm_mode_set_obj_prop(dev, arg_obj, state, property, value); +} + int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3338,53 +3388,35 @@ 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; + void *state = NULL; int ret = -EINVAL; - int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; mutex_lock(&dev->mode_config.mutex); - arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!arg_obj) - goto out; - if (!arg_obj->properties) - goto out; - - for (i = 0; i < arg_obj->properties->count; i++) - if (arg_obj->properties->ids[i] == arg->prop_id) - break; + state = dev->driver->atomic_begin(dev); + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto out_unlock; + } - if (i == arg_obj->properties->count) + ret = drm_mode_set_obj_prop_id(dev, state, + arg->obj_id, arg->obj_type, + arg->prop_id, arg->value); + if (ret) goto out; - prop_obj = drm_mode_object_find(dev, arg->prop_id, - DRM_MODE_OBJECT_PROPERTY); - if (!prop_obj) - 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, NULL); out: + dev->driver->atomic_end(dev, state); +out_unlock: mutex_unlock(&dev->mode_config.mutex); return ret; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d6b67bb..96530af 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -933,6 +933,38 @@ struct drm_driver { struct drm_device *dev, uint32_t handle); + /* + * Atomic functions: + */ + + /** + * 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. + */ + void *(*atomic_begin)(struct drm_device *dev); + + /** + * Check the state object to see if the requested state is + * physically possible. + */ + int (*atomic_check)(struct drm_device *dev, void *state); + + /** + * Commit the state. This will only be called if atomic_check() + * succeeds. + */ + int (*atomic_commit)(struct drm_device *dev, void *state, + struct drm_pending_vblank_event *event); + + /** + * Release resources associated with the state object. + */ + void (*atomic_end)(struct drm_device *dev, void *state); + /* Driver private ops for this object */ const struct vm_operations_struct *gem_vm_ops; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1422b36..a609190 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -357,7 +357,7 @@ struct drm_crtc_funcs { struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); - int (*set_property)(struct drm_crtc *crtc, + int (*set_property)(struct drm_crtc *crtc, void *state, struct drm_property *property, uint64_t val); }; @@ -455,8 +455,8 @@ 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, void *state, + struct drm_property *property, uint64_t val); void (*destroy)(struct drm_connector *connector); void (*force)(struct drm_connector *connector); }; @@ -627,7 +627,7 @@ struct drm_plane_funcs { int (*disable_plane)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane); - int (*set_property)(struct drm_plane *plane, + int (*set_property)(struct drm_plane *plane, void *state, struct drm_property *property, uint64_t val); };