From patchwork Mon Aug 29 08:27:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Vetter X-Patchwork-Id: 9303291 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 98798601C0 for ; Mon, 29 Aug 2016 08:28:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 86DE928766 for ; Mon, 29 Aug 2016 08:28:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7B936287F3; Mon, 29 Aug 2016 08:28:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B7DDF28766 for ; Mon, 29 Aug 2016 08:28:14 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5B4FC6E497; Mon, 29 Aug 2016 08:28:12 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wm0-x243.google.com (mail-wm0-x243.google.com [IPv6:2a00:1450:400c:c09::243]) by gabe.freedesktop.org (Postfix) with ESMTPS id 130976E458 for ; Mon, 29 Aug 2016 08:28:09 +0000 (UTC) Received: by mail-wm0-x243.google.com with SMTP id i5so8448786wmg.2 for ; Mon, 29 Aug 2016 01:28:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Nz318RgS4ESaMcnnfM9js+K6hiURfGBdJjGbOwVFI3E=; b=cmudgGuKpDwDpfAu/QcRr3Pp8mg3RWkk+RAfTOJ9EfyaQLCEmd3vj702jvgV7n5Ti+ a2uAgRU0EqkKdv1J8h2Mzg0f8+OBgSwLxLJwRC4eHHWvlGYxaSypNte47aGez9wyJJzD zf86gilyjXTSITk9a3Duqe9Jm3gH+V0FdIluU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Nz318RgS4ESaMcnnfM9js+K6hiURfGBdJjGbOwVFI3E=; b=EnZR9CaJ+4hanHaMMzXPpPJSIntQIStNeyq+rAqHdRid+NfO6RL9emFnRpu6np3hGl wQXSVD02XmAVFl9q0SRWpniMFf5Vdos3lUw49hLuwJgqcmib9YnQyTLfyzzNtK+Bf9E+ Q3uABfcNIhJDl4YQn+PHo1aFT3v30aEWobBOXJ0Vdnkq5oGRJARr1LrzX01/qWS21kvx vSzGy1weQLCNqxxYgG7CfZGRfgy0d4dFeH56GKbpqbX9OuVSVqYKhFiBRfBoSy3UxVyA ZNDIZFu7d3G2XLmGli66MHGR6k989scPY07HrMCDJSerHaoC6J0jZQSRBfW542xuhKK4 Qa6w== X-Gm-Message-State: AE9vXwMoXt1uwqbL9qhg00UYKzvGesKEpNqdy42Kxf45ivivMvyPUq+qmR82PNTPtPrTIg== X-Received: by 10.28.113.20 with SMTP id m20mr9000236wmc.82.1472459287022; Mon, 29 Aug 2016 01:28:07 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:56c9:0:decc:6e78:7e96:b452]) by smtp.gmail.com with ESMTPSA id b128sm12305797wmb.21.2016.08.29.01.28.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 29 Aug 2016 01:28:06 -0700 (PDT) From: Daniel Vetter To: DRI Development Subject: [PATCH 3/9] drm: Extract drm_mode_object.[hc] Date: Mon, 29 Aug 2016 10:27:51 +0200 Message-Id: <20160829082757.17913-3-daniel.vetter@ffwll.ch> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20160829082757.17913-1-daniel.vetter@ffwll.ch> References: <20160829082757.17913-1-daniel.vetter@ffwll.ch> Cc: Daniel Vetter , Daniel Vetter X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Just for the struct drm_mode_object base class. The header file was already partially extracted to help untangle the include loops. v2: - Also move the generic get/set property ioctls. At first this seemed like a bad idea since it requires making drm_mode_crtc_set_obj_prop non-static. But eventually that will get split away too (like the connector version already is) for both crtc and planes. Hence I reconsidered. - drm_mode_object.[hc] instead of drm_modeset.[hc], which requires renaming the drm_modeset.h header I already started building up. This is more consistent (matches the name of the main structure), and I want to be able to use drm_modeset.[hc] for the basic modeset init/cleanup functionality like drm_mode_config_init. Reviewed-by: Archit Taneja Signed-off-by: Daniel Vetter --- Documentation/gpu/drm-kms.rst | 9 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_crtc.c | 413 +-------------------- drivers/gpu/drm/drm_crtc_internal.h | 52 +-- drivers/gpu/drm/drm_mode_object.c | 435 +++++++++++++++++++++++ include/drm/drm_connector.h | 2 +- include/drm/drm_crtc.h | 12 +- include/drm/drm_encoder.h | 2 +- include/drm/drm_framebuffer.h | 2 +- include/drm/{drm_modeset.h => drm_mode_object.h} | 10 + include/drm/drm_modes.h | 2 +- 11 files changed, 492 insertions(+), 449 deletions(-) create mode 100644 drivers/gpu/drm/drm_mode_object.c rename include/drm/{drm_modeset.h => drm_mode_object.h} (87%) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 47c2835b7c2d..b164472f2157 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -15,6 +15,15 @@ be setup by initializing the following fields. - struct drm_mode_config_funcs \*funcs; Mode setting functions. +Modeset Base Object Abstraction +=============================== + +.. kernel-doc:: include/drm/drm_mode_object.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c + :export: + KMS Data Structures =================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8aa3a7800560..8d379565ac8e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ - drm_encoder.o + drm_encoder.o drm_mode_object.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 389d013dcb36..7ec9f7e7a077 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -57,162 +57,6 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { /* * Optional properties */ -/* - * Internal function to assign a slot in the object idr and optionally - * register the object into the idr. - */ -int drm_mode_object_get_reg(struct drm_device *dev, - struct drm_mode_object *obj, - uint32_t obj_type, - bool register_obj, - void (*obj_free_cb)(struct kref *kref)) -{ - int ret; - - mutex_lock(&dev->mode_config.idr_mutex); - ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); - if (ret >= 0) { - /* - * Set up the object linking under the protection of the idr - * lock so that other users can't see inconsistent state. - */ - obj->id = ret; - obj->type = obj_type; - if (obj_free_cb) { - obj->free_cb = obj_free_cb; - kref_init(&obj->refcount); - } - } - mutex_unlock(&dev->mode_config.idr_mutex); - - return ret < 0 ? ret : 0; -} - -/** - * drm_mode_object_get - allocate a new modeset identifier - * @dev: DRM device - * @obj: object pointer, used to generate unique ID - * @obj_type: object type - * - * Create a unique identifier based on @ptr in @dev's identifier space. Used - * for tracking modes, CRTCs and connectors. Note that despite the _get postfix - * modeset identifiers are _not_ reference counted. Hence don't use this for - * reference counted modeset objects like framebuffers. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_mode_object_get(struct drm_device *dev, - struct drm_mode_object *obj, uint32_t obj_type) -{ - return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); -} - -void drm_mode_object_register(struct drm_device *dev, - struct drm_mode_object *obj) -{ - mutex_lock(&dev->mode_config.idr_mutex); - idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); - mutex_unlock(&dev->mode_config.idr_mutex); -} - -/** - * drm_mode_object_unregister - free a modeset identifer - * @dev: DRM device - * @object: object to free - * - * Free @id from @dev's unique identifier pool. - * This function can be called multiple times, and guards against - * multiple removals. - * These modeset identifiers are _not_ reference counted. Hence don't use this - * for reference counted modeset objects like framebuffers. - */ -void drm_mode_object_unregister(struct drm_device *dev, - struct drm_mode_object *object) -{ - mutex_lock(&dev->mode_config.idr_mutex); - if (object->id) { - idr_remove(&dev->mode_config.crtc_idr, object->id); - object->id = 0; - } - mutex_unlock(&dev->mode_config.idr_mutex); -} - -struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, - uint32_t id, uint32_t type) -{ - struct drm_mode_object *obj = NULL; - - mutex_lock(&dev->mode_config.idr_mutex); - obj = idr_find(&dev->mode_config.crtc_idr, id); - if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) - obj = NULL; - if (obj && obj->id != id) - obj = NULL; - - if (obj && obj->free_cb) { - if (!kref_get_unless_zero(&obj->refcount)) - obj = NULL; - } - mutex_unlock(&dev->mode_config.idr_mutex); - - return obj; -} - -/** - * drm_mode_object_find - look up a drm object with static lifetime - * @dev: drm device - * @id: id of the mode object - * @type: type of the mode object - * - * This function is used to look up a modeset object. It will acquire a - * reference for reference counted objects. This reference must be dropped again - * by callind drm_mode_object_unreference(). - */ -struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, - uint32_t id, uint32_t type) -{ - struct drm_mode_object *obj = NULL; - - obj = __drm_mode_object_find(dev, id, type); - return obj; -} -EXPORT_SYMBOL(drm_mode_object_find); - -/** - * drm_mode_object_unreference - decr the object refcnt - * @obj: mode_object - * - * This functions decrements the object's refcount if it is a refcounted modeset - * object. It is a no-op on any other object. This is used to drop references - * acquired with drm_mode_object_reference(). - */ -void drm_mode_object_unreference(struct drm_mode_object *obj) -{ - if (obj->free_cb) { - DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); - kref_put(&obj->refcount, obj->free_cb); - } -} -EXPORT_SYMBOL(drm_mode_object_unreference); - -/** - * drm_mode_object_reference - incr the object refcnt - * @obj: mode_object - * - * This functions increments the object's refcount if it is a refcounted modeset - * object. It is a no-op on any other object. References should be dropped again - * by calling drm_mode_object_unreference(). - */ -void drm_mode_object_reference(struct drm_mode_object *obj) -{ - if (obj->free_cb) { - DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); - kref_get(&obj->refcount); - } -} -EXPORT_SYMBOL(drm_mode_object_reference); - /** * drm_crtc_force_disable - Forcibly turn off a CRTC * @crtc: CRTC to turn off @@ -1005,45 +849,6 @@ int drm_mode_getcrtc(struct drm_device *dev, return 0; } -/* helper for getconnector and getproperties ioctls */ -int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, - uint32_t __user *prop_ptr, - uint64_t __user *prop_values, - uint32_t *arg_count_props) -{ - int props_count; - int i, ret, copied; - - props_count = obj->properties->count; - if (!atomic) - props_count -= obj->properties->atomic_count; - - if ((*arg_count_props >= props_count) && props_count) { - for (i = 0, copied = 0; copied < props_count; i++) { - struct drm_property *prop = obj->properties->properties[i]; - uint64_t val; - - if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) - continue; - - ret = drm_object_property_get_value(obj, prop, &val); - if (ret) - return ret; - - if (put_user(prop->base.id, prop_ptr + copied)) - return -EFAULT; - - if (put_user(val, prop_values + copied)) - return -EFAULT; - - copied++; - } - } - *arg_count_props = props_count; - - return 0; -} - /** * drm_mode_getplane_res - enumerate all plane resources * @dev: DRM device @@ -2286,105 +2091,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) EXPORT_SYMBOL(drm_property_destroy); /** - * drm_object_attach_property - attach a property to a modeset object - * @obj: drm modeset object - * @property: property to attach - * @init_val: initial value of the property - * - * This attaches the given property to the modeset object with the given initial - * value. Currently this function cannot fail since the properties are stored in - * a statically sized array. - */ -void drm_object_attach_property(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t init_val) -{ - int count = obj->properties->count; - - if (count == DRM_OBJECT_MAX_PROPERTY) { - WARN(1, "Failed to attach object property (type: 0x%x). Please " - "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " - "you see this message on the same object type.\n", - obj->type); - return; - } - - obj->properties->properties[count] = property; - obj->properties->values[count] = init_val; - obj->properties->count++; - if (property->flags & DRM_MODE_PROP_ATOMIC) - obj->properties->atomic_count++; -} -EXPORT_SYMBOL(drm_object_attach_property); - -/** - * drm_object_property_set_value - set the value of a property - * @obj: drm mode object to set property value for - * @property: property to set - * @val: value the property should be set to - * - * This functions sets a given property on a given object. This function only - * changes the software state of the property, it does not call into the - * driver's ->set_property callback. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_object_property_set_value(struct drm_mode_object *obj, - struct drm_property *property, uint64_t val) -{ - int i; - - for (i = 0; i < obj->properties->count; i++) { - if (obj->properties->properties[i] == property) { - obj->properties->values[i] = val; - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL(drm_object_property_set_value); - -/** - * drm_object_property_get_value - retrieve the value of a property - * @obj: drm mode object to get property value from - * @property: property to retrieve - * @val: storage for the property value - * - * This function retrieves the softare state of the given property for the given - * property. Since there is no driver callback to retrieve the current property - * value this might be out of sync with the hardware, depending upon the driver - * and property. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_object_property_get_value(struct drm_mode_object *obj, - struct drm_property *property, uint64_t *val) -{ - int i; - - /* read-only properties bypass atomic mechanism and still store - * their value in obj->properties->values[].. mostly to avoid - * having to deal w/ EDID and similar props in atomic paths: - */ - if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && - !(property->flags & DRM_MODE_PROP_IMMUTABLE)) - return drm_atomic_get_property(obj, property, val); - - for (i = 0; i < obj->properties->count; i++) { - if (obj->properties->properties[i] == property) { - *val = obj->properties->values[i]; - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL(drm_object_property_get_value); - -/** * drm_mode_getproperty_ioctl - get the property metadata * @dev: DRM device * @data: ioctl data @@ -2929,9 +2635,9 @@ void drm_property_change_valid_put(struct drm_property *property, drm_property_unreference_blob(obj_to_blob(ref)); } -static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) +int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value) { int ret = -EINVAL; struct drm_crtc *crtc = obj_to_crtc(obj); @@ -2974,119 +2680,6 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane, EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); /** - * 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 - * - * This function retrieves the current value for an object's property. Compared - * to the connector specific ioctl this one is extended to also work on crtc and - * plane objects. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_obj_get_properties *arg = data; - struct drm_mode_object *obj; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!obj) { - ret = -ENOENT; - goto out; - } - if (!obj->properties) { - ret = -EINVAL; - goto out_unref; - } - - ret = drm_mode_object_get_properties(obj, file_priv->atomic, - (uint32_t __user *)(unsigned long)(arg->props_ptr), - (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), - &arg->count_props); - -out_unref: - drm_mode_object_unreference(obj); -out: - drm_modeset_unlock_all(dev); - return ret; -} - -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; - int i, ret = -EINVAL; - struct drm_mode_object *ref; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - - arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!arg_obj) { - ret = -ENOENT; - goto out; - } - if (!arg_obj->properties) - goto out_unref; - - for (i = 0; i < arg_obj->properties->count; i++) - if (arg_obj->properties->properties[i]->base.id == arg->prop_id) - break; - - if (i == arg_obj->properties->count) - goto out_unref; - - prop_obj = drm_mode_object_find(dev, arg->prop_id, - DRM_MODE_OBJECT_PROPERTY); - if (!prop_obj) { - ret = -ENOENT; - goto out_unref; - } - property = obj_to_property(prop_obj); - - if (!drm_property_change_valid_get(property, arg->value, &ref)) - goto out_unref; - - 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(obj_to_plane(arg_obj), - property, arg->value); - break; - } - - drm_property_change_valid_put(property, ref); - -out_unref: - drm_mode_object_unreference(arg_obj); -out: - drm_modeset_unlock_all(dev); - return ret; -} - -/** * drm_mode_crtc_set_gamma_size - set the gamma table size * @crtc: CRTC to set the gamma table size for * @gamma_size: size of the gamma table diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 69f2b21ddad3..26ea7b5e3684 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -33,29 +33,14 @@ /* drm_crtc.c */ -int drm_mode_object_get_reg(struct drm_device *dev, - struct drm_mode_object *obj, - uint32_t obj_type, - bool register_obj, - void (*obj_free_cb)(struct kref *kref)); -void drm_mode_object_register(struct drm_device *dev, - struct drm_mode_object *obj); -int drm_mode_object_get(struct drm_device *dev, - struct drm_mode_object *obj, uint32_t obj_type); -struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, - uint32_t id, uint32_t type); -void drm_mode_object_unregister(struct drm_device *dev, - struct drm_mode_object *object); -int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, - uint32_t __user *prop_ptr, - uint64_t __user *prop_values, - uint32_t *arg_count_props); +int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t value); bool drm_property_change_valid_get(struct drm_property *property, uint64_t value, struct drm_mode_object **ref); void drm_property_change_valid_put(struct drm_property *property, struct drm_mode_object *ref); - int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format); int drm_crtc_check_viewport(const struct drm_crtc *crtc, @@ -76,11 +61,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); /* IOCTLs */ -int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); - int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_getplane_res(struct drm_device *dev, void *data, @@ -113,6 +93,32 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* drm_mode_object.c */ +int drm_mode_object_get_reg(struct drm_device *dev, + struct drm_mode_object *obj, + uint32_t obj_type, + bool register_obj, + void (*obj_free_cb)(struct kref *kref)); +void drm_mode_object_register(struct drm_device *dev, + struct drm_mode_object *obj); +int drm_mode_object_get(struct drm_device *dev, + struct drm_mode_object *obj, uint32_t obj_type); +struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type); +void drm_mode_object_unregister(struct drm_device *dev, + struct drm_mode_object *object); +int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, + uint32_t __user *prop_ptr, + uint64_t __user *prop_values, + uint32_t *arg_count_props); + +/* IOCTL */ + +int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + /* drm_encoder.c */ int drm_encoder_register_all(struct drm_device *dev); void drm_encoder_unregister_all(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c new file mode 100644 index 000000000000..cef9104e8285 --- /dev/null +++ b/drivers/gpu/drm/drm_mode_object.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "drm_crtc_internal.h" + +/* + * Internal function to assign a slot in the object idr and optionally + * register the object into the idr. + */ +int drm_mode_object_get_reg(struct drm_device *dev, + struct drm_mode_object *obj, + uint32_t obj_type, + bool register_obj, + void (*obj_free_cb)(struct kref *kref)) +{ + int ret; + + mutex_lock(&dev->mode_config.idr_mutex); + ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); + if (ret >= 0) { + /* + * Set up the object linking under the protection of the idr + * lock so that other users can't see inconsistent state. + */ + obj->id = ret; + obj->type = obj_type; + if (obj_free_cb) { + obj->free_cb = obj_free_cb; + kref_init(&obj->refcount); + } + } + mutex_unlock(&dev->mode_config.idr_mutex); + + return ret < 0 ? ret : 0; +} + +/** + * drm_mode_object_get - allocate a new modeset identifier + * @dev: DRM device + * @obj: object pointer, used to generate unique ID + * @obj_type: object type + * + * Create a unique identifier based on @ptr in @dev's identifier space. Used + * for tracking modes, CRTCs and connectors. Note that despite the _get postfix + * modeset identifiers are _not_ reference counted. Hence don't use this for + * reference counted modeset objects like framebuffers. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_mode_object_get(struct drm_device *dev, + struct drm_mode_object *obj, uint32_t obj_type) +{ + return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); +} + +void drm_mode_object_register(struct drm_device *dev, + struct drm_mode_object *obj) +{ + mutex_lock(&dev->mode_config.idr_mutex); + idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); + mutex_unlock(&dev->mode_config.idr_mutex); +} + +/** + * drm_mode_object_unregister - free a modeset identifer + * @dev: DRM device + * @object: object to free + * + * Free @id from @dev's unique identifier pool. + * This function can be called multiple times, and guards against + * multiple removals. + * These modeset identifiers are _not_ reference counted. Hence don't use this + * for reference counted modeset objects like framebuffers. + */ +void drm_mode_object_unregister(struct drm_device *dev, + struct drm_mode_object *object) +{ + mutex_lock(&dev->mode_config.idr_mutex); + if (object->id) { + idr_remove(&dev->mode_config.crtc_idr, object->id); + object->id = 0; + } + mutex_unlock(&dev->mode_config.idr_mutex); +} + +struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type) +{ + struct drm_mode_object *obj = NULL; + + mutex_lock(&dev->mode_config.idr_mutex); + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) + obj = NULL; + if (obj && obj->id != id) + obj = NULL; + + if (obj && obj->free_cb) { + if (!kref_get_unless_zero(&obj->refcount)) + obj = NULL; + } + mutex_unlock(&dev->mode_config.idr_mutex); + + return obj; +} + +/** + * drm_mode_object_find - look up a drm object with static lifetime + * @dev: drm device + * @id: id of the mode object + * @type: type of the mode object + * + * This function is used to look up a modeset object. It will acquire a + * reference for reference counted objects. This reference must be dropped again + * by callind drm_mode_object_unreference(). + */ +struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, + uint32_t id, uint32_t type) +{ + struct drm_mode_object *obj = NULL; + + obj = __drm_mode_object_find(dev, id, type); + return obj; +} +EXPORT_SYMBOL(drm_mode_object_find); + +/** + * drm_mode_object_unreference - decr the object refcnt + * @obj: mode_object + * + * This functions decrements the object's refcount if it is a refcounted modeset + * object. It is a no-op on any other object. This is used to drop references + * acquired with drm_mode_object_reference(). + */ +void drm_mode_object_unreference(struct drm_mode_object *obj) +{ + if (obj->free_cb) { + DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); + kref_put(&obj->refcount, obj->free_cb); + } +} +EXPORT_SYMBOL(drm_mode_object_unreference); + +/** + * drm_mode_object_reference - incr the object refcnt + * @obj: mode_object + * + * This functions increments the object's refcount if it is a refcounted modeset + * object. It is a no-op on any other object. References should be dropped again + * by calling drm_mode_object_unreference(). + */ +void drm_mode_object_reference(struct drm_mode_object *obj) +{ + if (obj->free_cb) { + DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); + kref_get(&obj->refcount); + } +} +EXPORT_SYMBOL(drm_mode_object_reference); + +/** + * drm_object_attach_property - attach a property to a modeset object + * @obj: drm modeset object + * @property: property to attach + * @init_val: initial value of the property + * + * This attaches the given property to the modeset object with the given initial + * value. Currently this function cannot fail since the properties are stored in + * a statically sized array. + */ +void drm_object_attach_property(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t init_val) +{ + int count = obj->properties->count; + + if (count == DRM_OBJECT_MAX_PROPERTY) { + WARN(1, "Failed to attach object property (type: 0x%x). Please " + "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " + "you see this message on the same object type.\n", + obj->type); + return; + } + + obj->properties->properties[count] = property; + obj->properties->values[count] = init_val; + obj->properties->count++; + if (property->flags & DRM_MODE_PROP_ATOMIC) + obj->properties->atomic_count++; +} +EXPORT_SYMBOL(drm_object_attach_property); + +/** + * drm_object_property_set_value - set the value of a property + * @obj: drm mode object to set property value for + * @property: property to set + * @val: value the property should be set to + * + * This functions sets a given property on a given object. This function only + * changes the software state of the property, it does not call into the + * driver's ->set_property callback. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_object_property_set_value(struct drm_mode_object *obj, + struct drm_property *property, uint64_t val) +{ + int i; + + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->properties[i] == property) { + obj->properties->values[i] = val; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(drm_object_property_set_value); + +/** + * drm_object_property_get_value - retrieve the value of a property + * @obj: drm mode object to get property value from + * @property: property to retrieve + * @val: storage for the property value + * + * This function retrieves the softare state of the given property for the given + * property. Since there is no driver callback to retrieve the current property + * value this might be out of sync with the hardware, depending upon the driver + * and property. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_object_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val) +{ + int i; + + /* read-only properties bypass atomic mechanism and still store + * their value in obj->properties->values[].. mostly to avoid + * having to deal w/ EDID and similar props in atomic paths: + */ + if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && + !(property->flags & DRM_MODE_PROP_IMMUTABLE)) + return drm_atomic_get_property(obj, property, val); + + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->properties[i] == property) { + *val = obj->properties->values[i]; + return 0; + } + + } + + return -EINVAL; +} +EXPORT_SYMBOL(drm_object_property_get_value); + +/* helper for getconnector and getproperties ioctls */ +int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, + uint32_t __user *prop_ptr, + uint64_t __user *prop_values, + uint32_t *arg_count_props) +{ + int props_count; + int i, ret, copied; + + props_count = obj->properties->count; + if (!atomic) + props_count -= obj->properties->atomic_count; + + if ((*arg_count_props >= props_count) && props_count) { + for (i = 0, copied = 0; copied < props_count; i++) { + struct drm_property *prop = obj->properties->properties[i]; + uint64_t val; + + if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) + continue; + + ret = drm_object_property_get_value(obj, prop, &val); + if (ret) + return ret; + + if (put_user(prop->base.id, prop_ptr + copied)) + return -EFAULT; + + if (put_user(val, prop_values + copied)) + return -EFAULT; + + copied++; + } + } + *arg_count_props = props_count; + + return 0; +} + +/** + * 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 + * + * This function retrieves the current value for an object's property. Compared + * to the connector specific ioctl this one is extended to also work on crtc and + * plane objects. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_obj_get_properties *arg = data; + struct drm_mode_object *obj; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + + obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); + if (!obj) { + ret = -ENOENT; + goto out; + } + if (!obj->properties) { + ret = -EINVAL; + goto out_unref; + } + + ret = drm_mode_object_get_properties(obj, file_priv->atomic, + (uint32_t __user *)(unsigned long)(arg->props_ptr), + (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), + &arg->count_props); + +out_unref: + drm_mode_object_unreference(obj); +out: + drm_modeset_unlock_all(dev); + return ret; +} + +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; + int i, ret = -EINVAL; + struct drm_mode_object *ref; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + + arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); + if (!arg_obj) { + ret = -ENOENT; + goto out; + } + if (!arg_obj->properties) + goto out_unref; + + for (i = 0; i < arg_obj->properties->count; i++) + if (arg_obj->properties->properties[i]->base.id == arg->prop_id) + break; + + if (i == arg_obj->properties->count) + goto out_unref; + + prop_obj = drm_mode_object_find(dev, arg->prop_id, + DRM_MODE_OBJECT_PROPERTY); + if (!prop_obj) { + ret = -ENOENT; + goto out_unref; + } + property = obj_to_property(prop_obj); + + if (!drm_property_change_valid_get(property, arg->value, &ref)) + goto out_unref; + + 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(obj_to_plane(arg_obj), + property, arg->value); + break; + } + + drm_property_change_valid_put(property, ref); + +out_unref: + drm_mode_object_unreference(arg_obj); +out: + drm_modeset_unlock_all(dev); + return ret; +} diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f1576db6c044..66b7d6744dd2 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -25,7 +25,7 @@ #include #include -#include +#include struct drm_connector_helper_funcs; struct drm_device; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7a53b053cbe7..b3c3f0c7b449 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -2122,16 +2122,6 @@ static inline bool drm_property_type_is(struct drm_property *property, return property->flags & type; } -extern int drm_object_property_set_value(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t val); -extern int drm_object_property_get_value(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t *value); - -extern void drm_object_attach_property(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 3d7350f1fcc1..fce0203094f7 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -25,7 +25,7 @@ #include #include -#include +#include /** * struct drm_encoder_funcs - encoder controls diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 50deb40d3bfd..b2554c50a903 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -25,7 +25,7 @@ #include #include -#include +#include struct drm_framebuffer; struct drm_file; diff --git a/include/drm/drm_modeset.h b/include/drm/drm_mode_object.h similarity index 87% rename from include/drm/drm_modeset.h rename to include/drm/drm_mode_object.h index fe910d5efe12..c0e4414299f7 100644 --- a/include/drm/drm_modeset.h +++ b/include/drm/drm_mode_object.h @@ -67,4 +67,14 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, void drm_mode_object_reference(struct drm_mode_object *obj); void drm_mode_object_unreference(struct drm_mode_object *obj); +int drm_object_property_set_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t val); +int drm_object_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t *value); + +void drm_object_attach_property(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t init_val); #endif diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 1621e9b32330..011f199d3bcf 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -27,7 +27,7 @@ #ifndef __DRM_MODES_H__ #define __DRM_MODES_H__ -#include +#include #include /*