From patchwork Sat Oct 13 00:49:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 12196 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id AF31123EFB for ; Sat, 13 Oct 2012 00:49:24 +0000 (UTC) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by fiordland.canonical.com (Postfix) with ESMTP id 360D5A18888 for ; Sat, 13 Oct 2012 00:49:24 +0000 (UTC) Received: by mail-ie0-f180.google.com with SMTP id e10so5509064iej.11 for ; Fri, 12 Oct 2012 17:49:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :dkim-signature:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=1mhINDp4+W5bAZzA99tClLKwj+51bBjDDXMRaVShV/4=; b=RrnCSGA47etQvJyYe4SDV+elzgXWZqERRpzJn5qWN7uc9/pkxbSN+HGHDHXzN2kV7K e1sXOeNozHISTwcAw3iLSAqP1/ugTc2cj+smvcCt/fxc9cLSylMIeqiW6On+yoqs6Xyh rwbL4Az1OC+IMkjl1Tr1fT9s8IuDU5hhGzfLZ2Edxj0jqdLRWpH8ju1aVOOn4vs/KC3b KS5croiTjcib1WDScdNfS4zKXsQZvwCKenKcTM8N0EXxiQXdwEnYwwIfJ6+Y7zi9iARi yLUWZDA7OreSFYKmdyZXdn+lr9k4xwSjkVgzXr62eu5UZBrOYlgvtzZaSbloNBexdm7m Oekw== Received: by 10.50.168.37 with SMTP id zt5mr3587504igb.57.1350089363680; Fri, 12 Oct 2012 17:49:23 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.67.148 with SMTP id n20csp274600igt; Fri, 12 Oct 2012 17:49:22 -0700 (PDT) Received: by 10.182.194.70 with SMTP id hu6mr4884251obc.4.1350089362475; Fri, 12 Oct 2012 17:49:22 -0700 (PDT) Received: from mail-oa0-f50.google.com (mail-oa0-f50.google.com [209.85.219.50]) by mx.google.com with ESMTPS id d7si101453oea.52.2012.10.12.17.49.22 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 12 Oct 2012 17:49:22 -0700 (PDT) Received-SPF: pass (google.com: domain of robdclark@gmail.com designates 209.85.219.50 as permitted sender) client-ip=209.85.219.50; Authentication-Results: mx.google.com; spf=pass (google.com: domain of robdclark@gmail.com designates 209.85.219.50 as permitted sender) smtp.mail=robdclark@gmail.com; dkim=pass header.i=@gmail.com Received: by mail-oa0-f50.google.com with SMTP id n16so4214146oag.37 for ; Fri, 12 Oct 2012 17:49:22 -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=1mhINDp4+W5bAZzA99tClLKwj+51bBjDDXMRaVShV/4=; b=TnpMWoh5L8F+zCg2mCezrij9qhKsxXiVvv5KSCf5hsCF1zo6WWWFPV4oVLnBo5XIv/ gWJdxqzhRA3pKm0m7tRR1JUHRhwvWdgQoue51bcY2vZ9atlswEqkS2SASW25c9n7/Y1V nGRpv97R8g/eMv32DnzHbam4M2d4vWO+NJgchZ6T4mcTw/NR9+Sxi2tdEKr4P5KBPIAW W9CfSyA6mUnzO8DLaMifPsjJW57sD+74Q6SVg4Mp9jS60C9pX1GD3ZaEtJ4Utv7N7oJp 6yESuRbvzeddZIdd3BHUyEw4TxrMLRZY+WPXymF24qrdGhiYcfnsEhoBZk+X+AiQsTG1 dYdA== Received: by 10.182.177.100 with SMTP id cp4mr4901286obc.71.1350089362335; Fri, 12 Oct 2012 17:49:22 -0700 (PDT) Received: from localhost (ppp-70-129-143-201.dsl.rcsntx.swbell.net. [70.129.143.201]) by mx.google.com with ESMTPS id b5sm8238300obd.18.2012.10.12.17.49.20 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 12 Oct 2012 17:49:20 -0700 (PDT) Sender: Rob Clark From: Rob Clark To: dri-devel@lists.freedesktop.org Cc: patches@linaro.org, ville.syrjala@linux.intel.com, jbarnes@virtuousgeek.org, daniel.vetter@ffwll.ch, krh@bitplanet.net, Rob Clark Subject: [RFC 01/11] drm: add atomic fxns Date: Fri, 12 Oct 2012 19:49:02 -0500 Message-Id: <1350089352-18162-2-git-send-email-rob.clark@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1350089352-18162-1-git-send-email-rob.clark@linaro.org> References: <1350089352-18162-1-git-send-email-rob.clark@linaro.org> X-Gm-Message-State: ALoCoQkoaQzqHjY47nRyBbOomU7n1J1ZQpt7z+u5WedSboGfI4RGGcLJCgCicWQ73nO5VyN0SOk4 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. --- drivers/gpu/drm/drm_crtc.c | 126 +++++++++++++++++++++------------- drivers/staging/omapdrm/omap_crtc.c | 4 +- drivers/staging/omapdrm/omap_drv.h | 2 +- drivers/staging/omapdrm/omap_plane.c | 2 +- include/drm/drmP.h | 52 ++++++++++++++ include/drm/drm_crtc.h | 8 +-- 6 files changed, 139 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cee96f4..a236acf 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3208,12 +3208,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) { @@ -3221,7 +3220,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) @@ -3229,36 +3228,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) { @@ -3319,53 +3369,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, NULL); + 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/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index e430559..eddbb2f 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -327,7 +327,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, return 0; } -static int omap_crtc_set_property(struct drm_crtc *crtc, +static int omap_crtc_set_property(struct drm_crtc *crtc, void *state, struct drm_property *property, uint64_t val) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -338,7 +338,7 @@ 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); } static const struct drm_crtc_funcs omap_crtc_funcs = { diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index fec3c75..c20ed7e 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -171,7 +171,7 @@ int omap_plane_mode_set(struct drm_plane *plane, void (*fxn)(void *), void *arg); void omap_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); -int omap_plane_set_property(struct drm_plane *plane, +int omap_plane_set_property(struct drm_plane *plane, void *state, struct drm_property *property, uint64_t val); struct drm_encoder *omap_encoder_init(struct drm_device *dev); diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index c9098fc..854fdce 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c @@ -327,7 +327,7 @@ void omap_plane_install_properties(struct drm_plane *plane, drm_object_attach_property(obj, prop, 0); } -int omap_plane_set_property(struct drm_plane *plane, +int omap_plane_set_property(struct drm_plane *plane, void *state, struct drm_property *property, uint64_t val) { struct omap_plane *omap_plane = to_omap_plane(plane); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index ee8f927..9c41d36 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -940,6 +940,58 @@ 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. + * + * \param dev dev DRM device handle. + * \param crtc for asynchronous page-flip operations, the crtc + * that is being updated. (The driver should return -EBUSY if + * a page-flip is still pending.) Otherwise, NULL. + * \returns a driver private state object, which is passed + * back in to the various other atomic fxns + */ + void *(*atomic_begin)(struct drm_device *dev, struct drm_crtc *crtc); + + /** + * Check the state object to see if the requested state is + * physically possible. + * + * \param dev dev DRM device handle. + * \param state the driver private state object + */ + int (*atomic_check)(struct drm_device *dev, void *state); + + /** + * Commit the state. This will only be called if atomic_check() + * succeeds. + * + * \param dev dev DRM device handle. + * \param state the driver private state object + * \param event for asynchronous page-flip operations, the + * userspace has requested an event to be sent when the + * page-flip completes, or NULL. Will always be NULL for + * non-page-flip operations + */ + int (*atomic_commit)(struct drm_device *dev, void *state, + struct drm_pending_vblank_event *event); + + /** + * Release resources associated with the state object. + * + * \param dev dev DRM device handle. + * \param state the driver private 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 a45cdc2..4ae5295 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -356,7 +356,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); }; @@ -454,8 +454,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); };