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