linux/drivers/gpu/drm/drm_mode_object.c
<<
>>
Prefs
   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_atomic.h>
  27#include <drm/drm_drv.h>
  28#include <drm/drm_device.h>
  29#include <drm/drm_file.h>
  30#include <drm/drm_mode_object.h>
  31#include <drm/drm_print.h>
  32
  33#include "drm_crtc_internal.h"
  34
  35/*
  36 * Internal function to assign a slot in the object idr and optionally
  37 * register the object into the idr.
  38 */
  39int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
  40                          uint32_t obj_type, bool register_obj,
  41                          void (*obj_free_cb)(struct kref *kref))
  42{
  43        int ret;
  44
  45        WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
  46
  47        mutex_lock(&dev->mode_config.idr_mutex);
  48        ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,
  49                        1, 0, GFP_KERNEL);
  50        if (ret >= 0) {
  51                /*
  52                 * Set up the object linking under the protection of the idr
  53                 * lock so that other users can't see inconsistent state.
  54                 */
  55                obj->id = ret;
  56                obj->type = obj_type;
  57                if (obj_free_cb) {
  58                        obj->free_cb = obj_free_cb;
  59                        kref_init(&obj->refcount);
  60                }
  61        }
  62        mutex_unlock(&dev->mode_config.idr_mutex);
  63
  64        return ret < 0 ? ret : 0;
  65}
  66
  67/**
  68 * drm_mode_object_add - allocate a new modeset identifier
  69 * @dev: DRM device
  70 * @obj: object pointer, used to generate unique ID
  71 * @obj_type: object type
  72 *
  73 * Create a unique identifier based on @ptr in @dev's identifier space.  Used
  74 * for tracking modes, CRTCs and connectors.
  75 *
  76 * Returns:
  77 * Zero on success, error code on failure.
  78 */
  79int drm_mode_object_add(struct drm_device *dev,
  80                        struct drm_mode_object *obj, uint32_t obj_type)
  81{
  82        return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
  83}
  84
  85void drm_mode_object_register(struct drm_device *dev,
  86                              struct drm_mode_object *obj)
  87{
  88        mutex_lock(&dev->mode_config.idr_mutex);
  89        idr_replace(&dev->mode_config.object_idr, obj, obj->id);
  90        mutex_unlock(&dev->mode_config.idr_mutex);
  91}
  92
  93/**
  94 * drm_mode_object_unregister - free a modeset identifier
  95 * @dev: DRM device
  96 * @object: object to free
  97 *
  98 * Free @id from @dev's unique identifier pool.
  99 * This function can be called multiple times, and guards against
 100 * multiple removals.
 101 * These modeset identifiers are _not_ reference counted. Hence don't use this
 102 * for reference counted modeset objects like framebuffers.
 103 */
 104void drm_mode_object_unregister(struct drm_device *dev,
 105                                struct drm_mode_object *object)
 106{
 107        WARN_ON(!dev->driver->load && dev->registered && !object->free_cb);
 108
 109        mutex_lock(&dev->mode_config.idr_mutex);
 110        if (object->id) {
 111                idr_remove(&dev->mode_config.object_idr, object->id);
 112                object->id = 0;
 113        }
 114        mutex_unlock(&dev->mode_config.idr_mutex);
 115}
 116
 117/**
 118 * drm_mode_object_lease_required - check types which must be leased to be used
 119 * @type: type of object
 120 *
 121 * Returns whether the provided type of drm_mode_object must
 122 * be owned or leased to be used by a process.
 123 */
 124bool drm_mode_object_lease_required(uint32_t type)
 125{
 126        switch(type) {
 127        case DRM_MODE_OBJECT_CRTC:
 128        case DRM_MODE_OBJECT_CONNECTOR:
 129        case DRM_MODE_OBJECT_PLANE:
 130                return true;
 131        default:
 132                return false;
 133        }
 134}
 135
 136struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
 137                                               struct drm_file *file_priv,
 138                                               uint32_t id, uint32_t type)
 139{
 140        struct drm_mode_object *obj = NULL;
 141
 142        mutex_lock(&dev->mode_config.idr_mutex);
 143        obj = idr_find(&dev->mode_config.object_idr, id);
 144        if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
 145                obj = NULL;
 146        if (obj && obj->id != id)
 147                obj = NULL;
 148
 149        if (obj && drm_mode_object_lease_required(obj->type) &&
 150            !_drm_lease_held(file_priv, obj->id))
 151                obj = NULL;
 152
 153        if (obj && obj->free_cb) {
 154                if (!kref_get_unless_zero(&obj->refcount))
 155                        obj = NULL;
 156        }
 157        mutex_unlock(&dev->mode_config.idr_mutex);
 158
 159        return obj;
 160}
 161
 162/**
 163 * drm_mode_object_find - look up a drm object with static lifetime
 164 * @dev: drm device
 165 * @file_priv: drm file
 166 * @id: id of the mode object
 167 * @type: type of the mode object
 168 *
 169 * This function is used to look up a modeset object. It will acquire a
 170 * reference for reference counted objects. This reference must be dropped again
 171 * by callind drm_mode_object_put().
 172 */
 173struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 174                struct drm_file *file_priv,
 175                uint32_t id, uint32_t type)
 176{
 177        struct drm_mode_object *obj = NULL;
 178
 179        obj = __drm_mode_object_find(dev, file_priv, id, type);
 180        return obj;
 181}
 182EXPORT_SYMBOL(drm_mode_object_find);
 183
 184/**
 185 * drm_mode_object_put - release a mode object reference
 186 * @obj: DRM mode object
 187 *
 188 * This function decrements the object's refcount if it is a refcounted modeset
 189 * object. It is a no-op on any other object. This is used to drop references
 190 * acquired with drm_mode_object_get().
 191 */
 192void drm_mode_object_put(struct drm_mode_object *obj)
 193{
 194        if (obj->free_cb) {
 195                DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
 196                kref_put(&obj->refcount, obj->free_cb);
 197        }
 198}
 199EXPORT_SYMBOL(drm_mode_object_put);
 200
 201/**
 202 * drm_mode_object_get - acquire a mode object reference
 203 * @obj: DRM mode object
 204 *
 205 * This function increments the object's refcount if it is a refcounted modeset
 206 * object. It is a no-op on any other object. References should be dropped again
 207 * by calling drm_mode_object_put().
 208 */
 209void drm_mode_object_get(struct drm_mode_object *obj)
 210{
 211        if (obj->free_cb) {
 212                DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
 213                kref_get(&obj->refcount);
 214        }
 215}
 216EXPORT_SYMBOL(drm_mode_object_get);
 217
 218/**
 219 * drm_object_attach_property - attach a property to a modeset object
 220 * @obj: drm modeset object
 221 * @property: property to attach
 222 * @init_val: initial value of the property
 223 *
 224 * This attaches the given property to the modeset object with the given initial
 225 * value. Currently this function cannot fail since the properties are stored in
 226 * a statically sized array.
 227 *
 228 * Note that all properties must be attached before the object itself is
 229 * registered and accessible from userspace.
 230 */
 231void drm_object_attach_property(struct drm_mode_object *obj,
 232                                struct drm_property *property,
 233                                uint64_t init_val)
 234{
 235        int count = obj->properties->count;
 236        struct drm_device *dev = property->dev;
 237
 238
 239        if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
 240                struct drm_connector *connector = obj_to_connector(obj);
 241
 242                WARN_ON(!dev->driver->load &&
 243                        connector->registration_state == DRM_CONNECTOR_REGISTERED);
 244        } else {
 245                WARN_ON(!dev->driver->load && dev->registered);
 246        }
 247
 248        if (count == DRM_OBJECT_MAX_PROPERTY) {
 249                WARN(1, "Failed to attach object property (type: 0x%x). Please "
 250                        "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
 251                        "you see this message on the same object type.\n",
 252                        obj->type);
 253                return;
 254        }
 255
 256        obj->properties->properties[count] = property;
 257        obj->properties->values[count] = init_val;
 258        obj->properties->count++;
 259}
 260EXPORT_SYMBOL(drm_object_attach_property);
 261
 262/**
 263 * drm_object_property_set_value - set the value of a property
 264 * @obj: drm mode object to set property value for
 265 * @property: property to set
 266 * @val: value the property should be set to
 267 *
 268 * This function sets a given property on a given object. This function only
 269 * changes the software state of the property, it does not call into the
 270 * driver's ->set_property callback.
 271 *
 272 * Note that atomic drivers should not have any need to call this, the core will
 273 * ensure consistency of values reported back to userspace through the
 274 * appropriate ->atomic_get_property callback. Only legacy drivers should call
 275 * this function to update the tracked value (after clamping and other
 276 * restrictions have been applied).
 277 *
 278 * Returns:
 279 * Zero on success, error code on failure.
 280 */
 281int drm_object_property_set_value(struct drm_mode_object *obj,
 282                                  struct drm_property *property, uint64_t val)
 283{
 284        int i;
 285
 286        WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
 287                !(property->flags & DRM_MODE_PROP_IMMUTABLE));
 288
 289        for (i = 0; i < obj->properties->count; i++) {
 290                if (obj->properties->properties[i] == property) {
 291                        obj->properties->values[i] = val;
 292                        return 0;
 293                }
 294        }
 295
 296        return -EINVAL;
 297}
 298EXPORT_SYMBOL(drm_object_property_set_value);
 299
 300static int __drm_object_property_get_value(struct drm_mode_object *obj,
 301                                           struct drm_property *property,
 302                                           uint64_t *val)
 303{
 304        int i;
 305
 306        /* read-only properties bypass atomic mechanism and still store
 307         * their value in obj->properties->values[].. mostly to avoid
 308         * having to deal w/ EDID and similar props in atomic paths:
 309         */
 310        if (drm_drv_uses_atomic_modeset(property->dev) &&
 311                        !(property->flags & DRM_MODE_PROP_IMMUTABLE))
 312                return drm_atomic_get_property(obj, property, val);
 313
 314        for (i = 0; i < obj->properties->count; i++) {
 315                if (obj->properties->properties[i] == property) {
 316                        *val = obj->properties->values[i];
 317                        return 0;
 318                }
 319
 320        }
 321
 322        return -EINVAL;
 323}
 324
 325/**
 326 * drm_object_property_get_value - retrieve the value of a property
 327 * @obj: drm mode object to get property value from
 328 * @property: property to retrieve
 329 * @val: storage for the property value
 330 *
 331 * This function retrieves the softare state of the given property for the given
 332 * property. Since there is no driver callback to retrieve the current property
 333 * value this might be out of sync with the hardware, depending upon the driver
 334 * and property.
 335 *
 336 * Atomic drivers should never call this function directly, the core will read
 337 * out property values through the various ->atomic_get_property callbacks.
 338 *
 339 * Returns:
 340 * Zero on success, error code on failure.
 341 */
 342int drm_object_property_get_value(struct drm_mode_object *obj,
 343                                  struct drm_property *property, uint64_t *val)
 344{
 345        WARN_ON(drm_drv_uses_atomic_modeset(property->dev));
 346
 347        return __drm_object_property_get_value(obj, property, val);
 348}
 349EXPORT_SYMBOL(drm_object_property_get_value);
 350
 351/* helper for getconnector and getproperties ioctls */
 352int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
 353                                   uint32_t __user *prop_ptr,
 354                                   uint64_t __user *prop_values,
 355                                   uint32_t *arg_count_props)
 356{
 357        int i, ret, count;
 358
 359        for (i = 0, count = 0; i < obj->properties->count; i++) {
 360                struct drm_property *prop = obj->properties->properties[i];
 361                uint64_t val;
 362
 363                if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
 364                        continue;
 365
 366                if (*arg_count_props > count) {
 367                        ret = __drm_object_property_get_value(obj, prop, &val);
 368                        if (ret)
 369                                return ret;
 370
 371                        if (put_user(prop->base.id, prop_ptr + count))
 372                                return -EFAULT;
 373
 374                        if (put_user(val, prop_values + count))
 375                                return -EFAULT;
 376                }
 377
 378                count++;
 379        }
 380        *arg_count_props = count;
 381
 382        return 0;
 383}
 384
 385/**
 386 * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
 387 * @dev: DRM device
 388 * @data: ioctl data
 389 * @file_priv: DRM file info
 390 *
 391 * This function retrieves the current value for an object's property. Compared
 392 * to the connector specific ioctl this one is extended to also work on crtc and
 393 * plane objects.
 394 *
 395 * Called by the user via ioctl.
 396 *
 397 * Returns:
 398 * Zero on success, negative errno on failure.
 399 */
 400int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 401                                      struct drm_file *file_priv)
 402{
 403        struct drm_mode_obj_get_properties *arg = data;
 404        struct drm_mode_object *obj;
 405        struct drm_modeset_acquire_ctx ctx;
 406        int ret = 0;
 407
 408        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 409                return -EOPNOTSUPP;
 410
 411        DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
 412
 413        obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
 414        if (!obj) {
 415                ret = -ENOENT;
 416                goto out;
 417        }
 418        if (!obj->properties) {
 419                ret = -EINVAL;
 420                goto out_unref;
 421        }
 422
 423        ret = drm_mode_object_get_properties(obj, file_priv->atomic,
 424                        (uint32_t __user *)(unsigned long)(arg->props_ptr),
 425                        (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
 426                        &arg->count_props);
 427
 428out_unref:
 429        drm_mode_object_put(obj);
 430out:
 431        DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 432        return ret;
 433}
 434
 435struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
 436                                               uint32_t prop_id)
 437{
 438        int i;
 439
 440        for (i = 0; i < obj->properties->count; i++)
 441                if (obj->properties->properties[i]->base.id == prop_id)
 442                        return obj->properties->properties[i];
 443
 444        return NULL;
 445}
 446
 447static int set_property_legacy(struct drm_mode_object *obj,
 448                               struct drm_property *prop,
 449                               uint64_t prop_value)
 450{
 451        struct drm_device *dev = prop->dev;
 452        struct drm_mode_object *ref;
 453        struct drm_modeset_acquire_ctx ctx;
 454        int ret = -EINVAL;
 455
 456        if (!drm_property_change_valid_get(prop, prop_value, &ref))
 457                return -EINVAL;
 458
 459        DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
 460        switch (obj->type) {
 461        case DRM_MODE_OBJECT_CONNECTOR:
 462                ret = drm_connector_set_obj_prop(obj, prop, prop_value);
 463                break;
 464        case DRM_MODE_OBJECT_CRTC:
 465                ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
 466                break;
 467        case DRM_MODE_OBJECT_PLANE:
 468                ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
 469                                                  prop, prop_value);
 470                break;
 471        }
 472        drm_property_change_valid_put(prop, ref);
 473        DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 474
 475        return ret;
 476}
 477
 478static int set_property_atomic(struct drm_mode_object *obj,
 479                               struct drm_file *file_priv,
 480                               struct drm_property *prop,
 481                               uint64_t prop_value)
 482{
 483        struct drm_device *dev = prop->dev;
 484        struct drm_atomic_state *state;
 485        struct drm_modeset_acquire_ctx ctx;
 486        int ret;
 487
 488        state = drm_atomic_state_alloc(dev);
 489        if (!state)
 490                return -ENOMEM;
 491
 492        drm_modeset_acquire_init(&ctx, 0);
 493        state->acquire_ctx = &ctx;
 494
 495retry:
 496        if (prop == state->dev->mode_config.dpms_property) {
 497                if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
 498                        ret = -EINVAL;
 499                        goto out;
 500                }
 501
 502                ret = drm_atomic_connector_commit_dpms(state,
 503                                                       obj_to_connector(obj),
 504                                                       prop_value);
 505        } else {
 506                ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
 507                if (ret)
 508                        goto out;
 509                ret = drm_atomic_commit(state);
 510        }
 511out:
 512        if (ret == -EDEADLK) {
 513                drm_atomic_state_clear(state);
 514                drm_modeset_backoff(&ctx);
 515                goto retry;
 516        }
 517
 518        drm_atomic_state_put(state);
 519
 520        drm_modeset_drop_locks(&ctx);
 521        drm_modeset_acquire_fini(&ctx);
 522
 523        return ret;
 524}
 525
 526int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 527                                    struct drm_file *file_priv)
 528{
 529        struct drm_mode_obj_set_property *arg = data;
 530        struct drm_mode_object *arg_obj;
 531        struct drm_property *property;
 532        int ret = -EINVAL;
 533
 534        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 535                return -EOPNOTSUPP;
 536
 537        arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
 538        if (!arg_obj)
 539                return -ENOENT;
 540
 541        if (!arg_obj->properties)
 542                goto out_unref;
 543
 544        property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
 545        if (!property)
 546                goto out_unref;
 547
 548        if (drm_drv_uses_atomic_modeset(property->dev))
 549                ret = set_property_atomic(arg_obj, file_priv, property, arg->value);
 550        else
 551                ret = set_property_legacy(arg_obj, property, arg->value);
 552
 553out_unref:
 554        drm_mode_object_put(arg_obj);
 555        return ret;
 556}
 557