linux/drivers/gpu/drm/drm_modeset_lock.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014 Red Hat
   3 * Author: Rob Clark <robdclark@gmail.com>
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a
   6 * copy of this software and associated documentation files (the "Software"),
   7 * to deal in the Software without restriction, including without limitation
   8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   9 * and/or sell copies of the Software, and to permit persons to whom the
  10 * Software is furnished to do so, subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice shall be included in
  13 * all copies or substantial portions of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21 * OTHER DEALINGS IN THE SOFTWARE.
  22 */
  23
  24#include <drm/drm_atomic.h>
  25#include <drm/drm_crtc.h>
  26#include <drm/drm_device.h>
  27#include <drm/drm_modeset_lock.h>
  28
  29/**
  30 * DOC: kms locking
  31 *
  32 * As KMS moves toward more fine grained locking, and atomic ioctl where
  33 * userspace can indirectly control locking order, it becomes necessary
  34 * to use &ww_mutex and acquire-contexts to avoid deadlocks.  But because
  35 * the locking is more distributed around the driver code, we want a bit
  36 * of extra utility/tracking out of our acquire-ctx.  This is provided
  37 * by &struct drm_modeset_lock and &struct drm_modeset_acquire_ctx.
  38 *
  39 * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.rst
  40 *
  41 * The basic usage pattern is to::
  42 *
  43 *     drm_modeset_acquire_init(ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
  44 *     retry:
  45 *     foreach (lock in random_ordered_set_of_locks) {
  46 *         ret = drm_modeset_lock(lock, ctx)
  47 *         if (ret == -EDEADLK) {
  48 *             ret = drm_modeset_backoff(ctx);
  49 *             if (!ret)
  50 *                 goto retry;
  51 *         }
  52 *         if (ret)
  53 *             goto out;
  54 *     }
  55 *     ... do stuff ...
  56 *     out:
  57 *     drm_modeset_drop_locks(ctx);
  58 *     drm_modeset_acquire_fini(ctx);
  59 *
  60 * For convenience this control flow is implemented in
  61 * DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() for the case
  62 * where all modeset locks need to be taken through drm_modeset_lock_all_ctx().
  63 *
  64 * If all that is needed is a single modeset lock, then the &struct
  65 * drm_modeset_acquire_ctx is not needed and the locking can be simplified
  66 * by passing a NULL instead of ctx in the drm_modeset_lock() call or
  67 * calling  drm_modeset_lock_single_interruptible(). To unlock afterwards
  68 * call drm_modeset_unlock().
  69 *
  70 * On top of these per-object locks using &ww_mutex there's also an overall
  71 * &drm_mode_config.mutex, for protecting everything else. Mostly this means
  72 * probe state of connectors, and preventing hotplug add/removal of connectors.
  73 *
  74 * Finally there's a bunch of dedicated locks to protect drm core internal
  75 * lists and lookup data structures.
  76 */
  77
  78static DEFINE_WW_CLASS(crtc_ww_class);
  79
  80/**
  81 * drm_modeset_lock_all - take all modeset locks
  82 * @dev: DRM device
  83 *
  84 * This function takes all modeset locks, suitable where a more fine-grained
  85 * scheme isn't (yet) implemented. Locks must be dropped by calling the
  86 * drm_modeset_unlock_all() function.
  87 *
  88 * This function is deprecated. It allocates a lock acquisition context and
  89 * stores it in &drm_device.mode_config. This facilitate conversion of
  90 * existing code because it removes the need to manually deal with the
  91 * acquisition context, but it is also brittle because the context is global
  92 * and care must be taken not to nest calls. New code should use the
  93 * drm_modeset_lock_all_ctx() function and pass in the context explicitly.
  94 */
  95void drm_modeset_lock_all(struct drm_device *dev)
  96{
  97        struct drm_mode_config *config = &dev->mode_config;
  98        struct drm_modeset_acquire_ctx *ctx;
  99        int ret;
 100
 101        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
 102        if (WARN_ON(!ctx))
 103                return;
 104
 105        mutex_lock(&config->mutex);
 106
 107        drm_modeset_acquire_init(ctx, 0);
 108
 109retry:
 110        ret = drm_modeset_lock_all_ctx(dev, ctx);
 111        if (ret < 0) {
 112                if (ret == -EDEADLK) {
 113                        drm_modeset_backoff(ctx);
 114                        goto retry;
 115                }
 116
 117                drm_modeset_acquire_fini(ctx);
 118                kfree(ctx);
 119                return;
 120        }
 121        ww_acquire_done(&ctx->ww_ctx);
 122
 123        WARN_ON(config->acquire_ctx);
 124
 125        /*
 126         * We hold the locks now, so it is safe to stash the acquisition
 127         * context for drm_modeset_unlock_all().
 128         */
 129        config->acquire_ctx = ctx;
 130
 131        drm_warn_on_modeset_not_all_locked(dev);
 132}
 133EXPORT_SYMBOL(drm_modeset_lock_all);
 134
 135/**
 136 * drm_modeset_unlock_all - drop all modeset locks
 137 * @dev: DRM device
 138 *
 139 * This function drops all modeset locks taken by a previous call to the
 140 * drm_modeset_lock_all() function.
 141 *
 142 * This function is deprecated. It uses the lock acquisition context stored
 143 * in &drm_device.mode_config. This facilitates conversion of existing
 144 * code because it removes the need to manually deal with the acquisition
 145 * context, but it is also brittle because the context is global and care must
 146 * be taken not to nest calls. New code should pass the acquisition context
 147 * directly to the drm_modeset_drop_locks() function.
 148 */
 149void drm_modeset_unlock_all(struct drm_device *dev)
 150{
 151        struct drm_mode_config *config = &dev->mode_config;
 152        struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
 153
 154        if (WARN_ON(!ctx))
 155                return;
 156
 157        config->acquire_ctx = NULL;
 158        drm_modeset_drop_locks(ctx);
 159        drm_modeset_acquire_fini(ctx);
 160
 161        kfree(ctx);
 162
 163        mutex_unlock(&dev->mode_config.mutex);
 164}
 165EXPORT_SYMBOL(drm_modeset_unlock_all);
 166
 167/**
 168 * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
 169 * @dev: device
 170 *
 171 * Useful as a debug assert.
 172 */
 173void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
 174{
 175        struct drm_crtc *crtc;
 176
 177        /* Locking is currently fubar in the panic handler. */
 178        if (oops_in_progress)
 179                return;
 180
 181        drm_for_each_crtc(crtc, dev)
 182                WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 183
 184        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
 185        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 186}
 187EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
 188
 189/**
 190 * drm_modeset_acquire_init - initialize acquire context
 191 * @ctx: the acquire context
 192 * @flags: 0 or %DRM_MODESET_ACQUIRE_INTERRUPTIBLE
 193 *
 194 * When passing %DRM_MODESET_ACQUIRE_INTERRUPTIBLE to @flags,
 195 * all calls to drm_modeset_lock() will perform an interruptible
 196 * wait.
 197 */
 198void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
 199                uint32_t flags)
 200{
 201        memset(ctx, 0, sizeof(*ctx));
 202        ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class);
 203        INIT_LIST_HEAD(&ctx->locked);
 204
 205        if (flags & DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
 206                ctx->interruptible = true;
 207}
 208EXPORT_SYMBOL(drm_modeset_acquire_init);
 209
 210/**
 211 * drm_modeset_acquire_fini - cleanup acquire context
 212 * @ctx: the acquire context
 213 */
 214void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)
 215{
 216        ww_acquire_fini(&ctx->ww_ctx);
 217}
 218EXPORT_SYMBOL(drm_modeset_acquire_fini);
 219
 220/**
 221 * drm_modeset_drop_locks - drop all locks
 222 * @ctx: the acquire context
 223 *
 224 * Drop all locks currently held against this acquire context.
 225 */
 226void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)
 227{
 228        WARN_ON(ctx->contended);
 229        while (!list_empty(&ctx->locked)) {
 230                struct drm_modeset_lock *lock;
 231
 232                lock = list_first_entry(&ctx->locked,
 233                                struct drm_modeset_lock, head);
 234
 235                drm_modeset_unlock(lock);
 236        }
 237}
 238EXPORT_SYMBOL(drm_modeset_drop_locks);
 239
 240static inline int modeset_lock(struct drm_modeset_lock *lock,
 241                struct drm_modeset_acquire_ctx *ctx,
 242                bool interruptible, bool slow)
 243{
 244        int ret;
 245
 246        WARN_ON(ctx->contended);
 247
 248        if (ctx->trylock_only) {
 249                lockdep_assert_held(&ctx->ww_ctx);
 250
 251                if (!ww_mutex_trylock(&lock->mutex))
 252                        return -EBUSY;
 253                else
 254                        return 0;
 255        } else if (interruptible && slow) {
 256                ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
 257        } else if (interruptible) {
 258                ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
 259        } else if (slow) {
 260                ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx);
 261                ret = 0;
 262        } else {
 263                ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx);
 264        }
 265        if (!ret) {
 266                WARN_ON(!list_empty(&lock->head));
 267                list_add(&lock->head, &ctx->locked);
 268        } else if (ret == -EALREADY) {
 269                /* we already hold the lock.. this is fine.  For atomic
 270                 * we will need to be able to drm_modeset_lock() things
 271                 * without having to keep track of what is already locked
 272                 * or not.
 273                 */
 274                ret = 0;
 275        } else if (ret == -EDEADLK) {
 276                ctx->contended = lock;
 277        }
 278
 279        return ret;
 280}
 281
 282/**
 283 * drm_modeset_backoff - deadlock avoidance backoff
 284 * @ctx: the acquire context
 285 *
 286 * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK),
 287 * you must call this function to drop all currently held locks and
 288 * block until the contended lock becomes available.
 289 *
 290 * This function returns 0 on success, or -ERESTARTSYS if this context
 291 * is initialized with %DRM_MODESET_ACQUIRE_INTERRUPTIBLE and the
 292 * wait has been interrupted.
 293 */
 294int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
 295{
 296        struct drm_modeset_lock *contended = ctx->contended;
 297
 298        ctx->contended = NULL;
 299
 300        if (WARN_ON(!contended))
 301                return 0;
 302
 303        drm_modeset_drop_locks(ctx);
 304
 305        return modeset_lock(contended, ctx, ctx->interruptible, true);
 306}
 307EXPORT_SYMBOL(drm_modeset_backoff);
 308
 309/**
 310 * drm_modeset_lock_init - initialize lock
 311 * @lock: lock to init
 312 */
 313void drm_modeset_lock_init(struct drm_modeset_lock *lock)
 314{
 315        ww_mutex_init(&lock->mutex, &crtc_ww_class);
 316        INIT_LIST_HEAD(&lock->head);
 317}
 318EXPORT_SYMBOL(drm_modeset_lock_init);
 319
 320/**
 321 * drm_modeset_lock - take modeset lock
 322 * @lock: lock to take
 323 * @ctx: acquire ctx
 324 *
 325 * If @ctx is not NULL, then its ww acquire context is used and the
 326 * lock will be tracked by the context and can be released by calling
 327 * drm_modeset_drop_locks().  If -EDEADLK is returned, this means a
 328 * deadlock scenario has been detected and it is an error to attempt
 329 * to take any more locks without first calling drm_modeset_backoff().
 330 *
 331 * If the @ctx is not NULL and initialized with
 332 * %DRM_MODESET_ACQUIRE_INTERRUPTIBLE, this function will fail with
 333 * -ERESTARTSYS when interrupted.
 334 *
 335 * If @ctx is NULL then the function call behaves like a normal,
 336 * uninterruptible non-nesting mutex_lock() call.
 337 */
 338int drm_modeset_lock(struct drm_modeset_lock *lock,
 339                struct drm_modeset_acquire_ctx *ctx)
 340{
 341        if (ctx)
 342                return modeset_lock(lock, ctx, ctx->interruptible, false);
 343
 344        ww_mutex_lock(&lock->mutex, NULL);
 345        return 0;
 346}
 347EXPORT_SYMBOL(drm_modeset_lock);
 348
 349/**
 350 * drm_modeset_lock_single_interruptible - take a single modeset lock
 351 * @lock: lock to take
 352 *
 353 * This function behaves as drm_modeset_lock() with a NULL context,
 354 * but performs interruptible waits.
 355 *
 356 * This function returns 0 on success, or -ERESTARTSYS when interrupted.
 357 */
 358int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock)
 359{
 360        return ww_mutex_lock_interruptible(&lock->mutex, NULL);
 361}
 362EXPORT_SYMBOL(drm_modeset_lock_single_interruptible);
 363
 364/**
 365 * drm_modeset_unlock - drop modeset lock
 366 * @lock: lock to release
 367 */
 368void drm_modeset_unlock(struct drm_modeset_lock *lock)
 369{
 370        list_del_init(&lock->head);
 371        ww_mutex_unlock(&lock->mutex);
 372}
 373EXPORT_SYMBOL(drm_modeset_unlock);
 374
 375/**
 376 * drm_modeset_lock_all_ctx - take all modeset locks
 377 * @dev: DRM device
 378 * @ctx: lock acquisition context
 379 *
 380 * This function takes all modeset locks, suitable where a more fine-grained
 381 * scheme isn't (yet) implemented.
 382 *
 383 * Unlike drm_modeset_lock_all(), it doesn't take the &drm_mode_config.mutex
 384 * since that lock isn't required for modeset state changes. Callers which
 385 * need to grab that lock too need to do so outside of the acquire context
 386 * @ctx.
 387 *
 388 * Locks acquired with this function should be released by calling the
 389 * drm_modeset_drop_locks() function on @ctx.
 390 *
 391 * See also: DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END()
 392 *
 393 * Returns: 0 on success or a negative error-code on failure.
 394 */
 395int drm_modeset_lock_all_ctx(struct drm_device *dev,
 396                             struct drm_modeset_acquire_ctx *ctx)
 397{
 398        struct drm_private_obj *privobj;
 399        struct drm_crtc *crtc;
 400        struct drm_plane *plane;
 401        int ret;
 402
 403        ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
 404        if (ret)
 405                return ret;
 406
 407        drm_for_each_crtc(crtc, dev) {
 408                ret = drm_modeset_lock(&crtc->mutex, ctx);
 409                if (ret)
 410                        return ret;
 411        }
 412
 413        drm_for_each_plane(plane, dev) {
 414                ret = drm_modeset_lock(&plane->mutex, ctx);
 415                if (ret)
 416                        return ret;
 417        }
 418
 419        drm_for_each_privobj(privobj, dev) {
 420                ret = drm_modeset_lock(&privobj->lock, ctx);
 421                if (ret)
 422                        return ret;
 423        }
 424
 425        return 0;
 426}
 427EXPORT_SYMBOL(drm_modeset_lock_all_ctx);
 428