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