151fd371bSRob Clark /* 251fd371bSRob Clark * Copyright (C) 2014 Red Hat 351fd371bSRob Clark * Author: Rob Clark <robdclark@gmail.com> 451fd371bSRob Clark * 551fd371bSRob Clark * Permission is hereby granted, free of charge, to any person obtaining a 651fd371bSRob Clark * copy of this software and associated documentation files (the "Software"), 751fd371bSRob Clark * to deal in the Software without restriction, including without limitation 851fd371bSRob Clark * the rights to use, copy, modify, merge, publish, distribute, sublicense, 951fd371bSRob Clark * and/or sell copies of the Software, and to permit persons to whom the 1051fd371bSRob Clark * Software is furnished to do so, subject to the following conditions: 1151fd371bSRob Clark * 1251fd371bSRob Clark * The above copyright notice and this permission notice shall be included in 1351fd371bSRob Clark * all copies or substantial portions of the Software. 1451fd371bSRob Clark * 1551fd371bSRob Clark * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1651fd371bSRob Clark * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1751fd371bSRob Clark * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1851fd371bSRob Clark * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1951fd371bSRob Clark * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2051fd371bSRob Clark * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2151fd371bSRob Clark * OTHER DEALINGS IN THE SOFTWARE. 2251fd371bSRob Clark */ 2351fd371bSRob Clark 2451fd371bSRob Clark #include <drm/drmP.h> 2551fd371bSRob Clark #include <drm/drm_crtc.h> 2651fd371bSRob Clark #include <drm/drm_modeset_lock.h> 2751fd371bSRob Clark 2851fd371bSRob Clark /** 2951fd371bSRob Clark * DOC: kms locking 3051fd371bSRob Clark * 3151fd371bSRob Clark * As KMS moves toward more fine grained locking, and atomic ioctl where 3251fd371bSRob Clark * userspace can indirectly control locking order, it becomes necessary 3351fd371bSRob Clark * to use ww_mutex and acquire-contexts to avoid deadlocks. But because 3451fd371bSRob Clark * the locking is more distributed around the driver code, we want a bit 3551fd371bSRob Clark * of extra utility/tracking out of our acquire-ctx. This is provided 3651fd371bSRob Clark * by drm_modeset_lock / drm_modeset_acquire_ctx. 3751fd371bSRob Clark * 3851fd371bSRob Clark * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt 3951fd371bSRob Clark * 4051fd371bSRob Clark * The basic usage pattern is to: 4151fd371bSRob Clark * 4251fd371bSRob Clark * drm_modeset_acquire_init(&ctx) 4351fd371bSRob Clark * retry: 4451fd371bSRob Clark * foreach (lock in random_ordered_set_of_locks) { 4551fd371bSRob Clark * ret = drm_modeset_lock(lock, &ctx) 4651fd371bSRob Clark * if (ret == -EDEADLK) { 4751fd371bSRob Clark * drm_modeset_backoff(&ctx); 4851fd371bSRob Clark * goto retry; 4951fd371bSRob Clark * } 5051fd371bSRob Clark * } 5151fd371bSRob Clark * 5251fd371bSRob Clark * ... do stuff ... 5351fd371bSRob Clark * 5451fd371bSRob Clark * drm_modeset_drop_locks(&ctx); 5551fd371bSRob Clark * drm_modeset_acquire_fini(&ctx); 5651fd371bSRob Clark */ 5751fd371bSRob Clark 5851fd371bSRob Clark 5951fd371bSRob Clark /** 60cb597bb3SDaniel Vetter * __drm_modeset_lock_all - internal helper to grab all modeset locks 61cb597bb3SDaniel Vetter * @dev: DRM device 62cb597bb3SDaniel Vetter * @trylock: trylock mode for atomic contexts 63a6a8bb84SDaniel Vetter * 64cb597bb3SDaniel Vetter * This is a special version of drm_modeset_lock_all() which can also be used in 65cb597bb3SDaniel Vetter * atomic contexts. Then @trylock must be set to true. 66cb597bb3SDaniel Vetter * 67cb597bb3SDaniel Vetter * Returns: 68cb597bb3SDaniel Vetter * 0 on success or negative error code on failure. 69a6a8bb84SDaniel Vetter */ 70cb597bb3SDaniel Vetter int __drm_modeset_lock_all(struct drm_device *dev, 71cb597bb3SDaniel Vetter bool trylock) 72a6a8bb84SDaniel Vetter { 73a6a8bb84SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 74a6a8bb84SDaniel Vetter struct drm_modeset_acquire_ctx *ctx; 75a6a8bb84SDaniel Vetter int ret; 76a6a8bb84SDaniel Vetter 77cb597bb3SDaniel Vetter ctx = kzalloc(sizeof(*ctx), 78cb597bb3SDaniel Vetter trylock ? GFP_ATOMIC : GFP_KERNEL); 79cb597bb3SDaniel Vetter if (!ctx) 80cb597bb3SDaniel Vetter return -ENOMEM; 81a6a8bb84SDaniel Vetter 82cb597bb3SDaniel Vetter if (trylock) { 83cb597bb3SDaniel Vetter if (!mutex_trylock(&config->mutex)) 84cb597bb3SDaniel Vetter return -EBUSY; 85cb597bb3SDaniel Vetter } else { 86a6a8bb84SDaniel Vetter mutex_lock(&config->mutex); 87cb597bb3SDaniel Vetter } 88a6a8bb84SDaniel Vetter 89a6a8bb84SDaniel Vetter drm_modeset_acquire_init(ctx, 0); 90cb597bb3SDaniel Vetter ctx->trylock_only = trylock; 91a6a8bb84SDaniel Vetter 92a6a8bb84SDaniel Vetter retry: 93a6a8bb84SDaniel Vetter ret = drm_modeset_lock(&config->connection_mutex, ctx); 94a6a8bb84SDaniel Vetter if (ret) 95a6a8bb84SDaniel Vetter goto fail; 96a6a8bb84SDaniel Vetter ret = drm_modeset_lock_all_crtcs(dev, ctx); 97a6a8bb84SDaniel Vetter if (ret) 98a6a8bb84SDaniel Vetter goto fail; 99a6a8bb84SDaniel Vetter 100a6a8bb84SDaniel Vetter WARN_ON(config->acquire_ctx); 101a6a8bb84SDaniel Vetter 102a6a8bb84SDaniel Vetter /* now we hold the locks, so now that it is safe, stash the 103a6a8bb84SDaniel Vetter * ctx for drm_modeset_unlock_all(): 104a6a8bb84SDaniel Vetter */ 105a6a8bb84SDaniel Vetter config->acquire_ctx = ctx; 106a6a8bb84SDaniel Vetter 107a6a8bb84SDaniel Vetter drm_warn_on_modeset_not_all_locked(dev); 108a6a8bb84SDaniel Vetter 109cb597bb3SDaniel Vetter return 0; 110a6a8bb84SDaniel Vetter 111a6a8bb84SDaniel Vetter fail: 112a6a8bb84SDaniel Vetter if (ret == -EDEADLK) { 113a6a8bb84SDaniel Vetter drm_modeset_backoff(ctx); 114a6a8bb84SDaniel Vetter goto retry; 115a6a8bb84SDaniel Vetter } 116cb597bb3SDaniel Vetter 117cb597bb3SDaniel Vetter return ret; 118cb597bb3SDaniel Vetter } 119cb597bb3SDaniel Vetter EXPORT_SYMBOL(__drm_modeset_lock_all); 120cb597bb3SDaniel Vetter 121cb597bb3SDaniel Vetter /** 122cb597bb3SDaniel Vetter * drm_modeset_lock_all - take all modeset locks 123cb597bb3SDaniel Vetter * @dev: drm device 124cb597bb3SDaniel Vetter * 125cb597bb3SDaniel Vetter * This function takes all modeset locks, suitable where a more fine-grained 126cb597bb3SDaniel Vetter * scheme isn't (yet) implemented. Locks must be dropped with 127cb597bb3SDaniel Vetter * drm_modeset_unlock_all. 128cb597bb3SDaniel Vetter */ 129cb597bb3SDaniel Vetter void drm_modeset_lock_all(struct drm_device *dev) 130cb597bb3SDaniel Vetter { 131cb597bb3SDaniel Vetter WARN_ON(__drm_modeset_lock_all(dev, false) != 0); 132a6a8bb84SDaniel Vetter } 133a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_all); 134a6a8bb84SDaniel Vetter 135a6a8bb84SDaniel Vetter /** 136a6a8bb84SDaniel Vetter * drm_modeset_unlock_all - drop all modeset locks 137a6a8bb84SDaniel Vetter * @dev: device 138a6a8bb84SDaniel Vetter * 139a6a8bb84SDaniel Vetter * This function drop all modeset locks taken by drm_modeset_lock_all. 140a6a8bb84SDaniel Vetter */ 141a6a8bb84SDaniel Vetter void drm_modeset_unlock_all(struct drm_device *dev) 142a6a8bb84SDaniel Vetter { 143a6a8bb84SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 144a6a8bb84SDaniel Vetter struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; 145a6a8bb84SDaniel Vetter 146a6a8bb84SDaniel Vetter if (WARN_ON(!ctx)) 147a6a8bb84SDaniel Vetter return; 148a6a8bb84SDaniel Vetter 149a6a8bb84SDaniel Vetter config->acquire_ctx = NULL; 150a6a8bb84SDaniel Vetter drm_modeset_drop_locks(ctx); 151a6a8bb84SDaniel Vetter drm_modeset_acquire_fini(ctx); 152a6a8bb84SDaniel Vetter 153a6a8bb84SDaniel Vetter kfree(ctx); 154a6a8bb84SDaniel Vetter 155a6a8bb84SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 156a6a8bb84SDaniel Vetter } 157a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_all); 158a6a8bb84SDaniel Vetter 159a6a8bb84SDaniel Vetter /** 160d059f652SDaniel Vetter * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx 161d059f652SDaniel Vetter * @crtc: drm crtc 162d059f652SDaniel Vetter * 163d059f652SDaniel Vetter * This function locks the given crtc using a hidden acquire context. This is 164d059f652SDaniel Vetter * necessary so that drivers internally using the atomic interfaces can grab 165d059f652SDaniel Vetter * further locks with the lock acquire context. 166d059f652SDaniel Vetter */ 167d059f652SDaniel Vetter void drm_modeset_lock_crtc(struct drm_crtc *crtc) 168d059f652SDaniel Vetter { 169d059f652SDaniel Vetter struct drm_modeset_acquire_ctx *ctx; 170d059f652SDaniel Vetter int ret; 171d059f652SDaniel Vetter 172d059f652SDaniel Vetter ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 173d059f652SDaniel Vetter if (WARN_ON(!ctx)) 174d059f652SDaniel Vetter return; 175d059f652SDaniel Vetter 176d059f652SDaniel Vetter drm_modeset_acquire_init(ctx, 0); 177d059f652SDaniel Vetter 178d059f652SDaniel Vetter retry: 179d059f652SDaniel Vetter ret = drm_modeset_lock(&crtc->mutex, ctx); 180d059f652SDaniel Vetter if (ret) 181d059f652SDaniel Vetter goto fail; 182d059f652SDaniel Vetter 183d059f652SDaniel Vetter WARN_ON(crtc->acquire_ctx); 184d059f652SDaniel Vetter 185d059f652SDaniel Vetter /* now we hold the locks, so now that it is safe, stash the 186d059f652SDaniel Vetter * ctx for drm_modeset_unlock_crtc(): 187d059f652SDaniel Vetter */ 188d059f652SDaniel Vetter crtc->acquire_ctx = ctx; 189d059f652SDaniel Vetter 190d059f652SDaniel Vetter return; 191d059f652SDaniel Vetter 192d059f652SDaniel Vetter fail: 193d059f652SDaniel Vetter if (ret == -EDEADLK) { 194d059f652SDaniel Vetter drm_modeset_backoff(ctx); 195d059f652SDaniel Vetter goto retry; 196d059f652SDaniel Vetter } 197d059f652SDaniel Vetter } 198d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_crtc); 199d059f652SDaniel Vetter 200d059f652SDaniel Vetter /** 201d059f652SDaniel Vetter * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls 202295ee853SDaniel Vetter * @crtc: drm crtc 203d059f652SDaniel Vetter * 204d059f652SDaniel Vetter * Legacy ioctl operations like cursor updates or page flips only have per-crtc 205d059f652SDaniel Vetter * locking, and store the acquire ctx in the corresponding crtc. All other 206d059f652SDaniel Vetter * legacy operations take all locks and use a global acquire context. This 207d059f652SDaniel Vetter * function grabs the right one. 208d059f652SDaniel Vetter */ 209d059f652SDaniel Vetter struct drm_modeset_acquire_ctx * 210d059f652SDaniel Vetter drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) 211d059f652SDaniel Vetter { 212d059f652SDaniel Vetter if (crtc->acquire_ctx) 213d059f652SDaniel Vetter return crtc->acquire_ctx; 214d059f652SDaniel Vetter 215d059f652SDaniel Vetter WARN_ON(!crtc->dev->mode_config.acquire_ctx); 216d059f652SDaniel Vetter 217d059f652SDaniel Vetter return crtc->dev->mode_config.acquire_ctx; 218d059f652SDaniel Vetter } 219d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); 220d059f652SDaniel Vetter 221d059f652SDaniel Vetter /** 222d059f652SDaniel Vetter * drm_modeset_unlock_crtc - drop crtc lock 223d059f652SDaniel Vetter * @crtc: drm crtc 224d059f652SDaniel Vetter * 225d059f652SDaniel Vetter * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other 226d059f652SDaniel Vetter * locks acquired through the hidden context. 227d059f652SDaniel Vetter */ 228d059f652SDaniel Vetter void drm_modeset_unlock_crtc(struct drm_crtc *crtc) 229d059f652SDaniel Vetter { 230d059f652SDaniel Vetter struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; 231d059f652SDaniel Vetter 232d059f652SDaniel Vetter if (WARN_ON(!ctx)) 233d059f652SDaniel Vetter return; 234d059f652SDaniel Vetter 235d059f652SDaniel Vetter crtc->acquire_ctx = NULL; 236d059f652SDaniel Vetter drm_modeset_drop_locks(ctx); 237d059f652SDaniel Vetter drm_modeset_acquire_fini(ctx); 238d059f652SDaniel Vetter 239d059f652SDaniel Vetter kfree(ctx); 240d059f652SDaniel Vetter } 241d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_crtc); 242d059f652SDaniel Vetter 243d059f652SDaniel Vetter /** 244a6a8bb84SDaniel Vetter * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked 245a6a8bb84SDaniel Vetter * @dev: device 246a6a8bb84SDaniel Vetter * 247a6a8bb84SDaniel Vetter * Useful as a debug assert. 248a6a8bb84SDaniel Vetter */ 249a6a8bb84SDaniel Vetter void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) 250a6a8bb84SDaniel Vetter { 251a6a8bb84SDaniel Vetter struct drm_crtc *crtc; 252a6a8bb84SDaniel Vetter 253a6a8bb84SDaniel Vetter /* Locking is currently fubar in the panic handler. */ 254a6a8bb84SDaniel Vetter if (oops_in_progress) 255a6a8bb84SDaniel Vetter return; 256a6a8bb84SDaniel Vetter 257a6a8bb84SDaniel Vetter list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 258a6a8bb84SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 259a6a8bb84SDaniel Vetter 260a6a8bb84SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 261a6a8bb84SDaniel Vetter WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 262a6a8bb84SDaniel Vetter } 263a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); 264a6a8bb84SDaniel Vetter 265a6a8bb84SDaniel Vetter /** 26651fd371bSRob Clark * drm_modeset_acquire_init - initialize acquire context 26751fd371bSRob Clark * @ctx: the acquire context 26851fd371bSRob Clark * @flags: for future 26951fd371bSRob Clark */ 27051fd371bSRob Clark void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 27151fd371bSRob Clark uint32_t flags) 27251fd371bSRob Clark { 273fb54918aSRob Clark memset(ctx, 0, sizeof(*ctx)); 27451fd371bSRob Clark ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); 27551fd371bSRob Clark INIT_LIST_HEAD(&ctx->locked); 27651fd371bSRob Clark } 27751fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_acquire_init); 27851fd371bSRob Clark 27951fd371bSRob Clark /** 28051fd371bSRob Clark * drm_modeset_acquire_fini - cleanup acquire context 28151fd371bSRob Clark * @ctx: the acquire context 28251fd371bSRob Clark */ 28351fd371bSRob Clark void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) 28451fd371bSRob Clark { 28551fd371bSRob Clark ww_acquire_fini(&ctx->ww_ctx); 28651fd371bSRob Clark } 28751fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_acquire_fini); 28851fd371bSRob Clark 28951fd371bSRob Clark /** 29051fd371bSRob Clark * drm_modeset_drop_locks - drop all locks 29151fd371bSRob Clark * @ctx: the acquire context 29251fd371bSRob Clark * 29351fd371bSRob Clark * Drop all locks currently held against this acquire context. 29451fd371bSRob Clark */ 29551fd371bSRob Clark void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) 29651fd371bSRob Clark { 29751fd371bSRob Clark WARN_ON(ctx->contended); 29851fd371bSRob Clark while (!list_empty(&ctx->locked)) { 29951fd371bSRob Clark struct drm_modeset_lock *lock; 30051fd371bSRob Clark 30151fd371bSRob Clark lock = list_first_entry(&ctx->locked, 30251fd371bSRob Clark struct drm_modeset_lock, head); 30351fd371bSRob Clark 30451fd371bSRob Clark drm_modeset_unlock(lock); 30551fd371bSRob Clark } 30651fd371bSRob Clark } 30751fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_drop_locks); 30851fd371bSRob Clark 30951fd371bSRob Clark static inline int modeset_lock(struct drm_modeset_lock *lock, 31051fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx, 31151fd371bSRob Clark bool interruptible, bool slow) 31251fd371bSRob Clark { 31351fd371bSRob Clark int ret; 31451fd371bSRob Clark 31551fd371bSRob Clark WARN_ON(ctx->contended); 31651fd371bSRob Clark 317cb597bb3SDaniel Vetter if (ctx->trylock_only) { 318cb597bb3SDaniel Vetter if (!ww_mutex_trylock(&lock->mutex)) 319cb597bb3SDaniel Vetter return -EBUSY; 320cb597bb3SDaniel Vetter else 321cb597bb3SDaniel Vetter return 0; 322cb597bb3SDaniel Vetter } else if (interruptible && slow) { 32351fd371bSRob Clark ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); 32451fd371bSRob Clark } else if (interruptible) { 32551fd371bSRob Clark ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); 32651fd371bSRob Clark } else if (slow) { 32751fd371bSRob Clark ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx); 32851fd371bSRob Clark ret = 0; 32951fd371bSRob Clark } else { 33051fd371bSRob Clark ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx); 33151fd371bSRob Clark } 33251fd371bSRob Clark if (!ret) { 33351fd371bSRob Clark WARN_ON(!list_empty(&lock->head)); 33451fd371bSRob Clark list_add(&lock->head, &ctx->locked); 33551fd371bSRob Clark } else if (ret == -EALREADY) { 33651fd371bSRob Clark /* we already hold the lock.. this is fine. For atomic 33751fd371bSRob Clark * we will need to be able to drm_modeset_lock() things 33851fd371bSRob Clark * without having to keep track of what is already locked 33951fd371bSRob Clark * or not. 34051fd371bSRob Clark */ 34151fd371bSRob Clark ret = 0; 34251fd371bSRob Clark } else if (ret == -EDEADLK) { 34351fd371bSRob Clark ctx->contended = lock; 34451fd371bSRob Clark } 34551fd371bSRob Clark 34651fd371bSRob Clark return ret; 34751fd371bSRob Clark } 34851fd371bSRob Clark 34951fd371bSRob Clark static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, 35051fd371bSRob Clark bool interruptible) 35151fd371bSRob Clark { 35251fd371bSRob Clark struct drm_modeset_lock *contended = ctx->contended; 35351fd371bSRob Clark 35451fd371bSRob Clark ctx->contended = NULL; 35551fd371bSRob Clark 35651fd371bSRob Clark if (WARN_ON(!contended)) 35751fd371bSRob Clark return 0; 35851fd371bSRob Clark 35951fd371bSRob Clark drm_modeset_drop_locks(ctx); 36051fd371bSRob Clark 36151fd371bSRob Clark return modeset_lock(contended, ctx, interruptible, true); 36251fd371bSRob Clark } 36351fd371bSRob Clark 36451fd371bSRob Clark /** 36551fd371bSRob Clark * drm_modeset_backoff - deadlock avoidance backoff 36651fd371bSRob Clark * @ctx: the acquire context 36751fd371bSRob Clark * 36851fd371bSRob Clark * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK), 36951fd371bSRob Clark * you must call this function to drop all currently held locks and 37051fd371bSRob Clark * block until the contended lock becomes available. 37151fd371bSRob Clark */ 37251fd371bSRob Clark void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) 37351fd371bSRob Clark { 37451fd371bSRob Clark modeset_backoff(ctx, false); 37551fd371bSRob Clark } 37651fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_backoff); 37751fd371bSRob Clark 37851fd371bSRob Clark /** 37951fd371bSRob Clark * drm_modeset_backoff_interruptible - deadlock avoidance backoff 38051fd371bSRob Clark * @ctx: the acquire context 38151fd371bSRob Clark * 38251fd371bSRob Clark * Interruptible version of drm_modeset_backoff() 38351fd371bSRob Clark */ 38451fd371bSRob Clark int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx) 38551fd371bSRob Clark { 38651fd371bSRob Clark return modeset_backoff(ctx, true); 38751fd371bSRob Clark } 38851fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_backoff_interruptible); 38951fd371bSRob Clark 39051fd371bSRob Clark /** 39151fd371bSRob Clark * drm_modeset_lock - take modeset lock 39251fd371bSRob Clark * @lock: lock to take 39351fd371bSRob Clark * @ctx: acquire ctx 39451fd371bSRob Clark * 39551fd371bSRob Clark * If ctx is not NULL, then its ww acquire context is used and the 39651fd371bSRob Clark * lock will be tracked by the context and can be released by calling 39751fd371bSRob Clark * drm_modeset_drop_locks(). If -EDEADLK is returned, this means a 39851fd371bSRob Clark * deadlock scenario has been detected and it is an error to attempt 39951fd371bSRob Clark * to take any more locks without first calling drm_modeset_backoff(). 40051fd371bSRob Clark */ 40151fd371bSRob Clark int drm_modeset_lock(struct drm_modeset_lock *lock, 40251fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 40351fd371bSRob Clark { 40451fd371bSRob Clark if (ctx) 40551fd371bSRob Clark return modeset_lock(lock, ctx, false, false); 40651fd371bSRob Clark 40751fd371bSRob Clark ww_mutex_lock(&lock->mutex, NULL); 40851fd371bSRob Clark return 0; 40951fd371bSRob Clark } 41051fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_lock); 41151fd371bSRob Clark 41251fd371bSRob Clark /** 41351fd371bSRob Clark * drm_modeset_lock_interruptible - take modeset lock 41451fd371bSRob Clark * @lock: lock to take 41551fd371bSRob Clark * @ctx: acquire ctx 41651fd371bSRob Clark * 41751fd371bSRob Clark * Interruptible version of drm_modeset_lock() 41851fd371bSRob Clark */ 41951fd371bSRob Clark int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 42051fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 42151fd371bSRob Clark { 42251fd371bSRob Clark if (ctx) 42351fd371bSRob Clark return modeset_lock(lock, ctx, true, false); 42451fd371bSRob Clark 42551fd371bSRob Clark return ww_mutex_lock_interruptible(&lock->mutex, NULL); 42651fd371bSRob Clark } 42751fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_lock_interruptible); 42851fd371bSRob Clark 42951fd371bSRob Clark /** 43051fd371bSRob Clark * drm_modeset_unlock - drop modeset lock 43151fd371bSRob Clark * @lock: lock to release 43251fd371bSRob Clark */ 43351fd371bSRob Clark void drm_modeset_unlock(struct drm_modeset_lock *lock) 43451fd371bSRob Clark { 43551fd371bSRob Clark list_del_init(&lock->head); 43651fd371bSRob Clark ww_mutex_unlock(&lock->mutex); 43751fd371bSRob Clark } 43851fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_unlock); 43951fd371bSRob Clark 44051fd371bSRob Clark /* Temporary.. until we have sufficiently fine grained locking, there 44151fd371bSRob Clark * are a couple scenarios where it is convenient to grab all crtc locks. 44251fd371bSRob Clark * It is planned to remove this: 44351fd371bSRob Clark */ 44451fd371bSRob Clark int drm_modeset_lock_all_crtcs(struct drm_device *dev, 44551fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 44651fd371bSRob Clark { 44751fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 44851fd371bSRob Clark struct drm_crtc *crtc; 44951fd371bSRob Clark int ret = 0; 45051fd371bSRob Clark 45151fd371bSRob Clark list_for_each_entry(crtc, &config->crtc_list, head) { 45251fd371bSRob Clark ret = drm_modeset_lock(&crtc->mutex, ctx); 45351fd371bSRob Clark if (ret) 45451fd371bSRob Clark return ret; 45551fd371bSRob Clark } 45651fd371bSRob Clark 45751fd371bSRob Clark return 0; 45851fd371bSRob Clark } 45951fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_lock_all_crtcs); 460