xref: /openbmc/linux/drivers/gpu/drm/drm_property.c (revision 753f2674)
159e71ee7SDaniel Vetter /*
259e71ee7SDaniel Vetter  * Copyright (c) 2016 Intel Corporation
359e71ee7SDaniel Vetter  *
459e71ee7SDaniel Vetter  * Permission to use, copy, modify, distribute, and sell this software and its
559e71ee7SDaniel Vetter  * documentation for any purpose is hereby granted without fee, provided that
659e71ee7SDaniel Vetter  * the above copyright notice appear in all copies and that both that copyright
759e71ee7SDaniel Vetter  * notice and this permission notice appear in supporting documentation, and
859e71ee7SDaniel Vetter  * that the name of the copyright holders not be used in advertising or
959e71ee7SDaniel Vetter  * publicity pertaining to distribution of the software without specific,
1059e71ee7SDaniel Vetter  * written prior permission.  The copyright holders make no representations
1159e71ee7SDaniel Vetter  * about the suitability of this software for any purpose.  It is provided "as
1259e71ee7SDaniel Vetter  * is" without express or implied warranty.
1359e71ee7SDaniel Vetter  *
1459e71ee7SDaniel Vetter  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1559e71ee7SDaniel Vetter  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1659e71ee7SDaniel Vetter  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1759e71ee7SDaniel Vetter  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1859e71ee7SDaniel Vetter  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1959e71ee7SDaniel Vetter  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2059e71ee7SDaniel Vetter  * OF THIS SOFTWARE.
2159e71ee7SDaniel Vetter  */
2259e71ee7SDaniel Vetter 
2359e71ee7SDaniel Vetter #include <linux/export.h>
240500c04eSSam Ravnborg #include <linux/uaccess.h>
250500c04eSSam Ravnborg 
260500c04eSSam Ravnborg #include <drm/drm_crtc.h>
270500c04eSSam Ravnborg #include <drm/drm_drv.h>
280500c04eSSam Ravnborg #include <drm/drm_file.h>
290500c04eSSam Ravnborg #include <drm/drm_framebuffer.h>
3059e71ee7SDaniel Vetter #include <drm/drm_property.h>
3159e71ee7SDaniel Vetter 
3259e71ee7SDaniel Vetter #include "drm_crtc_internal.h"
3359e71ee7SDaniel Vetter 
34c8458c7eSDaniel Vetter /**
35c8458c7eSDaniel Vetter  * DOC: overview
36c8458c7eSDaniel Vetter  *
37c8458c7eSDaniel Vetter  * Properties as represented by &drm_property are used to extend the modeset
38c8458c7eSDaniel Vetter  * interface exposed to userspace. For the atomic modeset IOCTL properties are
39c8458c7eSDaniel Vetter  * even the only way to transport metadata about the desired new modeset
40c8458c7eSDaniel Vetter  * configuration from userspace to the kernel. Properties have a well-defined
41c8458c7eSDaniel Vetter  * value range, which is enforced by the drm core. See the documentation of the
42ea0dd85aSDaniel Vetter  * flags member of &struct drm_property for an overview of the different
43c8458c7eSDaniel Vetter  * property types and ranges.
44c8458c7eSDaniel Vetter  *
45c8458c7eSDaniel Vetter  * Properties don't store the current value directly, but need to be
464cf1d871SBhaskar Chowdhury  * instantiated by attaching them to a &drm_mode_object with
47c8458c7eSDaniel Vetter  * drm_object_attach_property().
48c8458c7eSDaniel Vetter  *
49c8458c7eSDaniel Vetter  * Property values are only 64bit. To support bigger piles of data (like gamma
50d574528aSDaniel Vetter  * tables, color correction matrices or large structures) a property can instead
51d574528aSDaniel Vetter  * point at a &drm_property_blob with that additional data.
52c8458c7eSDaniel Vetter  *
53c8458c7eSDaniel Vetter  * Properties are defined by their symbolic name, userspace must keep a
54c8458c7eSDaniel Vetter  * per-object mapping from those names to the property ID used in the atomic
55c8458c7eSDaniel Vetter  * IOCTL and in the get/set property IOCTL.
56c8458c7eSDaniel Vetter  */
57c8458c7eSDaniel Vetter 
drm_property_flags_valid(u32 flags)58100bc0d9SVille Syrjälä static bool drm_property_flags_valid(u32 flags)
5959e71ee7SDaniel Vetter {
60100bc0d9SVille Syrjälä 	u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
61100bc0d9SVille Syrjälä 	u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
62100bc0d9SVille Syrjälä 
63100bc0d9SVille Syrjälä 	/* Reject undefined/deprecated flags */
64100bc0d9SVille Syrjälä 	if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
65100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_EXTENDED_TYPE |
66100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_IMMUTABLE |
67100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_ATOMIC))
68100bc0d9SVille Syrjälä 		return false;
69100bc0d9SVille Syrjälä 
70100bc0d9SVille Syrjälä 	/* We want either a legacy type or an extended type, but not both */
71100bc0d9SVille Syrjälä 	if (!legacy_type == !ext_type)
72100bc0d9SVille Syrjälä 		return false;
73100bc0d9SVille Syrjälä 
74100bc0d9SVille Syrjälä 	/* Only one legacy type at a time please */
75100bc0d9SVille Syrjälä 	if (legacy_type && !is_power_of_2(legacy_type))
76100bc0d9SVille Syrjälä 		return false;
77100bc0d9SVille Syrjälä 
78100bc0d9SVille Syrjälä 	return true;
7959e71ee7SDaniel Vetter }
8059e71ee7SDaniel Vetter 
8159e71ee7SDaniel Vetter /**
8259e71ee7SDaniel Vetter  * drm_property_create - create a new property type
8359e71ee7SDaniel Vetter  * @dev: drm device
8459e71ee7SDaniel Vetter  * @flags: flags specifying the property type
8559e71ee7SDaniel Vetter  * @name: name of the property
8659e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
8759e71ee7SDaniel Vetter  *
8859e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
896a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
906a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
916a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
9259e71ee7SDaniel Vetter  *
9359e71ee7SDaniel Vetter  * Returns:
9459e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
9559e71ee7SDaniel Vetter  */
drm_property_create(struct drm_device * dev,u32 flags,const char * name,int num_values)9651abc976SVille Syrjälä struct drm_property *drm_property_create(struct drm_device *dev,
9751abc976SVille Syrjälä 					 u32 flags, const char *name,
9851abc976SVille Syrjälä 					 int num_values)
9959e71ee7SDaniel Vetter {
10059e71ee7SDaniel Vetter 	struct drm_property *property = NULL;
10159e71ee7SDaniel Vetter 	int ret;
10259e71ee7SDaniel Vetter 
103100bc0d9SVille Syrjälä 	if (WARN_ON(!drm_property_flags_valid(flags)))
104100bc0d9SVille Syrjälä 		return NULL;
105100bc0d9SVille Syrjälä 
1065ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
1075ebbb5b4SVille Syrjälä 		return NULL;
1085ebbb5b4SVille Syrjälä 
10959e71ee7SDaniel Vetter 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
11059e71ee7SDaniel Vetter 	if (!property)
11159e71ee7SDaniel Vetter 		return NULL;
11259e71ee7SDaniel Vetter 
11359e71ee7SDaniel Vetter 	property->dev = dev;
11459e71ee7SDaniel Vetter 
11559e71ee7SDaniel Vetter 	if (num_values) {
11659e71ee7SDaniel Vetter 		property->values = kcalloc(num_values, sizeof(uint64_t),
11759e71ee7SDaniel Vetter 					   GFP_KERNEL);
11859e71ee7SDaniel Vetter 		if (!property->values)
11959e71ee7SDaniel Vetter 			goto fail;
12059e71ee7SDaniel Vetter 	}
12159e71ee7SDaniel Vetter 
1222135ea7aSThierry Reding 	ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
12359e71ee7SDaniel Vetter 	if (ret)
12459e71ee7SDaniel Vetter 		goto fail;
12559e71ee7SDaniel Vetter 
12659e71ee7SDaniel Vetter 	property->flags = flags;
12759e71ee7SDaniel Vetter 	property->num_values = num_values;
12859e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&property->enum_list);
12959e71ee7SDaniel Vetter 
130*753f2674SLaurent Pinchart 	strscpy_pad(property->name, name, DRM_PROP_NAME_LEN);
13159e71ee7SDaniel Vetter 
13259e71ee7SDaniel Vetter 	list_add_tail(&property->head, &dev->mode_config.property_list);
13359e71ee7SDaniel Vetter 
13459e71ee7SDaniel Vetter 	return property;
13559e71ee7SDaniel Vetter fail:
13659e71ee7SDaniel Vetter 	kfree(property->values);
13759e71ee7SDaniel Vetter 	kfree(property);
13859e71ee7SDaniel Vetter 	return NULL;
13959e71ee7SDaniel Vetter }
14059e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create);
14159e71ee7SDaniel Vetter 
14259e71ee7SDaniel Vetter /**
14359e71ee7SDaniel Vetter  * drm_property_create_enum - create a new enumeration property type
14459e71ee7SDaniel Vetter  * @dev: drm device
14559e71ee7SDaniel Vetter  * @flags: flags specifying the property type
14659e71ee7SDaniel Vetter  * @name: name of the property
14759e71ee7SDaniel Vetter  * @props: enumeration lists with property values
14859e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
14959e71ee7SDaniel Vetter  *
15059e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
1516a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
1526a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
1536a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
15459e71ee7SDaniel Vetter  *
15559e71ee7SDaniel Vetter  * Userspace is only allowed to set one of the predefined values for enumeration
15659e71ee7SDaniel Vetter  * properties.
15759e71ee7SDaniel Vetter  *
15859e71ee7SDaniel Vetter  * Returns:
15959e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
16059e71ee7SDaniel Vetter  */
drm_property_create_enum(struct drm_device * dev,u32 flags,const char * name,const struct drm_prop_enum_list * props,int num_values)16151abc976SVille Syrjälä struct drm_property *drm_property_create_enum(struct drm_device *dev,
16251abc976SVille Syrjälä 					      u32 flags, const char *name,
16359e71ee7SDaniel Vetter 					      const struct drm_prop_enum_list *props,
16459e71ee7SDaniel Vetter 					      int num_values)
16559e71ee7SDaniel Vetter {
16659e71ee7SDaniel Vetter 	struct drm_property *property;
16759e71ee7SDaniel Vetter 	int i, ret;
16859e71ee7SDaniel Vetter 
16959e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_ENUM;
17059e71ee7SDaniel Vetter 
17159e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
17259e71ee7SDaniel Vetter 	if (!property)
17359e71ee7SDaniel Vetter 		return NULL;
17459e71ee7SDaniel Vetter 
17559e71ee7SDaniel Vetter 	for (i = 0; i < num_values; i++) {
17630e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
17759e71ee7SDaniel Vetter 					    props[i].type,
17859e71ee7SDaniel Vetter 					    props[i].name);
17959e71ee7SDaniel Vetter 		if (ret) {
18059e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
18159e71ee7SDaniel Vetter 			return NULL;
18259e71ee7SDaniel Vetter 		}
18359e71ee7SDaniel Vetter 	}
18459e71ee7SDaniel Vetter 
18559e71ee7SDaniel Vetter 	return property;
18659e71ee7SDaniel Vetter }
18759e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_enum);
18859e71ee7SDaniel Vetter 
18959e71ee7SDaniel Vetter /**
19059e71ee7SDaniel Vetter  * drm_property_create_bitmask - create a new bitmask property type
19159e71ee7SDaniel Vetter  * @dev: drm device
19259e71ee7SDaniel Vetter  * @flags: flags specifying the property type
19359e71ee7SDaniel Vetter  * @name: name of the property
19459e71ee7SDaniel Vetter  * @props: enumeration lists with property bitflags
19559e71ee7SDaniel Vetter  * @num_props: size of the @props array
19659e71ee7SDaniel Vetter  * @supported_bits: bitmask of all supported enumeration values
19759e71ee7SDaniel Vetter  *
19859e71ee7SDaniel Vetter  * This creates a new bitmask drm property which can then be attached to a drm
1996a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2006a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2016a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
20259e71ee7SDaniel Vetter  *
20359e71ee7SDaniel Vetter  * Compared to plain enumeration properties userspace is allowed to set any
20459e71ee7SDaniel Vetter  * or'ed together combination of the predefined property bitflag values
20559e71ee7SDaniel Vetter  *
20659e71ee7SDaniel Vetter  * Returns:
20759e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
20859e71ee7SDaniel Vetter  */
drm_property_create_bitmask(struct drm_device * dev,u32 flags,const char * name,const struct drm_prop_enum_list * props,int num_props,uint64_t supported_bits)20959e71ee7SDaniel Vetter struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
21051abc976SVille Syrjälä 						 u32 flags, const char *name,
21159e71ee7SDaniel Vetter 						 const struct drm_prop_enum_list *props,
21259e71ee7SDaniel Vetter 						 int num_props,
21359e71ee7SDaniel Vetter 						 uint64_t supported_bits)
21459e71ee7SDaniel Vetter {
21559e71ee7SDaniel Vetter 	struct drm_property *property;
21630e9db6dSVille Syrjälä 	int i, ret;
21759e71ee7SDaniel Vetter 	int num_values = hweight64(supported_bits);
21859e71ee7SDaniel Vetter 
21959e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_BITMASK;
22059e71ee7SDaniel Vetter 
22159e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
22259e71ee7SDaniel Vetter 	if (!property)
22359e71ee7SDaniel Vetter 		return NULL;
22459e71ee7SDaniel Vetter 	for (i = 0; i < num_props; i++) {
22559e71ee7SDaniel Vetter 		if (!(supported_bits & (1ULL << props[i].type)))
22659e71ee7SDaniel Vetter 			continue;
22759e71ee7SDaniel Vetter 
22830e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
22959e71ee7SDaniel Vetter 					    props[i].type,
23059e71ee7SDaniel Vetter 					    props[i].name);
23159e71ee7SDaniel Vetter 		if (ret) {
23259e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
23359e71ee7SDaniel Vetter 			return NULL;
23459e71ee7SDaniel Vetter 		}
23559e71ee7SDaniel Vetter 	}
23659e71ee7SDaniel Vetter 
23759e71ee7SDaniel Vetter 	return property;
23859e71ee7SDaniel Vetter }
23959e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bitmask);
24059e71ee7SDaniel Vetter 
property_create_range(struct drm_device * dev,u32 flags,const char * name,uint64_t min,uint64_t max)24159e71ee7SDaniel Vetter static struct drm_property *property_create_range(struct drm_device *dev,
24251abc976SVille Syrjälä 						  u32 flags, const char *name,
24359e71ee7SDaniel Vetter 						  uint64_t min, uint64_t max)
24459e71ee7SDaniel Vetter {
24559e71ee7SDaniel Vetter 	struct drm_property *property;
24659e71ee7SDaniel Vetter 
24759e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 2);
24859e71ee7SDaniel Vetter 	if (!property)
24959e71ee7SDaniel Vetter 		return NULL;
25059e71ee7SDaniel Vetter 
25159e71ee7SDaniel Vetter 	property->values[0] = min;
25259e71ee7SDaniel Vetter 	property->values[1] = max;
25359e71ee7SDaniel Vetter 
25459e71ee7SDaniel Vetter 	return property;
25559e71ee7SDaniel Vetter }
25659e71ee7SDaniel Vetter 
25759e71ee7SDaniel Vetter /**
25859e71ee7SDaniel Vetter  * drm_property_create_range - create a new unsigned ranged property type
25959e71ee7SDaniel Vetter  * @dev: drm device
26059e71ee7SDaniel Vetter  * @flags: flags specifying the property type
26159e71ee7SDaniel Vetter  * @name: name of the property
26259e71ee7SDaniel Vetter  * @min: minimum value of the property
26359e71ee7SDaniel Vetter  * @max: maximum value of the property
26459e71ee7SDaniel Vetter  *
26559e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2666a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2676a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2686a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
26959e71ee7SDaniel Vetter  *
27059e71ee7SDaniel Vetter  * Userspace is allowed to set any unsigned integer value in the (min, max)
27159e71ee7SDaniel Vetter  * range inclusive.
27259e71ee7SDaniel Vetter  *
27359e71ee7SDaniel Vetter  * Returns:
27459e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
27559e71ee7SDaniel Vetter  */
drm_property_create_range(struct drm_device * dev,u32 flags,const char * name,uint64_t min,uint64_t max)27651abc976SVille Syrjälä struct drm_property *drm_property_create_range(struct drm_device *dev,
27751abc976SVille Syrjälä 					       u32 flags, const char *name,
27859e71ee7SDaniel Vetter 					       uint64_t min, uint64_t max)
27959e71ee7SDaniel Vetter {
28059e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
28159e71ee7SDaniel Vetter 			name, min, max);
28259e71ee7SDaniel Vetter }
28359e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_range);
28459e71ee7SDaniel Vetter 
28559e71ee7SDaniel Vetter /**
28659e71ee7SDaniel Vetter  * drm_property_create_signed_range - create a new signed ranged property type
28759e71ee7SDaniel Vetter  * @dev: drm device
28859e71ee7SDaniel Vetter  * @flags: flags specifying the property type
28959e71ee7SDaniel Vetter  * @name: name of the property
29059e71ee7SDaniel Vetter  * @min: minimum value of the property
29159e71ee7SDaniel Vetter  * @max: maximum value of the property
29259e71ee7SDaniel Vetter  *
29359e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2946a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2956a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2966a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
29759e71ee7SDaniel Vetter  *
29859e71ee7SDaniel Vetter  * Userspace is allowed to set any signed integer value in the (min, max)
29959e71ee7SDaniel Vetter  * range inclusive.
30059e71ee7SDaniel Vetter  *
30159e71ee7SDaniel Vetter  * Returns:
30259e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
30359e71ee7SDaniel Vetter  */
drm_property_create_signed_range(struct drm_device * dev,u32 flags,const char * name,int64_t min,int64_t max)30459e71ee7SDaniel Vetter struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
30551abc976SVille Syrjälä 						      u32 flags, const char *name,
30659e71ee7SDaniel Vetter 						      int64_t min, int64_t max)
30759e71ee7SDaniel Vetter {
30859e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
30959e71ee7SDaniel Vetter 			name, I642U64(min), I642U64(max));
31059e71ee7SDaniel Vetter }
31159e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_signed_range);
31259e71ee7SDaniel Vetter 
31359e71ee7SDaniel Vetter /**
31459e71ee7SDaniel Vetter  * drm_property_create_object - create a new object property type
31559e71ee7SDaniel Vetter  * @dev: drm device
31659e71ee7SDaniel Vetter  * @flags: flags specifying the property type
31759e71ee7SDaniel Vetter  * @name: name of the property
31859e71ee7SDaniel Vetter  * @type: object type from DRM_MODE_OBJECT_* defines
31959e71ee7SDaniel Vetter  *
32059e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3216a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3226a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3236a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
32459e71ee7SDaniel Vetter  *
32559e71ee7SDaniel Vetter  * Userspace is only allowed to set this to any property value of the given
32659e71ee7SDaniel Vetter  * @type. Only useful for atomic properties, which is enforced.
32759e71ee7SDaniel Vetter  *
32859e71ee7SDaniel Vetter  * Returns:
32959e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
33059e71ee7SDaniel Vetter  */
drm_property_create_object(struct drm_device * dev,u32 flags,const char * name,uint32_t type)33159e71ee7SDaniel Vetter struct drm_property *drm_property_create_object(struct drm_device *dev,
33251abc976SVille Syrjälä 						u32 flags, const char *name,
333c8458c7eSDaniel Vetter 						uint32_t type)
33459e71ee7SDaniel Vetter {
33559e71ee7SDaniel Vetter 	struct drm_property *property;
33659e71ee7SDaniel Vetter 
33759e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_OBJECT;
33859e71ee7SDaniel Vetter 
33959e71ee7SDaniel Vetter 	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
34059e71ee7SDaniel Vetter 		return NULL;
34159e71ee7SDaniel Vetter 
34259e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 1);
34359e71ee7SDaniel Vetter 	if (!property)
34459e71ee7SDaniel Vetter 		return NULL;
34559e71ee7SDaniel Vetter 
34659e71ee7SDaniel Vetter 	property->values[0] = type;
34759e71ee7SDaniel Vetter 
34859e71ee7SDaniel Vetter 	return property;
34959e71ee7SDaniel Vetter }
35059e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_object);
35159e71ee7SDaniel Vetter 
35259e71ee7SDaniel Vetter /**
35359e71ee7SDaniel Vetter  * drm_property_create_bool - create a new boolean property type
35459e71ee7SDaniel Vetter  * @dev: drm device
35559e71ee7SDaniel Vetter  * @flags: flags specifying the property type
35659e71ee7SDaniel Vetter  * @name: name of the property
35759e71ee7SDaniel Vetter  *
35859e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3596a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3606a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3616a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
36259e71ee7SDaniel Vetter  *
36359e71ee7SDaniel Vetter  * This is implemented as a ranged property with only {0, 1} as valid values.
36459e71ee7SDaniel Vetter  *
36559e71ee7SDaniel Vetter  * Returns:
36659e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
36759e71ee7SDaniel Vetter  */
drm_property_create_bool(struct drm_device * dev,u32 flags,const char * name)36851abc976SVille Syrjälä struct drm_property *drm_property_create_bool(struct drm_device *dev,
36951abc976SVille Syrjälä 					      u32 flags, const char *name)
37059e71ee7SDaniel Vetter {
37159e71ee7SDaniel Vetter 	return drm_property_create_range(dev, flags, name, 0, 1);
37259e71ee7SDaniel Vetter }
37359e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool);
37459e71ee7SDaniel Vetter 
37559e71ee7SDaniel Vetter /**
37659e71ee7SDaniel Vetter  * drm_property_add_enum - add a possible value to an enumeration property
37759e71ee7SDaniel Vetter  * @property: enumeration property to change
37859e71ee7SDaniel Vetter  * @value: value of the new enumeration
37959e71ee7SDaniel Vetter  * @name: symbolic name of the new enumeration
38059e71ee7SDaniel Vetter  *
38159e71ee7SDaniel Vetter  * This functions adds enumerations to a property.
38259e71ee7SDaniel Vetter  *
38359e71ee7SDaniel Vetter  * It's use is deprecated, drivers should use one of the more specific helpers
38459e71ee7SDaniel Vetter  * to directly create the property with all enumerations already attached.
38559e71ee7SDaniel Vetter  *
38659e71ee7SDaniel Vetter  * Returns:
38759e71ee7SDaniel Vetter  * Zero on success, error code on failure.
38859e71ee7SDaniel Vetter  */
drm_property_add_enum(struct drm_property * property,uint64_t value,const char * name)38930e9db6dSVille Syrjälä int drm_property_add_enum(struct drm_property *property,
39059e71ee7SDaniel Vetter 			  uint64_t value, const char *name)
39159e71ee7SDaniel Vetter {
39259e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
39330e9db6dSVille Syrjälä 	int index = 0;
39459e71ee7SDaniel Vetter 
3955ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
3965ebbb5b4SVille Syrjälä 		return -EINVAL;
3975ebbb5b4SVille Syrjälä 
3981371f260SVille Syrjälä 	if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
3991371f260SVille Syrjälä 		    !drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
40059e71ee7SDaniel Vetter 		return -EINVAL;
40159e71ee7SDaniel Vetter 
40259e71ee7SDaniel Vetter 	/*
40359e71ee7SDaniel Vetter 	 * Bitmask enum properties have the additional constraint of values
40459e71ee7SDaniel Vetter 	 * from 0 to 63
40559e71ee7SDaniel Vetter 	 */
4068c6c2fe2SVille Syrjälä 	if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
4078c6c2fe2SVille Syrjälä 		    value > 63))
40859e71ee7SDaniel Vetter 		return -EINVAL;
40959e71ee7SDaniel Vetter 
41059e71ee7SDaniel Vetter 	list_for_each_entry(prop_enum, &property->enum_list, head) {
4116f881d04SVille Syrjälä 		if (WARN_ON(prop_enum->value == value))
4126f881d04SVille Syrjälä 			return -EINVAL;
41330e9db6dSVille Syrjälä 		index++;
41459e71ee7SDaniel Vetter 	}
41559e71ee7SDaniel Vetter 
41630e9db6dSVille Syrjälä 	if (WARN_ON(index >= property->num_values))
41730e9db6dSVille Syrjälä 		return -EINVAL;
41830e9db6dSVille Syrjälä 
41959e71ee7SDaniel Vetter 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
42059e71ee7SDaniel Vetter 	if (!prop_enum)
42159e71ee7SDaniel Vetter 		return -ENOMEM;
42259e71ee7SDaniel Vetter 
423*753f2674SLaurent Pinchart 	strscpy_pad(prop_enum->name, name, DRM_PROP_NAME_LEN);
42459e71ee7SDaniel Vetter 	prop_enum->value = value;
42559e71ee7SDaniel Vetter 
42659e71ee7SDaniel Vetter 	property->values[index] = value;
42759e71ee7SDaniel Vetter 	list_add_tail(&prop_enum->head, &property->enum_list);
42859e71ee7SDaniel Vetter 	return 0;
42959e71ee7SDaniel Vetter }
43059e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_add_enum);
43159e71ee7SDaniel Vetter 
43259e71ee7SDaniel Vetter /**
43359e71ee7SDaniel Vetter  * drm_property_destroy - destroy a drm property
43459e71ee7SDaniel Vetter  * @dev: drm device
4350ae865efSCai Huoqing  * @property: property to destroy
43659e71ee7SDaniel Vetter  *
43759e71ee7SDaniel Vetter  * This function frees a property including any attached resources like
43859e71ee7SDaniel Vetter  * enumeration values.
43959e71ee7SDaniel Vetter  */
drm_property_destroy(struct drm_device * dev,struct drm_property * property)44059e71ee7SDaniel Vetter void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
44159e71ee7SDaniel Vetter {
44259e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum, *pt;
44359e71ee7SDaniel Vetter 
44459e71ee7SDaniel Vetter 	list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
44559e71ee7SDaniel Vetter 		list_del(&prop_enum->head);
44659e71ee7SDaniel Vetter 		kfree(prop_enum);
44759e71ee7SDaniel Vetter 	}
44859e71ee7SDaniel Vetter 
44959e71ee7SDaniel Vetter 	if (property->num_values)
45059e71ee7SDaniel Vetter 		kfree(property->values);
45159e71ee7SDaniel Vetter 	drm_mode_object_unregister(dev, &property->base);
45259e71ee7SDaniel Vetter 	list_del(&property->head);
45359e71ee7SDaniel Vetter 	kfree(property);
45459e71ee7SDaniel Vetter }
45559e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_destroy);
45659e71ee7SDaniel Vetter 
drm_mode_getproperty_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)45759e71ee7SDaniel Vetter int drm_mode_getproperty_ioctl(struct drm_device *dev,
45859e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
45959e71ee7SDaniel Vetter {
46059e71ee7SDaniel Vetter 	struct drm_mode_get_property *out_resp = data;
46159e71ee7SDaniel Vetter 	struct drm_property *property;
46259e71ee7SDaniel Vetter 	int enum_count = 0;
46359e71ee7SDaniel Vetter 	int value_count = 0;
464eb8eb02eSDaniel Vetter 	int i, copied;
46559e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
46659e71ee7SDaniel Vetter 	struct drm_mode_property_enum __user *enum_ptr;
46759e71ee7SDaniel Vetter 	uint64_t __user *values_ptr;
46859e71ee7SDaniel Vetter 
46959e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
47069fdf420SChris Wilson 		return -EOPNOTSUPP;
47159e71ee7SDaniel Vetter 
472418da172SKeith Packard 	property = drm_property_find(dev, file_priv, out_resp->prop_id);
473eb8eb02eSDaniel Vetter 	if (!property)
474eb8eb02eSDaniel Vetter 		return -ENOENT;
47559e71ee7SDaniel Vetter 
476*753f2674SLaurent Pinchart 	strscpy_pad(out_resp->name, property->name, DRM_PROP_NAME_LEN);
47759e71ee7SDaniel Vetter 	out_resp->flags = property->flags;
47859e71ee7SDaniel Vetter 
479eb8eb02eSDaniel Vetter 	value_count = property->num_values;
480eb8eb02eSDaniel Vetter 	values_ptr = u64_to_user_ptr(out_resp->values_ptr);
481eb8eb02eSDaniel Vetter 
48259e71ee7SDaniel Vetter 	for (i = 0; i < value_count; i++) {
483eb8eb02eSDaniel Vetter 		if (i < out_resp->count_values &&
484eb8eb02eSDaniel Vetter 		    put_user(property->values[i], values_ptr + i)) {
485eb8eb02eSDaniel Vetter 			return -EFAULT;
48659e71ee7SDaniel Vetter 		}
48759e71ee7SDaniel Vetter 	}
48859e71ee7SDaniel Vetter 	out_resp->count_values = value_count;
48959e71ee7SDaniel Vetter 
490eb8eb02eSDaniel Vetter 	copied = 0;
491eb8eb02eSDaniel Vetter 	enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
492eb8eb02eSDaniel Vetter 
49359e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
49459e71ee7SDaniel Vetter 	    drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
49559e71ee7SDaniel Vetter 		list_for_each_entry(prop_enum, &property->enum_list, head) {
496eb8eb02eSDaniel Vetter 			enum_count++;
4978cb68c83SDaniel Vetter 			if (out_resp->count_enum_blobs < enum_count)
498eb8eb02eSDaniel Vetter 				continue;
49959e71ee7SDaniel Vetter 
500eb8eb02eSDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].value,
501eb8eb02eSDaniel Vetter 					 &prop_enum->value, sizeof(uint64_t)))
502eb8eb02eSDaniel Vetter 				return -EFAULT;
50359e71ee7SDaniel Vetter 
50459e71ee7SDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].name,
505eb8eb02eSDaniel Vetter 					 &prop_enum->name, DRM_PROP_NAME_LEN))
506eb8eb02eSDaniel Vetter 				return -EFAULT;
50759e71ee7SDaniel Vetter 			copied++;
50859e71ee7SDaniel Vetter 		}
50959e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = enum_count;
51059e71ee7SDaniel Vetter 	}
51159e71ee7SDaniel Vetter 
51259e71ee7SDaniel Vetter 	/*
51359e71ee7SDaniel Vetter 	 * NOTE: The idea seems to have been to use this to read all the blob
51459e71ee7SDaniel Vetter 	 * property values. But nothing ever added them to the corresponding
51559e71ee7SDaniel Vetter 	 * list, userspace always used the special-purpose get_blob ioctl to
51659e71ee7SDaniel Vetter 	 * read the value for a blob property. It also doesn't make a lot of
51759e71ee7SDaniel Vetter 	 * sense to return values here when everything else is just metadata for
51859e71ee7SDaniel Vetter 	 * the property itself.
51959e71ee7SDaniel Vetter 	 */
52059e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
52159e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = 0;
522eb8eb02eSDaniel Vetter 
523eb8eb02eSDaniel Vetter 	return 0;
52459e71ee7SDaniel Vetter }
52559e71ee7SDaniel Vetter 
drm_property_free_blob(struct kref * kref)52659e71ee7SDaniel Vetter static void drm_property_free_blob(struct kref *kref)
52759e71ee7SDaniel Vetter {
52859e71ee7SDaniel Vetter 	struct drm_property_blob *blob =
52959e71ee7SDaniel Vetter 		container_of(kref, struct drm_property_blob, base.refcount);
53059e71ee7SDaniel Vetter 
53159e71ee7SDaniel Vetter 	mutex_lock(&blob->dev->mode_config.blob_lock);
53259e71ee7SDaniel Vetter 	list_del(&blob->head_global);
53359e71ee7SDaniel Vetter 	mutex_unlock(&blob->dev->mode_config.blob_lock);
53459e71ee7SDaniel Vetter 
53559e71ee7SDaniel Vetter 	drm_mode_object_unregister(blob->dev, &blob->base);
53659e71ee7SDaniel Vetter 
537718b5406SMichel Dänzer 	kvfree(blob);
53859e71ee7SDaniel Vetter }
53959e71ee7SDaniel Vetter 
54059e71ee7SDaniel Vetter /**
54159e71ee7SDaniel Vetter  * drm_property_create_blob - Create new blob property
54259e71ee7SDaniel Vetter  * @dev: DRM device to create property for
54359e71ee7SDaniel Vetter  * @length: Length to allocate for blob data
54459e71ee7SDaniel Vetter  * @data: If specified, copies data into blob
54559e71ee7SDaniel Vetter  *
546c8458c7eSDaniel Vetter  * Creates a new blob property for a specified DRM device, optionally
547c8458c7eSDaniel Vetter  * copying data. Note that blob properties are meant to be invariant, hence the
548c8458c7eSDaniel Vetter  * data must be filled out before the blob is used as the value of any property.
549c8458c7eSDaniel Vetter  *
55059e71ee7SDaniel Vetter  * Returns:
55159e71ee7SDaniel Vetter  * New blob property with a single reference on success, or an ERR_PTR
55259e71ee7SDaniel Vetter  * value on failure.
55359e71ee7SDaniel Vetter  */
55459e71ee7SDaniel Vetter struct drm_property_blob *
drm_property_create_blob(struct drm_device * dev,size_t length,const void * data)55559e71ee7SDaniel Vetter drm_property_create_blob(struct drm_device *dev, size_t length,
55659e71ee7SDaniel Vetter 			 const void *data)
55759e71ee7SDaniel Vetter {
55859e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
55959e71ee7SDaniel Vetter 	int ret;
56059e71ee7SDaniel Vetter 
5615bf8bec3SDaniel Vetter 	if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
56259e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
56359e71ee7SDaniel Vetter 
564718b5406SMichel Dänzer 	blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
56559e71ee7SDaniel Vetter 	if (!blob)
56659e71ee7SDaniel Vetter 		return ERR_PTR(-ENOMEM);
56759e71ee7SDaniel Vetter 
56859e71ee7SDaniel Vetter 	/* This must be explicitly initialised, so we can safely call list_del
56959e71ee7SDaniel Vetter 	 * on it in the removal handler, even if it isn't in a file list. */
57059e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&blob->head_file);
5719c60583cSVille Syrjälä 	blob->data = (void *)blob + sizeof(*blob);
57259e71ee7SDaniel Vetter 	blob->length = length;
57359e71ee7SDaniel Vetter 	blob->dev = dev;
57459e71ee7SDaniel Vetter 
57559e71ee7SDaniel Vetter 	if (data)
57659e71ee7SDaniel Vetter 		memcpy(blob->data, data, length);
57759e71ee7SDaniel Vetter 
5782135ea7aSThierry Reding 	ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
57959e71ee7SDaniel Vetter 				    true, drm_property_free_blob);
58059e71ee7SDaniel Vetter 	if (ret) {
581718b5406SMichel Dänzer 		kvfree(blob);
58259e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
58359e71ee7SDaniel Vetter 	}
58459e71ee7SDaniel Vetter 
58559e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
58659e71ee7SDaniel Vetter 	list_add_tail(&blob->head_global,
58759e71ee7SDaniel Vetter 	              &dev->mode_config.property_blob_list);
58859e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
58959e71ee7SDaniel Vetter 
59059e71ee7SDaniel Vetter 	return blob;
59159e71ee7SDaniel Vetter }
59259e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_blob);
59359e71ee7SDaniel Vetter 
59459e71ee7SDaniel Vetter /**
5956472e509SThierry Reding  * drm_property_blob_put - release a blob property reference
5966472e509SThierry Reding  * @blob: DRM blob property
59759e71ee7SDaniel Vetter  *
5986472e509SThierry Reding  * Releases a reference to a blob property. May free the object.
59959e71ee7SDaniel Vetter  */
drm_property_blob_put(struct drm_property_blob * blob)6006472e509SThierry Reding void drm_property_blob_put(struct drm_property_blob *blob)
60159e71ee7SDaniel Vetter {
60259e71ee7SDaniel Vetter 	if (!blob)
60359e71ee7SDaniel Vetter 		return;
60459e71ee7SDaniel Vetter 
605020a218fSThierry Reding 	drm_mode_object_put(&blob->base);
60659e71ee7SDaniel Vetter }
6076472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_put);
60859e71ee7SDaniel Vetter 
drm_property_destroy_user_blobs(struct drm_device * dev,struct drm_file * file_priv)60959e71ee7SDaniel Vetter void drm_property_destroy_user_blobs(struct drm_device *dev,
61059e71ee7SDaniel Vetter 				     struct drm_file *file_priv)
61159e71ee7SDaniel Vetter {
61259e71ee7SDaniel Vetter 	struct drm_property_blob *blob, *bt;
61359e71ee7SDaniel Vetter 
61459e71ee7SDaniel Vetter 	/*
61559e71ee7SDaniel Vetter 	 * When the file gets released that means no one else can access the
61659e71ee7SDaniel Vetter 	 * blob list any more, so no need to grab dev->blob_lock.
61759e71ee7SDaniel Vetter 	 */
61859e71ee7SDaniel Vetter 	list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
61959e71ee7SDaniel Vetter 		list_del_init(&blob->head_file);
6206472e509SThierry Reding 		drm_property_blob_put(blob);
62159e71ee7SDaniel Vetter 	}
62259e71ee7SDaniel Vetter }
62359e71ee7SDaniel Vetter 
62459e71ee7SDaniel Vetter /**
6256472e509SThierry Reding  * drm_property_blob_get - acquire blob property reference
6266472e509SThierry Reding  * @blob: DRM blob property
627c8458c7eSDaniel Vetter  *
6286472e509SThierry Reding  * Acquires a reference to an existing blob property. Returns @blob, which
629c8458c7eSDaniel Vetter  * allows this to be used as a shorthand in assignments.
63059e71ee7SDaniel Vetter  */
drm_property_blob_get(struct drm_property_blob * blob)6316472e509SThierry Reding struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
63259e71ee7SDaniel Vetter {
633020a218fSThierry Reding 	drm_mode_object_get(&blob->base);
63459e71ee7SDaniel Vetter 	return blob;
63559e71ee7SDaniel Vetter }
6366472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_get);
63759e71ee7SDaniel Vetter 
63859e71ee7SDaniel Vetter /**
63959e71ee7SDaniel Vetter  * drm_property_lookup_blob - look up a blob property and take a reference
64059e71ee7SDaniel Vetter  * @dev: drm device
64159e71ee7SDaniel Vetter  * @id: id of the blob property
64259e71ee7SDaniel Vetter  *
64359e71ee7SDaniel Vetter  * If successful, this takes an additional reference to the blob property.
6444cf1d871SBhaskar Chowdhury  * callers need to make sure to eventually unreferenced the returned property
6456472e509SThierry Reding  * again, using drm_property_blob_put().
646c8458c7eSDaniel Vetter  *
647c8458c7eSDaniel Vetter  * Return:
648c8458c7eSDaniel Vetter  * NULL on failure, pointer to the blob on success.
64959e71ee7SDaniel Vetter  */
drm_property_lookup_blob(struct drm_device * dev,uint32_t id)65059e71ee7SDaniel Vetter struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
65159e71ee7SDaniel Vetter 					           uint32_t id)
65259e71ee7SDaniel Vetter {
65359e71ee7SDaniel Vetter 	struct drm_mode_object *obj;
65459e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL;
65559e71ee7SDaniel Vetter 
656418da172SKeith Packard 	obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
65759e71ee7SDaniel Vetter 	if (obj)
65859e71ee7SDaniel Vetter 		blob = obj_to_blob(obj);
65959e71ee7SDaniel Vetter 	return blob;
66059e71ee7SDaniel Vetter }
66159e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_lookup_blob);
66259e71ee7SDaniel Vetter 
66359e71ee7SDaniel Vetter /**
664c8458c7eSDaniel Vetter  * drm_property_replace_global_blob - replace existing blob property
66559e71ee7SDaniel Vetter  * @dev: drm device
66659e71ee7SDaniel Vetter  * @replace: location of blob property pointer to be replaced
66759e71ee7SDaniel Vetter  * @length: length of data for new blob, or 0 for no data
66859e71ee7SDaniel Vetter  * @data: content for new blob, or NULL for no data
66959e71ee7SDaniel Vetter  * @obj_holds_id: optional object for property holding blob ID
67059e71ee7SDaniel Vetter  * @prop_holds_id: optional property holding blob ID
67159e71ee7SDaniel Vetter  * @return 0 on success or error on failure
67259e71ee7SDaniel Vetter  *
673c8458c7eSDaniel Vetter  * This function will replace a global property in the blob list, optionally
674c8458c7eSDaniel Vetter  * updating a property which holds the ID of that property.
67559e71ee7SDaniel Vetter  *
67659e71ee7SDaniel Vetter  * If length is 0 or data is NULL, no new blob will be created, and the holding
67759e71ee7SDaniel Vetter  * property, if specified, will be set to 0.
67859e71ee7SDaniel Vetter  *
67959e71ee7SDaniel Vetter  * Access to the replace pointer is assumed to be protected by the caller, e.g.
68059e71ee7SDaniel Vetter  * by holding the relevant modesetting object lock for its parent.
68159e71ee7SDaniel Vetter  *
68259e71ee7SDaniel Vetter  * For example, a drm_connector has a 'PATH' property, which contains the ID
68359e71ee7SDaniel Vetter  * of a blob property with the value of the MST path information. Calling this
68459e71ee7SDaniel Vetter  * function with replace pointing to the connector's path_blob_ptr, length and
68559e71ee7SDaniel Vetter  * data set for the new path information, obj_holds_id set to the connector's
68659e71ee7SDaniel Vetter  * base object, and prop_holds_id set to the path property name, will perform
68759e71ee7SDaniel Vetter  * a completely atomic update. The access to path_blob_ptr is protected by the
68859e71ee7SDaniel Vetter  * caller holding a lock on the connector.
68959e71ee7SDaniel Vetter  */
drm_property_replace_global_blob(struct drm_device * dev,struct drm_property_blob ** replace,size_t length,const void * data,struct drm_mode_object * obj_holds_id,struct drm_property * prop_holds_id)69059e71ee7SDaniel Vetter int drm_property_replace_global_blob(struct drm_device *dev,
69159e71ee7SDaniel Vetter 				     struct drm_property_blob **replace,
69259e71ee7SDaniel Vetter 				     size_t length,
69359e71ee7SDaniel Vetter 				     const void *data,
69459e71ee7SDaniel Vetter 				     struct drm_mode_object *obj_holds_id,
69559e71ee7SDaniel Vetter 				     struct drm_property *prop_holds_id)
69659e71ee7SDaniel Vetter {
69759e71ee7SDaniel Vetter 	struct drm_property_blob *new_blob = NULL;
69859e71ee7SDaniel Vetter 	struct drm_property_blob *old_blob = NULL;
69959e71ee7SDaniel Vetter 	int ret;
70059e71ee7SDaniel Vetter 
70159e71ee7SDaniel Vetter 	WARN_ON(replace == NULL);
70259e71ee7SDaniel Vetter 
70359e71ee7SDaniel Vetter 	old_blob = *replace;
70459e71ee7SDaniel Vetter 
70559e71ee7SDaniel Vetter 	if (length && data) {
70659e71ee7SDaniel Vetter 		new_blob = drm_property_create_blob(dev, length, data);
70759e71ee7SDaniel Vetter 		if (IS_ERR(new_blob))
70859e71ee7SDaniel Vetter 			return PTR_ERR(new_blob);
70959e71ee7SDaniel Vetter 	}
71059e71ee7SDaniel Vetter 
71159e71ee7SDaniel Vetter 	if (obj_holds_id) {
71259e71ee7SDaniel Vetter 		ret = drm_object_property_set_value(obj_holds_id,
71359e71ee7SDaniel Vetter 						    prop_holds_id,
71459e71ee7SDaniel Vetter 						    new_blob ?
71559e71ee7SDaniel Vetter 						        new_blob->base.id : 0);
71659e71ee7SDaniel Vetter 		if (ret != 0)
71759e71ee7SDaniel Vetter 			goto err_created;
71859e71ee7SDaniel Vetter 	}
71959e71ee7SDaniel Vetter 
7206472e509SThierry Reding 	drm_property_blob_put(old_blob);
72159e71ee7SDaniel Vetter 	*replace = new_blob;
72259e71ee7SDaniel Vetter 
72359e71ee7SDaniel Vetter 	return 0;
72459e71ee7SDaniel Vetter 
72559e71ee7SDaniel Vetter err_created:
7266472e509SThierry Reding 	drm_property_blob_put(new_blob);
72759e71ee7SDaniel Vetter 	return ret;
72859e71ee7SDaniel Vetter }
72959e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_replace_global_blob);
73059e71ee7SDaniel Vetter 
7315f057ffdSPeter Rosin /**
7325f057ffdSPeter Rosin  * drm_property_replace_blob - replace a blob property
7335f057ffdSPeter Rosin  * @blob: a pointer to the member blob to be replaced
7345f057ffdSPeter Rosin  * @new_blob: the new blob to replace with
7355f057ffdSPeter Rosin  *
7365f057ffdSPeter Rosin  * Return: true if the blob was in fact replaced.
7375f057ffdSPeter Rosin  */
drm_property_replace_blob(struct drm_property_blob ** blob,struct drm_property_blob * new_blob)7385f057ffdSPeter Rosin bool drm_property_replace_blob(struct drm_property_blob **blob,
7395f057ffdSPeter Rosin 			       struct drm_property_blob *new_blob)
7405f057ffdSPeter Rosin {
7415f057ffdSPeter Rosin 	struct drm_property_blob *old_blob = *blob;
7425f057ffdSPeter Rosin 
7435f057ffdSPeter Rosin 	if (old_blob == new_blob)
7445f057ffdSPeter Rosin 		return false;
7455f057ffdSPeter Rosin 
7465f057ffdSPeter Rosin 	drm_property_blob_put(old_blob);
7475f057ffdSPeter Rosin 	if (new_blob)
7485f057ffdSPeter Rosin 		drm_property_blob_get(new_blob);
7495f057ffdSPeter Rosin 	*blob = new_blob;
7505f057ffdSPeter Rosin 	return true;
7515f057ffdSPeter Rosin }
7525f057ffdSPeter Rosin EXPORT_SYMBOL(drm_property_replace_blob);
7535f057ffdSPeter Rosin 
drm_mode_getblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)75459e71ee7SDaniel Vetter int drm_mode_getblob_ioctl(struct drm_device *dev,
75559e71ee7SDaniel Vetter 			   void *data, struct drm_file *file_priv)
75659e71ee7SDaniel Vetter {
75759e71ee7SDaniel Vetter 	struct drm_mode_get_blob *out_resp = data;
75859e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
75959e71ee7SDaniel Vetter 	int ret = 0;
76059e71ee7SDaniel Vetter 
76159e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
76269fdf420SChris Wilson 		return -EOPNOTSUPP;
76359e71ee7SDaniel Vetter 
76459e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
76559e71ee7SDaniel Vetter 	if (!blob)
76659e71ee7SDaniel Vetter 		return -ENOENT;
76759e71ee7SDaniel Vetter 
76859e71ee7SDaniel Vetter 	if (out_resp->length == blob->length) {
76975df6247SChris Wilson 		if (copy_to_user(u64_to_user_ptr(out_resp->data),
77075df6247SChris Wilson 				 blob->data,
77175df6247SChris Wilson 				 blob->length)) {
77259e71ee7SDaniel Vetter 			ret = -EFAULT;
77359e71ee7SDaniel Vetter 			goto unref;
77459e71ee7SDaniel Vetter 		}
77559e71ee7SDaniel Vetter 	}
77659e71ee7SDaniel Vetter 	out_resp->length = blob->length;
77759e71ee7SDaniel Vetter unref:
7786472e509SThierry Reding 	drm_property_blob_put(blob);
77959e71ee7SDaniel Vetter 
78059e71ee7SDaniel Vetter 	return ret;
78159e71ee7SDaniel Vetter }
78259e71ee7SDaniel Vetter 
drm_mode_createblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)78359e71ee7SDaniel Vetter int drm_mode_createblob_ioctl(struct drm_device *dev,
78459e71ee7SDaniel Vetter 			      void *data, struct drm_file *file_priv)
78559e71ee7SDaniel Vetter {
78659e71ee7SDaniel Vetter 	struct drm_mode_create_blob *out_resp = data;
78759e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
78859e71ee7SDaniel Vetter 	int ret = 0;
78959e71ee7SDaniel Vetter 
79059e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
79169fdf420SChris Wilson 		return -EOPNOTSUPP;
79259e71ee7SDaniel Vetter 
79359e71ee7SDaniel Vetter 	blob = drm_property_create_blob(dev, out_resp->length, NULL);
79459e71ee7SDaniel Vetter 	if (IS_ERR(blob))
79559e71ee7SDaniel Vetter 		return PTR_ERR(blob);
79659e71ee7SDaniel Vetter 
79775df6247SChris Wilson 	if (copy_from_user(blob->data,
79875df6247SChris Wilson 			   u64_to_user_ptr(out_resp->data),
79975df6247SChris Wilson 			   out_resp->length)) {
80059e71ee7SDaniel Vetter 		ret = -EFAULT;
80159e71ee7SDaniel Vetter 		goto out_blob;
80259e71ee7SDaniel Vetter 	}
80359e71ee7SDaniel Vetter 
80459e71ee7SDaniel Vetter 	/* Dropping the lock between create_blob and our access here is safe
80559e71ee7SDaniel Vetter 	 * as only the same file_priv can remove the blob; at this point, it is
80659e71ee7SDaniel Vetter 	 * not associated with any file_priv. */
80759e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
80859e71ee7SDaniel Vetter 	out_resp->blob_id = blob->base.id;
80959e71ee7SDaniel Vetter 	list_add_tail(&blob->head_file, &file_priv->blobs);
81059e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
81159e71ee7SDaniel Vetter 
81259e71ee7SDaniel Vetter 	return 0;
81359e71ee7SDaniel Vetter 
81459e71ee7SDaniel Vetter out_blob:
8156472e509SThierry Reding 	drm_property_blob_put(blob);
81659e71ee7SDaniel Vetter 	return ret;
81759e71ee7SDaniel Vetter }
81859e71ee7SDaniel Vetter 
drm_mode_destroyblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)81959e71ee7SDaniel Vetter int drm_mode_destroyblob_ioctl(struct drm_device *dev,
82059e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
82159e71ee7SDaniel Vetter {
82259e71ee7SDaniel Vetter 	struct drm_mode_destroy_blob *out_resp = data;
82359e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL, *bt;
82459e71ee7SDaniel Vetter 	bool found = false;
82559e71ee7SDaniel Vetter 	int ret = 0;
82659e71ee7SDaniel Vetter 
82759e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
82869fdf420SChris Wilson 		return -EOPNOTSUPP;
82959e71ee7SDaniel Vetter 
83059e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
83159e71ee7SDaniel Vetter 	if (!blob)
83259e71ee7SDaniel Vetter 		return -ENOENT;
83359e71ee7SDaniel Vetter 
83459e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
83559e71ee7SDaniel Vetter 	/* Ensure the property was actually created by this user. */
83659e71ee7SDaniel Vetter 	list_for_each_entry(bt, &file_priv->blobs, head_file) {
83759e71ee7SDaniel Vetter 		if (bt == blob) {
83859e71ee7SDaniel Vetter 			found = true;
83959e71ee7SDaniel Vetter 			break;
84059e71ee7SDaniel Vetter 		}
84159e71ee7SDaniel Vetter 	}
84259e71ee7SDaniel Vetter 
84359e71ee7SDaniel Vetter 	if (!found) {
84459e71ee7SDaniel Vetter 		ret = -EPERM;
84559e71ee7SDaniel Vetter 		goto err;
84659e71ee7SDaniel Vetter 	}
84759e71ee7SDaniel Vetter 
84859e71ee7SDaniel Vetter 	/* We must drop head_file here, because we may not be the last
84959e71ee7SDaniel Vetter 	 * reference on the blob. */
85059e71ee7SDaniel Vetter 	list_del_init(&blob->head_file);
85159e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
85259e71ee7SDaniel Vetter 
85359e71ee7SDaniel Vetter 	/* One reference from lookup, and one from the filp. */
8546472e509SThierry Reding 	drm_property_blob_put(blob);
8556472e509SThierry Reding 	drm_property_blob_put(blob);
85659e71ee7SDaniel Vetter 
85759e71ee7SDaniel Vetter 	return 0;
85859e71ee7SDaniel Vetter 
85959e71ee7SDaniel Vetter err:
86059e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
8616472e509SThierry Reding 	drm_property_blob_put(blob);
86259e71ee7SDaniel Vetter 
86359e71ee7SDaniel Vetter 	return ret;
86459e71ee7SDaniel Vetter }
86559e71ee7SDaniel Vetter 
86659e71ee7SDaniel Vetter /* Some properties could refer to dynamic refcnt'd objects, or things that
86759e71ee7SDaniel Vetter  * need special locking to handle lifetime issues (ie. to ensure the prop
86859e71ee7SDaniel Vetter  * value doesn't become invalid part way through the property update due to
86959e71ee7SDaniel Vetter  * race).  The value returned by reference via 'obj' should be passed back
87059e71ee7SDaniel Vetter  * to drm_property_change_valid_put() after the property is set (and the
8711e55a53aSMatt Roper  * object to which the property is attached has a chance to take its own
87259e71ee7SDaniel Vetter  * reference).
87359e71ee7SDaniel Vetter  */
drm_property_change_valid_get(struct drm_property * property,uint64_t value,struct drm_mode_object ** ref)87459e71ee7SDaniel Vetter bool drm_property_change_valid_get(struct drm_property *property,
87559e71ee7SDaniel Vetter 				   uint64_t value, struct drm_mode_object **ref)
87659e71ee7SDaniel Vetter {
87759e71ee7SDaniel Vetter 	int i;
87859e71ee7SDaniel Vetter 
87959e71ee7SDaniel Vetter 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
88059e71ee7SDaniel Vetter 		return false;
88159e71ee7SDaniel Vetter 
88259e71ee7SDaniel Vetter 	*ref = NULL;
88359e71ee7SDaniel Vetter 
88459e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
88559e71ee7SDaniel Vetter 		if (value < property->values[0] || value > property->values[1])
88659e71ee7SDaniel Vetter 			return false;
88759e71ee7SDaniel Vetter 		return true;
88859e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
88959e71ee7SDaniel Vetter 		int64_t svalue = U642I64(value);
89059e71ee7SDaniel Vetter 
89159e71ee7SDaniel Vetter 		if (svalue < U642I64(property->values[0]) ||
89259e71ee7SDaniel Vetter 				svalue > U642I64(property->values[1]))
89359e71ee7SDaniel Vetter 			return false;
89459e71ee7SDaniel Vetter 		return true;
89559e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
89659e71ee7SDaniel Vetter 		uint64_t valid_mask = 0;
89759e71ee7SDaniel Vetter 
89859e71ee7SDaniel Vetter 		for (i = 0; i < property->num_values; i++)
89959e71ee7SDaniel Vetter 			valid_mask |= (1ULL << property->values[i]);
90059e71ee7SDaniel Vetter 		return !(value & ~valid_mask);
90130c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
90230c06570SMaarten Lankhorst 		struct drm_property_blob *blob;
90330c06570SMaarten Lankhorst 
90430c06570SMaarten Lankhorst 		if (value == 0)
90530c06570SMaarten Lankhorst 			return true;
90630c06570SMaarten Lankhorst 
90730c06570SMaarten Lankhorst 		blob = drm_property_lookup_blob(property->dev, value);
90830c06570SMaarten Lankhorst 		if (blob) {
90930c06570SMaarten Lankhorst 			*ref = &blob->base;
91030c06570SMaarten Lankhorst 			return true;
91130c06570SMaarten Lankhorst 		} else {
91230c06570SMaarten Lankhorst 			return false;
91330c06570SMaarten Lankhorst 		}
91430c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
91559e71ee7SDaniel Vetter 		/* a zero value for an object property translates to null: */
91659e71ee7SDaniel Vetter 		if (value == 0)
91759e71ee7SDaniel Vetter 			return true;
91859e71ee7SDaniel Vetter 
919418da172SKeith Packard 		*ref = __drm_mode_object_find(property->dev, NULL, value,
92059e71ee7SDaniel Vetter 					      property->values[0]);
92159e71ee7SDaniel Vetter 		return *ref != NULL;
92259e71ee7SDaniel Vetter 	}
92359e71ee7SDaniel Vetter 
92459e71ee7SDaniel Vetter 	for (i = 0; i < property->num_values; i++)
92559e71ee7SDaniel Vetter 		if (property->values[i] == value)
92659e71ee7SDaniel Vetter 			return true;
92759e71ee7SDaniel Vetter 	return false;
92859e71ee7SDaniel Vetter }
92959e71ee7SDaniel Vetter 
drm_property_change_valid_put(struct drm_property * property,struct drm_mode_object * ref)93059e71ee7SDaniel Vetter void drm_property_change_valid_put(struct drm_property *property,
93159e71ee7SDaniel Vetter 		struct drm_mode_object *ref)
93259e71ee7SDaniel Vetter {
93359e71ee7SDaniel Vetter 	if (!ref)
93459e71ee7SDaniel Vetter 		return;
93559e71ee7SDaniel Vetter 
93630c06570SMaarten Lankhorst 	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
937020a218fSThierry Reding 		drm_mode_object_put(ref);
93830c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
9396472e509SThierry Reding 		drm_property_blob_put(obj_to_blob(ref));
94059e71ee7SDaniel Vetter }
941