LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_property.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 274 28.1 %
Date: 2023-07-19 18:55:55 Functions: 9 24 37.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Intel Corporation
       3             :  *
       4             :  * Permission to use, copy, modify, distribute, and sell this software and its
       5             :  * documentation for any purpose is hereby granted without fee, provided that
       6             :  * the above copyright notice appear in all copies and that both that copyright
       7             :  * notice and this permission notice appear in supporting documentation, and
       8             :  * that the name of the copyright holders not be used in advertising or
       9             :  * publicity pertaining to distribution of the software without specific,
      10             :  * written prior permission.  The copyright holders make no representations
      11             :  * about the suitability of this software for any purpose.  It is provided "as
      12             :  * is" without express or implied warranty.
      13             :  *
      14             :  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      15             :  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      16             :  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      17             :  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      18             :  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      19             :  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      20             :  * OF THIS SOFTWARE.
      21             :  */
      22             : 
      23             : #include <linux/export.h>
      24             : #include <linux/uaccess.h>
      25             : 
      26             : #include <drm/drm_crtc.h>
      27             : #include <drm/drm_drv.h>
      28             : #include <drm/drm_file.h>
      29             : #include <drm/drm_framebuffer.h>
      30             : #include <drm/drm_property.h>
      31             : 
      32             : #include "drm_crtc_internal.h"
      33             : 
      34             : /**
      35             :  * DOC: overview
      36             :  *
      37             :  * Properties as represented by &drm_property are used to extend the modeset
      38             :  * interface exposed to userspace. For the atomic modeset IOCTL properties are
      39             :  * even the only way to transport metadata about the desired new modeset
      40             :  * configuration from userspace to the kernel. Properties have a well-defined
      41             :  * value range, which is enforced by the drm core. See the documentation of the
      42             :  * flags member of &struct drm_property for an overview of the different
      43             :  * property types and ranges.
      44             :  *
      45             :  * Properties don't store the current value directly, but need to be
      46             :  * instantiated by attaching them to a &drm_mode_object with
      47             :  * drm_object_attach_property().
      48             :  *
      49             :  * Property values are only 64bit. To support bigger piles of data (like gamma
      50             :  * tables, color correction matrices or large structures) a property can instead
      51             :  * point at a &drm_property_blob with that additional data.
      52             :  *
      53             :  * Properties are defined by their symbolic name, userspace must keep a
      54             :  * per-object mapping from those names to the property ID used in the atomic
      55             :  * IOCTL and in the get/set property IOCTL.
      56             :  */
      57             : 
      58         751 : static bool drm_property_flags_valid(u32 flags)
      59             : {
      60         751 :         u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
      61         751 :         u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
      62             : 
      63             :         /* Reject undefined/deprecated flags */
      64         751 :         if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
      65             :                       DRM_MODE_PROP_EXTENDED_TYPE |
      66             :                       DRM_MODE_PROP_IMMUTABLE |
      67             :                       DRM_MODE_PROP_ATOMIC))
      68             :                 return false;
      69             : 
      70             :         /* We want either a legacy type or an extended type, but not both */
      71         751 :         if (!legacy_type == !ext_type)
      72             :                 return false;
      73             : 
      74             :         /* Only one legacy type at a time please */
      75        1392 :         if (legacy_type && !is_power_of_2(legacy_type))
      76             :                 return false;
      77             : 
      78         751 :         return true;
      79             : }
      80             : 
      81             : /**
      82             :  * drm_property_create - create a new property type
      83             :  * @dev: drm device
      84             :  * @flags: flags specifying the property type
      85             :  * @name: name of the property
      86             :  * @num_values: number of pre-defined values
      87             :  *
      88             :  * This creates a new generic drm property which can then be attached to a drm
      89             :  * object with drm_object_attach_property(). The returned property object must
      90             :  * be freed with drm_property_destroy(), which is done automatically when
      91             :  * calling drm_mode_config_cleanup().
      92             :  *
      93             :  * Returns:
      94             :  * A pointer to the newly created property on success, NULL on failure.
      95             :  */
      96         751 : struct drm_property *drm_property_create(struct drm_device *dev,
      97             :                                          u32 flags, const char *name,
      98             :                                          int num_values)
      99             : {
     100         751 :         struct drm_property *property = NULL;
     101             :         int ret;
     102             : 
     103         751 :         if (WARN_ON(!drm_property_flags_valid(flags)))
     104             :                 return NULL;
     105             : 
     106         751 :         if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
     107             :                 return NULL;
     108             : 
     109         751 :         property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
     110         751 :         if (!property)
     111             :                 return NULL;
     112             : 
     113         751 :         property->dev = dev;
     114             : 
     115         751 :         if (num_values) {
     116        1060 :                 property->values = kcalloc(num_values, sizeof(uint64_t),
     117             :                                            GFP_KERNEL);
     118         530 :                 if (!property->values)
     119             :                         goto fail;
     120             :         }
     121             : 
     122         751 :         ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
     123         751 :         if (ret)
     124             :                 goto fail;
     125             : 
     126         751 :         property->flags = flags;
     127         751 :         property->num_values = num_values;
     128        1502 :         INIT_LIST_HEAD(&property->enum_list);
     129             : 
     130         751 :         strscpy_pad(property->name, name, DRM_PROP_NAME_LEN);
     131             : 
     132        1502 :         list_add_tail(&property->head, &dev->mode_config.property_list);
     133             : 
     134         751 :         return property;
     135             : fail:
     136           0 :         kfree(property->values);
     137           0 :         kfree(property);
     138           0 :         return NULL;
     139             : }
     140             : EXPORT_SYMBOL(drm_property_create);
     141             : 
     142             : /**
     143             :  * drm_property_create_enum - create a new enumeration property type
     144             :  * @dev: drm device
     145             :  * @flags: flags specifying the property type
     146             :  * @name: name of the property
     147             :  * @props: enumeration lists with property values
     148             :  * @num_values: number of pre-defined values
     149             :  *
     150             :  * This creates a new generic drm property which can then be attached to a drm
     151             :  * object with drm_object_attach_property(). The returned property object must
     152             :  * be freed with drm_property_destroy(), which is done automatically when
     153             :  * calling drm_mode_config_cleanup().
     154             :  *
     155             :  * Userspace is only allowed to set one of the predefined values for enumeration
     156             :  * properties.
     157             :  *
     158             :  * Returns:
     159             :  * A pointer to the newly created property on success, NULL on failure.
     160             :  */
     161          87 : struct drm_property *drm_property_create_enum(struct drm_device *dev,
     162             :                                               u32 flags, const char *name,
     163             :                                               const struct drm_prop_enum_list *props,
     164             :                                               int num_values)
     165             : {
     166             :         struct drm_property *property;
     167             :         int i, ret;
     168             : 
     169          87 :         flags |= DRM_MODE_PROP_ENUM;
     170             : 
     171          87 :         property = drm_property_create(dev, flags, name, num_values);
     172          87 :         if (!property)
     173             :                 return NULL;
     174             : 
     175         278 :         for (i = 0; i < num_values; i++) {
     176         556 :                 ret = drm_property_add_enum(property,
     177         278 :                                             props[i].type,
     178         278 :                                             props[i].name);
     179         278 :                 if (ret) {
     180           0 :                         drm_property_destroy(dev, property);
     181           0 :                         return NULL;
     182             :                 }
     183             :         }
     184             : 
     185             :         return property;
     186             : }
     187             : EXPORT_SYMBOL(drm_property_create_enum);
     188             : 
     189             : /**
     190             :  * drm_property_create_bitmask - create a new bitmask property type
     191             :  * @dev: drm device
     192             :  * @flags: flags specifying the property type
     193             :  * @name: name of the property
     194             :  * @props: enumeration lists with property bitflags
     195             :  * @num_props: size of the @props array
     196             :  * @supported_bits: bitmask of all supported enumeration values
     197             :  *
     198             :  * This creates a new bitmask drm property which can then be attached to a drm
     199             :  * object with drm_object_attach_property(). The returned property object must
     200             :  * be freed with drm_property_destroy(), which is done automatically when
     201             :  * calling drm_mode_config_cleanup().
     202             :  *
     203             :  * Compared to plain enumeration properties userspace is allowed to set any
     204             :  * or'ed together combination of the predefined property bitflag values
     205             :  *
     206             :  * Returns:
     207             :  * A pointer to the newly created property on success, NULL on failure.
     208             :  */
     209           0 : struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
     210             :                                                  u32 flags, const char *name,
     211             :                                                  const struct drm_prop_enum_list *props,
     212             :                                                  int num_props,
     213             :                                                  uint64_t supported_bits)
     214             : {
     215             :         struct drm_property *property;
     216             :         int i, ret;
     217           0 :         int num_values = hweight64(supported_bits);
     218             : 
     219           0 :         flags |= DRM_MODE_PROP_BITMASK;
     220             : 
     221           0 :         property = drm_property_create(dev, flags, name, num_values);
     222           0 :         if (!property)
     223             :                 return NULL;
     224           0 :         for (i = 0; i < num_props; i++) {
     225           0 :                 if (!(supported_bits & (1ULL << props[i].type)))
     226           0 :                         continue;
     227             : 
     228           0 :                 ret = drm_property_add_enum(property,
     229             :                                             props[i].type,
     230             :                                             props[i].name);
     231           0 :                 if (ret) {
     232           0 :                         drm_property_destroy(dev, property);
     233           0 :                         return NULL;
     234             :                 }
     235             :         }
     236             : 
     237             :         return property;
     238             : }
     239             : EXPORT_SYMBOL(drm_property_create_bitmask);
     240             : 
     241             : static struct drm_property *property_create_range(struct drm_device *dev,
     242             :                                                   u32 flags, const char *name,
     243             :                                                   uint64_t min, uint64_t max)
     244             : {
     245             :         struct drm_property *property;
     246             : 
     247         400 :         property = drm_property_create(dev, flags, name, 2);
     248         400 :         if (!property)
     249             :                 return NULL;
     250             : 
     251         400 :         property->values[0] = min;
     252         400 :         property->values[1] = max;
     253             : 
     254             :         return property;
     255             : }
     256             : 
     257             : /**
     258             :  * drm_property_create_range - create a new unsigned ranged property type
     259             :  * @dev: drm device
     260             :  * @flags: flags specifying the property type
     261             :  * @name: name of the property
     262             :  * @min: minimum value of the property
     263             :  * @max: maximum value of the property
     264             :  *
     265             :  * This creates a new generic drm property which can then be attached to a drm
     266             :  * object with drm_object_attach_property(). The returned property object must
     267             :  * be freed with drm_property_destroy(), which is done automatically when
     268             :  * calling drm_mode_config_cleanup().
     269             :  *
     270             :  * Userspace is allowed to set any unsigned integer value in the (min, max)
     271             :  * range inclusive.
     272             :  *
     273             :  * Returns:
     274             :  * A pointer to the newly created property on success, NULL on failure.
     275             :  */
     276         268 : struct drm_property *drm_property_create_range(struct drm_device *dev,
     277             :                                                u32 flags, const char *name,
     278             :                                                uint64_t min, uint64_t max)
     279             : {
     280         668 :         return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
     281             :                         name, min, max);
     282             : }
     283             : EXPORT_SYMBOL(drm_property_create_range);
     284             : 
     285             : /**
     286             :  * drm_property_create_signed_range - create a new signed ranged property type
     287             :  * @dev: drm device
     288             :  * @flags: flags specifying the property type
     289             :  * @name: name of the property
     290             :  * @min: minimum value of the property
     291             :  * @max: maximum value of the property
     292             :  *
     293             :  * This creates a new generic drm property which can then be attached to a drm
     294             :  * object with drm_object_attach_property(). The returned property object must
     295             :  * be freed with drm_property_destroy(), which is done automatically when
     296             :  * calling drm_mode_config_cleanup().
     297             :  *
     298             :  * Userspace is allowed to set any signed integer value in the (min, max)
     299             :  * range inclusive.
     300             :  *
     301             :  * Returns:
     302             :  * A pointer to the newly created property on success, NULL on failure.
     303             :  */
     304          66 : struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
     305             :                                                       u32 flags, const char *name,
     306             :                                                       int64_t min, int64_t max)
     307             : {
     308         198 :         return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
     309             :                         name, I642U64(min), I642U64(max));
     310             : }
     311             : EXPORT_SYMBOL(drm_property_create_signed_range);
     312             : 
     313             : /**
     314             :  * drm_property_create_object - create a new object property type
     315             :  * @dev: drm device
     316             :  * @flags: flags specifying the property type
     317             :  * @name: name of the property
     318             :  * @type: object type from DRM_MODE_OBJECT_* defines
     319             :  *
     320             :  * This creates a new generic drm property which can then be attached to a drm
     321             :  * object with drm_object_attach_property(). The returned property object must
     322             :  * be freed with drm_property_destroy(), which is done automatically when
     323             :  * calling drm_mode_config_cleanup().
     324             :  *
     325             :  * Userspace is only allowed to set this to any property value of the given
     326             :  * @type. Only useful for atomic properties, which is enforced.
     327             :  *
     328             :  * Returns:
     329             :  * A pointer to the newly created property on success, NULL on failure.
     330             :  */
     331          44 : struct drm_property *drm_property_create_object(struct drm_device *dev,
     332             :                                                 u32 flags, const char *name,
     333             :                                                 uint32_t type)
     334             : {
     335             :         struct drm_property *property;
     336             : 
     337          44 :         flags |= DRM_MODE_PROP_OBJECT;
     338             : 
     339          44 :         if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
     340             :                 return NULL;
     341             : 
     342          44 :         property = drm_property_create(dev, flags, name, 1);
     343          44 :         if (!property)
     344             :                 return NULL;
     345             : 
     346          44 :         property->values[0] = type;
     347             : 
     348          44 :         return property;
     349             : }
     350             : EXPORT_SYMBOL(drm_property_create_object);
     351             : 
     352             : /**
     353             :  * drm_property_create_bool - create a new boolean property type
     354             :  * @dev: drm device
     355             :  * @flags: flags specifying the property type
     356             :  * @name: name of the property
     357             :  *
     358             :  * This creates a new generic drm property which can then be attached to a drm
     359             :  * object with drm_object_attach_property(). The returned property object must
     360             :  * be freed with drm_property_destroy(), which is done automatically when
     361             :  * calling drm_mode_config_cleanup().
     362             :  *
     363             :  * This is implemented as a ranged property with only {0, 1} as valid values.
     364             :  *
     365             :  * Returns:
     366             :  * A pointer to the newly created property on success, NULL on failure.
     367             :  */
     368          66 : struct drm_property *drm_property_create_bool(struct drm_device *dev,
     369             :                                               u32 flags, const char *name)
     370             : {
     371          66 :         return drm_property_create_range(dev, flags, name, 0, 1);
     372             : }
     373             : EXPORT_SYMBOL(drm_property_create_bool);
     374             : 
     375             : /**
     376             :  * drm_property_add_enum - add a possible value to an enumeration property
     377             :  * @property: enumeration property to change
     378             :  * @value: value of the new enumeration
     379             :  * @name: symbolic name of the new enumeration
     380             :  *
     381             :  * This functions adds enumerations to a property.
     382             :  *
     383             :  * It's use is deprecated, drivers should use one of the more specific helpers
     384             :  * to directly create the property with all enumerations already attached.
     385             :  *
     386             :  * Returns:
     387             :  * Zero on success, error code on failure.
     388             :  */
     389         278 : int drm_property_add_enum(struct drm_property *property,
     390             :                           uint64_t value, const char *name)
     391             : {
     392             :         struct drm_property_enum *prop_enum;
     393         278 :         int index = 0;
     394             : 
     395         278 :         if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
     396             :                 return -EINVAL;
     397             : 
     398         556 :         if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
     399             :                     !drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
     400             :                 return -EINVAL;
     401             : 
     402             :         /*
     403             :          * Bitmask enum properties have the additional constraint of values
     404             :          * from 0 to 63
     405             :          */
     406         556 :         if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
     407             :                     value > 63))
     408             :                 return -EINVAL;
     409             : 
     410         642 :         list_for_each_entry(prop_enum, &property->enum_list, head) {
     411         364 :                 if (WARN_ON(prop_enum->value == value))
     412             :                         return -EINVAL;
     413         364 :                 index++;
     414             :         }
     415             : 
     416         278 :         if (WARN_ON(index >= property->num_values))
     417             :                 return -EINVAL;
     418             : 
     419         278 :         prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
     420         278 :         if (!prop_enum)
     421             :                 return -ENOMEM;
     422             : 
     423         278 :         strscpy_pad(prop_enum->name, name, DRM_PROP_NAME_LEN);
     424         278 :         prop_enum->value = value;
     425             : 
     426         278 :         property->values[index] = value;
     427         556 :         list_add_tail(&prop_enum->head, &property->enum_list);
     428         278 :         return 0;
     429             : }
     430             : EXPORT_SYMBOL(drm_property_add_enum);
     431             : 
     432             : /**
     433             :  * drm_property_destroy - destroy a drm property
     434             :  * @dev: drm device
     435             :  * @property: property to destroy
     436             :  *
     437             :  * This function frees a property including any attached resources like
     438             :  * enumeration values.
     439             :  */
     440         751 : void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
     441             : {
     442             :         struct drm_property_enum *prop_enum, *pt;
     443             : 
     444        1029 :         list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
     445         556 :                 list_del(&prop_enum->head);
     446         278 :                 kfree(prop_enum);
     447             :         }
     448             : 
     449         751 :         if (property->num_values)
     450         530 :                 kfree(property->values);
     451         751 :         drm_mode_object_unregister(dev, &property->base);
     452        1502 :         list_del(&property->head);
     453         751 :         kfree(property);
     454         751 : }
     455             : EXPORT_SYMBOL(drm_property_destroy);
     456             : 
     457           0 : int drm_mode_getproperty_ioctl(struct drm_device *dev,
     458             :                                void *data, struct drm_file *file_priv)
     459             : {
     460           0 :         struct drm_mode_get_property *out_resp = data;
     461             :         struct drm_property *property;
     462           0 :         int enum_count = 0;
     463           0 :         int value_count = 0;
     464             :         int i, copied;
     465             :         struct drm_property_enum *prop_enum;
     466             :         struct drm_mode_property_enum __user *enum_ptr;
     467             :         uint64_t __user *values_ptr;
     468             : 
     469           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     470             :                 return -EOPNOTSUPP;
     471             : 
     472           0 :         property = drm_property_find(dev, file_priv, out_resp->prop_id);
     473           0 :         if (!property)
     474             :                 return -ENOENT;
     475             : 
     476           0 :         strscpy_pad(out_resp->name, property->name, DRM_PROP_NAME_LEN);
     477           0 :         out_resp->flags = property->flags;
     478             : 
     479           0 :         value_count = property->num_values;
     480           0 :         values_ptr = u64_to_user_ptr(out_resp->values_ptr);
     481             : 
     482           0 :         for (i = 0; i < value_count; i++) {
     483           0 :                 if (i < out_resp->count_values &&
     484           0 :                     put_user(property->values[i], values_ptr + i)) {
     485             :                         return -EFAULT;
     486             :                 }
     487             :         }
     488           0 :         out_resp->count_values = value_count;
     489             : 
     490           0 :         copied = 0;
     491           0 :         enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
     492             : 
     493           0 :         if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
     494           0 :             drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
     495           0 :                 list_for_each_entry(prop_enum, &property->enum_list, head) {
     496           0 :                         enum_count++;
     497           0 :                         if (out_resp->count_enum_blobs < enum_count)
     498           0 :                                 continue;
     499             : 
     500           0 :                         if (copy_to_user(&enum_ptr[copied].value,
     501           0 :                                          &prop_enum->value, sizeof(uint64_t)))
     502             :                                 return -EFAULT;
     503             : 
     504           0 :                         if (copy_to_user(&enum_ptr[copied].name,
     505           0 :                                          &prop_enum->name, DRM_PROP_NAME_LEN))
     506             :                                 return -EFAULT;
     507           0 :                         copied++;
     508             :                 }
     509           0 :                 out_resp->count_enum_blobs = enum_count;
     510             :         }
     511             : 
     512             :         /*
     513             :          * NOTE: The idea seems to have been to use this to read all the blob
     514             :          * property values. But nothing ever added them to the corresponding
     515             :          * list, userspace always used the special-purpose get_blob ioctl to
     516             :          * read the value for a blob property. It also doesn't make a lot of
     517             :          * sense to return values here when everything else is just metadata for
     518             :          * the property itself.
     519             :          */
     520           0 :         if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
     521           0 :                 out_resp->count_enum_blobs = 0;
     522             : 
     523             :         return 0;
     524             : }
     525             : 
     526           0 : static void drm_property_free_blob(struct kref *kref)
     527             : {
     528           0 :         struct drm_property_blob *blob =
     529           0 :                 container_of(kref, struct drm_property_blob, base.refcount);
     530             : 
     531           0 :         mutex_lock(&blob->dev->mode_config.blob_lock);
     532           0 :         list_del(&blob->head_global);
     533           0 :         mutex_unlock(&blob->dev->mode_config.blob_lock);
     534             : 
     535           0 :         drm_mode_object_unregister(blob->dev, &blob->base);
     536             : 
     537           0 :         kvfree(blob);
     538           0 : }
     539             : 
     540             : /**
     541             :  * drm_property_create_blob - Create new blob property
     542             :  * @dev: DRM device to create property for
     543             :  * @length: Length to allocate for blob data
     544             :  * @data: If specified, copies data into blob
     545             :  *
     546             :  * Creates a new blob property for a specified DRM device, optionally
     547             :  * copying data. Note that blob properties are meant to be invariant, hence the
     548             :  * data must be filled out before the blob is used as the value of any property.
     549             :  *
     550             :  * Returns:
     551             :  * New blob property with a single reference on success, or an ERR_PTR
     552             :  * value on failure.
     553             :  */
     554             : struct drm_property_blob *
     555           0 : drm_property_create_blob(struct drm_device *dev, size_t length,
     556             :                          const void *data)
     557             : {
     558             :         struct drm_property_blob *blob;
     559             :         int ret;
     560             : 
     561           0 :         if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
     562             :                 return ERR_PTR(-EINVAL);
     563             : 
     564           0 :         blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
     565           0 :         if (!blob)
     566             :                 return ERR_PTR(-ENOMEM);
     567             : 
     568             :         /* This must be explicitly initialised, so we can safely call list_del
     569             :          * on it in the removal handler, even if it isn't in a file list. */
     570           0 :         INIT_LIST_HEAD(&blob->head_file);
     571           0 :         blob->data = (void *)blob + sizeof(*blob);
     572           0 :         blob->length = length;
     573           0 :         blob->dev = dev;
     574             : 
     575           0 :         if (data)
     576           0 :                 memcpy(blob->data, data, length);
     577             : 
     578           0 :         ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
     579             :                                     true, drm_property_free_blob);
     580           0 :         if (ret) {
     581           0 :                 kvfree(blob);
     582           0 :                 return ERR_PTR(-EINVAL);
     583             :         }
     584             : 
     585           0 :         mutex_lock(&dev->mode_config.blob_lock);
     586           0 :         list_add_tail(&blob->head_global,
     587             :                       &dev->mode_config.property_blob_list);
     588           0 :         mutex_unlock(&dev->mode_config.blob_lock);
     589             : 
     590           0 :         return blob;
     591             : }
     592             : EXPORT_SYMBOL(drm_property_create_blob);
     593             : 
     594             : /**
     595             :  * drm_property_blob_put - release a blob property reference
     596             :  * @blob: DRM blob property
     597             :  *
     598             :  * Releases a reference to a blob property. May free the object.
     599             :  */
     600           0 : void drm_property_blob_put(struct drm_property_blob *blob)
     601             : {
     602           0 :         if (!blob)
     603             :                 return;
     604             : 
     605           0 :         drm_mode_object_put(&blob->base);
     606             : }
     607             : EXPORT_SYMBOL(drm_property_blob_put);
     608             : 
     609           0 : void drm_property_destroy_user_blobs(struct drm_device *dev,
     610             :                                      struct drm_file *file_priv)
     611             : {
     612             :         struct drm_property_blob *blob, *bt;
     613             : 
     614             :         /*
     615             :          * When the file gets released that means no one else can access the
     616             :          * blob list any more, so no need to grab dev->blob_lock.
     617             :          */
     618           0 :         list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
     619           0 :                 list_del_init(&blob->head_file);
     620           0 :                 drm_property_blob_put(blob);
     621             :         }
     622           0 : }
     623             : 
     624             : /**
     625             :  * drm_property_blob_get - acquire blob property reference
     626             :  * @blob: DRM blob property
     627             :  *
     628             :  * Acquires a reference to an existing blob property. Returns @blob, which
     629             :  * allows this to be used as a shorthand in assignments.
     630             :  */
     631           0 : struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
     632             : {
     633           0 :         drm_mode_object_get(&blob->base);
     634           0 :         return blob;
     635             : }
     636             : EXPORT_SYMBOL(drm_property_blob_get);
     637             : 
     638             : /**
     639             :  * drm_property_lookup_blob - look up a blob property and take a reference
     640             :  * @dev: drm device
     641             :  * @id: id of the blob property
     642             :  *
     643             :  * If successful, this takes an additional reference to the blob property.
     644             :  * callers need to make sure to eventually unreferenced the returned property
     645             :  * again, using drm_property_blob_put().
     646             :  *
     647             :  * Return:
     648             :  * NULL on failure, pointer to the blob on success.
     649             :  */
     650           0 : struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
     651             :                                                    uint32_t id)
     652             : {
     653             :         struct drm_mode_object *obj;
     654           0 :         struct drm_property_blob *blob = NULL;
     655             : 
     656           0 :         obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
     657           0 :         if (obj)
     658           0 :                 blob = obj_to_blob(obj);
     659           0 :         return blob;
     660             : }
     661             : EXPORT_SYMBOL(drm_property_lookup_blob);
     662             : 
     663             : /**
     664             :  * drm_property_replace_global_blob - replace existing blob property
     665             :  * @dev: drm device
     666             :  * @replace: location of blob property pointer to be replaced
     667             :  * @length: length of data for new blob, or 0 for no data
     668             :  * @data: content for new blob, or NULL for no data
     669             :  * @obj_holds_id: optional object for property holding blob ID
     670             :  * @prop_holds_id: optional property holding blob ID
     671             :  * @return 0 on success or error on failure
     672             :  *
     673             :  * This function will replace a global property in the blob list, optionally
     674             :  * updating a property which holds the ID of that property.
     675             :  *
     676             :  * If length is 0 or data is NULL, no new blob will be created, and the holding
     677             :  * property, if specified, will be set to 0.
     678             :  *
     679             :  * Access to the replace pointer is assumed to be protected by the caller, e.g.
     680             :  * by holding the relevant modesetting object lock for its parent.
     681             :  *
     682             :  * For example, a drm_connector has a 'PATH' property, which contains the ID
     683             :  * of a blob property with the value of the MST path information. Calling this
     684             :  * function with replace pointing to the connector's path_blob_ptr, length and
     685             :  * data set for the new path information, obj_holds_id set to the connector's
     686             :  * base object, and prop_holds_id set to the path property name, will perform
     687             :  * a completely atomic update. The access to path_blob_ptr is protected by the
     688             :  * caller holding a lock on the connector.
     689             :  */
     690           0 : int drm_property_replace_global_blob(struct drm_device *dev,
     691             :                                      struct drm_property_blob **replace,
     692             :                                      size_t length,
     693             :                                      const void *data,
     694             :                                      struct drm_mode_object *obj_holds_id,
     695             :                                      struct drm_property *prop_holds_id)
     696             : {
     697           0 :         struct drm_property_blob *new_blob = NULL;
     698           0 :         struct drm_property_blob *old_blob = NULL;
     699             :         int ret;
     700             : 
     701           0 :         WARN_ON(replace == NULL);
     702             : 
     703           0 :         old_blob = *replace;
     704             : 
     705           0 :         if (length && data) {
     706           0 :                 new_blob = drm_property_create_blob(dev, length, data);
     707           0 :                 if (IS_ERR(new_blob))
     708           0 :                         return PTR_ERR(new_blob);
     709             :         }
     710             : 
     711           0 :         if (obj_holds_id) {
     712           0 :                 ret = drm_object_property_set_value(obj_holds_id,
     713             :                                                     prop_holds_id,
     714             :                                                     new_blob ?
     715           0 :                                                         new_blob->base.id : 0);
     716           0 :                 if (ret != 0)
     717             :                         goto err_created;
     718             :         }
     719             : 
     720           0 :         drm_property_blob_put(old_blob);
     721           0 :         *replace = new_blob;
     722             : 
     723           0 :         return 0;
     724             : 
     725             : err_created:
     726             :         drm_property_blob_put(new_blob);
     727             :         return ret;
     728             : }
     729             : EXPORT_SYMBOL(drm_property_replace_global_blob);
     730             : 
     731             : /**
     732             :  * drm_property_replace_blob - replace a blob property
     733             :  * @blob: a pointer to the member blob to be replaced
     734             :  * @new_blob: the new blob to replace with
     735             :  *
     736             :  * Return: true if the blob was in fact replaced.
     737             :  */
     738           0 : bool drm_property_replace_blob(struct drm_property_blob **blob,
     739             :                                struct drm_property_blob *new_blob)
     740             : {
     741           0 :         struct drm_property_blob *old_blob = *blob;
     742             : 
     743           0 :         if (old_blob == new_blob)
     744             :                 return false;
     745             : 
     746           0 :         drm_property_blob_put(old_blob);
     747           0 :         if (new_blob)
     748             :                 drm_property_blob_get(new_blob);
     749           0 :         *blob = new_blob;
     750           0 :         return true;
     751             : }
     752             : EXPORT_SYMBOL(drm_property_replace_blob);
     753             : 
     754           0 : int drm_mode_getblob_ioctl(struct drm_device *dev,
     755             :                            void *data, struct drm_file *file_priv)
     756             : {
     757           0 :         struct drm_mode_get_blob *out_resp = data;
     758             :         struct drm_property_blob *blob;
     759           0 :         int ret = 0;
     760             : 
     761           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     762             :                 return -EOPNOTSUPP;
     763             : 
     764           0 :         blob = drm_property_lookup_blob(dev, out_resp->blob_id);
     765           0 :         if (!blob)
     766             :                 return -ENOENT;
     767             : 
     768           0 :         if (out_resp->length == blob->length) {
     769           0 :                 if (copy_to_user(u64_to_user_ptr(out_resp->data),
     770           0 :                                  blob->data,
     771             :                                  blob->length)) {
     772             :                         ret = -EFAULT;
     773             :                         goto unref;
     774             :                 }
     775             :         }
     776           0 :         out_resp->length = blob->length;
     777             : unref:
     778           0 :         drm_property_blob_put(blob);
     779             : 
     780           0 :         return ret;
     781             : }
     782             : 
     783           0 : int drm_mode_createblob_ioctl(struct drm_device *dev,
     784             :                               void *data, struct drm_file *file_priv)
     785             : {
     786           0 :         struct drm_mode_create_blob *out_resp = data;
     787             :         struct drm_property_blob *blob;
     788           0 :         int ret = 0;
     789             : 
     790           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     791             :                 return -EOPNOTSUPP;
     792             : 
     793           0 :         blob = drm_property_create_blob(dev, out_resp->length, NULL);
     794           0 :         if (IS_ERR(blob))
     795           0 :                 return PTR_ERR(blob);
     796             : 
     797           0 :         if (copy_from_user(blob->data,
     798           0 :                            u64_to_user_ptr(out_resp->data),
     799           0 :                            out_resp->length)) {
     800           0 :                 ret = -EFAULT;
     801             :                 goto out_blob;
     802             :         }
     803             : 
     804             :         /* Dropping the lock between create_blob and our access here is safe
     805             :          * as only the same file_priv can remove the blob; at this point, it is
     806             :          * not associated with any file_priv. */
     807           0 :         mutex_lock(&dev->mode_config.blob_lock);
     808           0 :         out_resp->blob_id = blob->base.id;
     809           0 :         list_add_tail(&blob->head_file, &file_priv->blobs);
     810           0 :         mutex_unlock(&dev->mode_config.blob_lock);
     811             : 
     812           0 :         return 0;
     813             : 
     814             : out_blob:
     815             :         drm_property_blob_put(blob);
     816             :         return ret;
     817             : }
     818             : 
     819           0 : int drm_mode_destroyblob_ioctl(struct drm_device *dev,
     820             :                                void *data, struct drm_file *file_priv)
     821             : {
     822           0 :         struct drm_mode_destroy_blob *out_resp = data;
     823           0 :         struct drm_property_blob *blob = NULL, *bt;
     824           0 :         bool found = false;
     825           0 :         int ret = 0;
     826             : 
     827           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     828             :                 return -EOPNOTSUPP;
     829             : 
     830           0 :         blob = drm_property_lookup_blob(dev, out_resp->blob_id);
     831           0 :         if (!blob)
     832             :                 return -ENOENT;
     833             : 
     834           0 :         mutex_lock(&dev->mode_config.blob_lock);
     835             :         /* Ensure the property was actually created by this user. */
     836           0 :         list_for_each_entry(bt, &file_priv->blobs, head_file) {
     837           0 :                 if (bt == blob) {
     838             :                         found = true;
     839             :                         break;
     840             :                 }
     841             :         }
     842             : 
     843           0 :         if (!found) {
     844           0 :                 ret = -EPERM;
     845             :                 goto err;
     846             :         }
     847             : 
     848             :         /* We must drop head_file here, because we may not be the last
     849             :          * reference on the blob. */
     850           0 :         list_del_init(&blob->head_file);
     851           0 :         mutex_unlock(&dev->mode_config.blob_lock);
     852             : 
     853             :         /* One reference from lookup, and one from the filp. */
     854           0 :         drm_property_blob_put(blob);
     855           0 :         drm_property_blob_put(blob);
     856             : 
     857           0 :         return 0;
     858             : 
     859             : err:
     860           0 :         mutex_unlock(&dev->mode_config.blob_lock);
     861           0 :         drm_property_blob_put(blob);
     862             : 
     863           0 :         return ret;
     864             : }
     865             : 
     866             : /* Some properties could refer to dynamic refcnt'd objects, or things that
     867             :  * need special locking to handle lifetime issues (ie. to ensure the prop
     868             :  * value doesn't become invalid part way through the property update due to
     869             :  * race).  The value returned by reference via 'obj' should be passed back
     870             :  * to drm_property_change_valid_put() after the property is set (and the
     871             :  * object to which the property is attached has a chance to take its own
     872             :  * reference).
     873             :  */
     874           0 : bool drm_property_change_valid_get(struct drm_property *property,
     875             :                                    uint64_t value, struct drm_mode_object **ref)
     876             : {
     877             :         int i;
     878             : 
     879           0 :         if (property->flags & DRM_MODE_PROP_IMMUTABLE)
     880             :                 return false;
     881             : 
     882           0 :         *ref = NULL;
     883             : 
     884           0 :         if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
     885           0 :                 if (value < property->values[0] || value > property->values[1])
     886             :                         return false;
     887           0 :                 return true;
     888           0 :         } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
     889           0 :                 int64_t svalue = U642I64(value);
     890             : 
     891           0 :                 if (svalue < U642I64(property->values[0]) ||
     892           0 :                                 svalue > U642I64(property->values[1]))
     893             :                         return false;
     894             :                 return true;
     895           0 :         } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
     896             :                 uint64_t valid_mask = 0;
     897             : 
     898           0 :                 for (i = 0; i < property->num_values; i++)
     899           0 :                         valid_mask |= (1ULL << property->values[i]);
     900           0 :                 return !(value & ~valid_mask);
     901           0 :         } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
     902             :                 struct drm_property_blob *blob;
     903             : 
     904           0 :                 if (value == 0)
     905             :                         return true;
     906             : 
     907           0 :                 blob = drm_property_lookup_blob(property->dev, value);
     908           0 :                 if (blob) {
     909           0 :                         *ref = &blob->base;
     910           0 :                         return true;
     911             :                 } else {
     912             :                         return false;
     913             :                 }
     914           0 :         } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
     915             :                 /* a zero value for an object property translates to null: */
     916           0 :                 if (value == 0)
     917             :                         return true;
     918             : 
     919           0 :                 *ref = __drm_mode_object_find(property->dev, NULL, value,
     920           0 :                                               property->values[0]);
     921           0 :                 return *ref != NULL;
     922             :         }
     923             : 
     924           0 :         for (i = 0; i < property->num_values; i++)
     925           0 :                 if (property->values[i] == value)
     926             :                         return true;
     927             :         return false;
     928             : }
     929             : 
     930           0 : void drm_property_change_valid_put(struct drm_property *property,
     931             :                 struct drm_mode_object *ref)
     932             : {
     933           0 :         if (!ref)
     934             :                 return;
     935             : 
     936           0 :         if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
     937           0 :                 drm_mode_object_put(ref);
     938           0 :         } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
     939           0 :                 drm_property_blob_put(obj_to_blob(ref));
     940             : }

Generated by: LCOV version 1.14