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 * 38214e0aedSDavidlohr Bueso * For basic principles of ww_mutex, see: Documentation/locking/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 /** 59bf9e37baSDaniel Vetter * drm_modeset_lock_all - take all modeset locks 6006eaae46SThierry Reding * @dev: DRM device 61a6a8bb84SDaniel Vetter * 62bf9e37baSDaniel Vetter * This function takes all modeset locks, suitable where a more fine-grained 6306eaae46SThierry Reding * scheme isn't (yet) implemented. Locks must be dropped by calling the 6406eaae46SThierry Reding * drm_modeset_unlock_all() function. 6506eaae46SThierry Reding * 6606eaae46SThierry Reding * This function is deprecated. It allocates a lock acquisition context and 6706eaae46SThierry Reding * stores it in the DRM device's ->mode_config. This facilitate conversion of 6806eaae46SThierry Reding * existing code because it removes the need to manually deal with the 6906eaae46SThierry Reding * acquisition context, but it is also brittle because the context is global 7006eaae46SThierry Reding * and care must be taken not to nest calls. New code should use the 7106eaae46SThierry Reding * drm_modeset_lock_all_ctx() function and pass in the context explicitly. 72a6a8bb84SDaniel Vetter */ 73bf9e37baSDaniel Vetter void drm_modeset_lock_all(struct drm_device *dev) 74a6a8bb84SDaniel Vetter { 75a6a8bb84SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 76a6a8bb84SDaniel Vetter struct drm_modeset_acquire_ctx *ctx; 77a6a8bb84SDaniel Vetter int ret; 78a6a8bb84SDaniel Vetter 79bf9e37baSDaniel Vetter ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 80bf9e37baSDaniel Vetter if (WARN_ON(!ctx)) 81bf9e37baSDaniel Vetter return; 82a6a8bb84SDaniel Vetter 83a6a8bb84SDaniel Vetter mutex_lock(&config->mutex); 84a6a8bb84SDaniel Vetter 85a6a8bb84SDaniel Vetter drm_modeset_acquire_init(ctx, 0); 86a6a8bb84SDaniel Vetter 87a6a8bb84SDaniel Vetter retry: 8806eaae46SThierry Reding ret = drm_modeset_lock_all_ctx(dev, ctx); 8906eaae46SThierry Reding if (ret < 0) { 90a6a8bb84SDaniel Vetter if (ret == -EDEADLK) { 91a6a8bb84SDaniel Vetter drm_modeset_backoff(ctx); 92a6a8bb84SDaniel Vetter goto retry; 93a6a8bb84SDaniel Vetter } 94cb597bb3SDaniel Vetter 9506eaae46SThierry Reding drm_modeset_acquire_fini(ctx); 96ed181703SOleg Drokin kfree(ctx); 9706eaae46SThierry Reding return; 9806eaae46SThierry Reding } 9906eaae46SThierry Reding 10006eaae46SThierry Reding WARN_ON(config->acquire_ctx); 10106eaae46SThierry Reding 10206eaae46SThierry Reding /* 10306eaae46SThierry Reding * We hold the locks now, so it is safe to stash the acquisition 10406eaae46SThierry Reding * context for drm_modeset_unlock_all(). 10506eaae46SThierry Reding */ 10606eaae46SThierry Reding config->acquire_ctx = ctx; 10706eaae46SThierry Reding 10806eaae46SThierry Reding drm_warn_on_modeset_not_all_locked(dev); 109a6a8bb84SDaniel Vetter } 110a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_all); 111a6a8bb84SDaniel Vetter 112a6a8bb84SDaniel Vetter /** 113a6a8bb84SDaniel Vetter * drm_modeset_unlock_all - drop all modeset locks 11406eaae46SThierry Reding * @dev: DRM device 115a6a8bb84SDaniel Vetter * 11606eaae46SThierry Reding * This function drops all modeset locks taken by a previous call to the 11706eaae46SThierry Reding * drm_modeset_lock_all() function. 11806eaae46SThierry Reding * 11906eaae46SThierry Reding * This function is deprecated. It uses the lock acquisition context stored 12006eaae46SThierry Reding * in the DRM device's ->mode_config. This facilitates conversion of existing 12106eaae46SThierry Reding * code because it removes the need to manually deal with the acquisition 12206eaae46SThierry Reding * context, but it is also brittle because the context is global and care must 12306eaae46SThierry Reding * be taken not to nest calls. New code should pass the acquisition context 12406eaae46SThierry Reding * directly to the drm_modeset_drop_locks() function. 125a6a8bb84SDaniel Vetter */ 126a6a8bb84SDaniel Vetter void drm_modeset_unlock_all(struct drm_device *dev) 127a6a8bb84SDaniel Vetter { 128a6a8bb84SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 129a6a8bb84SDaniel Vetter struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; 130a6a8bb84SDaniel Vetter 131a6a8bb84SDaniel Vetter if (WARN_ON(!ctx)) 132a6a8bb84SDaniel Vetter return; 133a6a8bb84SDaniel Vetter 134a6a8bb84SDaniel Vetter config->acquire_ctx = NULL; 135a6a8bb84SDaniel Vetter drm_modeset_drop_locks(ctx); 136a6a8bb84SDaniel Vetter drm_modeset_acquire_fini(ctx); 137a6a8bb84SDaniel Vetter 138a6a8bb84SDaniel Vetter kfree(ctx); 139a6a8bb84SDaniel Vetter 140a6a8bb84SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 141a6a8bb84SDaniel Vetter } 142a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_all); 143a6a8bb84SDaniel Vetter 144a6a8bb84SDaniel Vetter /** 1454d02e2deSDaniel Vetter * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update 1464d02e2deSDaniel Vetter * @crtc: DRM CRTC 1474d02e2deSDaniel Vetter * @plane: DRM plane to be updated on @crtc 148d059f652SDaniel Vetter * 1494d02e2deSDaniel Vetter * This function locks the given crtc and plane (which should be either the 1504d02e2deSDaniel Vetter * primary or cursor plane) using a hidden acquire context. This is necessary so 1514d02e2deSDaniel Vetter * that drivers internally using the atomic interfaces can grab further locks 1524d02e2deSDaniel Vetter * with the lock acquire context. 1534d02e2deSDaniel Vetter * 1544d02e2deSDaniel Vetter * Note that @plane can be NULL, e.g. when the cursor support hasn't yet been 1554d02e2deSDaniel Vetter * converted to universal planes yet. 156d059f652SDaniel Vetter */ 1574d02e2deSDaniel Vetter void drm_modeset_lock_crtc(struct drm_crtc *crtc, 1584d02e2deSDaniel Vetter struct drm_plane *plane) 159d059f652SDaniel Vetter { 160d059f652SDaniel Vetter struct drm_modeset_acquire_ctx *ctx; 161d059f652SDaniel Vetter int ret; 162d059f652SDaniel Vetter 163d059f652SDaniel Vetter ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 164d059f652SDaniel Vetter if (WARN_ON(!ctx)) 165d059f652SDaniel Vetter return; 166d059f652SDaniel Vetter 167d059f652SDaniel Vetter drm_modeset_acquire_init(ctx, 0); 168d059f652SDaniel Vetter 169d059f652SDaniel Vetter retry: 170d059f652SDaniel Vetter ret = drm_modeset_lock(&crtc->mutex, ctx); 171d059f652SDaniel Vetter if (ret) 172d059f652SDaniel Vetter goto fail; 173d059f652SDaniel Vetter 1744d02e2deSDaniel Vetter if (plane) { 1754d02e2deSDaniel Vetter ret = drm_modeset_lock(&plane->mutex, ctx); 1764d02e2deSDaniel Vetter if (ret) 1774d02e2deSDaniel Vetter goto fail; 1784d02e2deSDaniel Vetter 1794d02e2deSDaniel Vetter if (plane->crtc) { 1804d02e2deSDaniel Vetter ret = drm_modeset_lock(&plane->crtc->mutex, ctx); 1814d02e2deSDaniel Vetter if (ret) 1824d02e2deSDaniel Vetter goto fail; 1834d02e2deSDaniel Vetter } 1844d02e2deSDaniel Vetter } 1854d02e2deSDaniel Vetter 186d059f652SDaniel Vetter WARN_ON(crtc->acquire_ctx); 187d059f652SDaniel Vetter 188d059f652SDaniel Vetter /* now we hold the locks, so now that it is safe, stash the 189d059f652SDaniel Vetter * ctx for drm_modeset_unlock_crtc(): 190d059f652SDaniel Vetter */ 191d059f652SDaniel Vetter crtc->acquire_ctx = ctx; 192d059f652SDaniel Vetter 193d059f652SDaniel Vetter return; 194d059f652SDaniel Vetter 195d059f652SDaniel Vetter fail: 196d059f652SDaniel Vetter if (ret == -EDEADLK) { 197d059f652SDaniel Vetter drm_modeset_backoff(ctx); 198d059f652SDaniel Vetter goto retry; 199d059f652SDaniel Vetter } 200d059f652SDaniel Vetter } 201d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_crtc); 202d059f652SDaniel Vetter 203d059f652SDaniel Vetter /** 204d059f652SDaniel Vetter * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls 205295ee853SDaniel Vetter * @crtc: drm crtc 206d059f652SDaniel Vetter * 207d059f652SDaniel Vetter * Legacy ioctl operations like cursor updates or page flips only have per-crtc 208d059f652SDaniel Vetter * locking, and store the acquire ctx in the corresponding crtc. All other 209d059f652SDaniel Vetter * legacy operations take all locks and use a global acquire context. This 210d059f652SDaniel Vetter * function grabs the right one. 211d059f652SDaniel Vetter */ 212d059f652SDaniel Vetter struct drm_modeset_acquire_ctx * 213d059f652SDaniel Vetter drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) 214d059f652SDaniel Vetter { 215d059f652SDaniel Vetter if (crtc->acquire_ctx) 216d059f652SDaniel Vetter return crtc->acquire_ctx; 217d059f652SDaniel Vetter 218d059f652SDaniel Vetter WARN_ON(!crtc->dev->mode_config.acquire_ctx); 219d059f652SDaniel Vetter 220d059f652SDaniel Vetter return crtc->dev->mode_config.acquire_ctx; 221d059f652SDaniel Vetter } 222d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); 223d059f652SDaniel Vetter 224d059f652SDaniel Vetter /** 225d059f652SDaniel Vetter * drm_modeset_unlock_crtc - drop crtc lock 226d059f652SDaniel Vetter * @crtc: drm crtc 227d059f652SDaniel Vetter * 228d059f652SDaniel Vetter * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other 229d059f652SDaniel Vetter * locks acquired through the hidden context. 230d059f652SDaniel Vetter */ 231d059f652SDaniel Vetter void drm_modeset_unlock_crtc(struct drm_crtc *crtc) 232d059f652SDaniel Vetter { 233d059f652SDaniel Vetter struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; 234d059f652SDaniel Vetter 235d059f652SDaniel Vetter if (WARN_ON(!ctx)) 236d059f652SDaniel Vetter return; 237d059f652SDaniel Vetter 238d059f652SDaniel Vetter crtc->acquire_ctx = NULL; 239d059f652SDaniel Vetter drm_modeset_drop_locks(ctx); 240d059f652SDaniel Vetter drm_modeset_acquire_fini(ctx); 241d059f652SDaniel Vetter 242d059f652SDaniel Vetter kfree(ctx); 243d059f652SDaniel Vetter } 244d059f652SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_crtc); 245d059f652SDaniel Vetter 246d059f652SDaniel Vetter /** 247a6a8bb84SDaniel Vetter * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked 248a6a8bb84SDaniel Vetter * @dev: device 249a6a8bb84SDaniel Vetter * 250a6a8bb84SDaniel Vetter * Useful as a debug assert. 251a6a8bb84SDaniel Vetter */ 252a6a8bb84SDaniel Vetter void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) 253a6a8bb84SDaniel Vetter { 254a6a8bb84SDaniel Vetter struct drm_crtc *crtc; 255a6a8bb84SDaniel Vetter 256a6a8bb84SDaniel Vetter /* Locking is currently fubar in the panic handler. */ 257a6a8bb84SDaniel Vetter if (oops_in_progress) 258a6a8bb84SDaniel Vetter return; 259a6a8bb84SDaniel Vetter 260e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 261a6a8bb84SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 262a6a8bb84SDaniel Vetter 263a6a8bb84SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 264a6a8bb84SDaniel Vetter WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 265a6a8bb84SDaniel Vetter } 266a6a8bb84SDaniel Vetter EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); 267a6a8bb84SDaniel Vetter 268a6a8bb84SDaniel Vetter /** 26951fd371bSRob Clark * drm_modeset_acquire_init - initialize acquire context 27051fd371bSRob Clark * @ctx: the acquire context 27151fd371bSRob Clark * @flags: for future 27251fd371bSRob Clark */ 27351fd371bSRob Clark void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 27451fd371bSRob Clark uint32_t flags) 27551fd371bSRob Clark { 276fb54918aSRob Clark memset(ctx, 0, sizeof(*ctx)); 27751fd371bSRob Clark ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); 27851fd371bSRob Clark INIT_LIST_HEAD(&ctx->locked); 27951fd371bSRob Clark } 28051fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_acquire_init); 28151fd371bSRob Clark 28251fd371bSRob Clark /** 28351fd371bSRob Clark * drm_modeset_acquire_fini - cleanup acquire context 28451fd371bSRob Clark * @ctx: the acquire context 28551fd371bSRob Clark */ 28651fd371bSRob Clark void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) 28751fd371bSRob Clark { 28851fd371bSRob Clark ww_acquire_fini(&ctx->ww_ctx); 28951fd371bSRob Clark } 29051fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_acquire_fini); 29151fd371bSRob Clark 29251fd371bSRob Clark /** 29351fd371bSRob Clark * drm_modeset_drop_locks - drop all locks 29451fd371bSRob Clark * @ctx: the acquire context 29551fd371bSRob Clark * 29651fd371bSRob Clark * Drop all locks currently held against this acquire context. 29751fd371bSRob Clark */ 29851fd371bSRob Clark void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) 29951fd371bSRob Clark { 30051fd371bSRob Clark WARN_ON(ctx->contended); 30151fd371bSRob Clark while (!list_empty(&ctx->locked)) { 30251fd371bSRob Clark struct drm_modeset_lock *lock; 30351fd371bSRob Clark 30451fd371bSRob Clark lock = list_first_entry(&ctx->locked, 30551fd371bSRob Clark struct drm_modeset_lock, head); 30651fd371bSRob Clark 30751fd371bSRob Clark drm_modeset_unlock(lock); 30851fd371bSRob Clark } 30951fd371bSRob Clark } 31051fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_drop_locks); 31151fd371bSRob Clark 31251fd371bSRob Clark static inline int modeset_lock(struct drm_modeset_lock *lock, 31351fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx, 31451fd371bSRob Clark bool interruptible, bool slow) 31551fd371bSRob Clark { 31651fd371bSRob Clark int ret; 31751fd371bSRob Clark 31851fd371bSRob Clark WARN_ON(ctx->contended); 31951fd371bSRob Clark 320cb597bb3SDaniel Vetter if (ctx->trylock_only) { 321825926d8SMaarten Lankhorst lockdep_assert_held(&ctx->ww_ctx); 322825926d8SMaarten Lankhorst 323cb597bb3SDaniel Vetter if (!ww_mutex_trylock(&lock->mutex)) 324cb597bb3SDaniel Vetter return -EBUSY; 325cb597bb3SDaniel Vetter else 326cb597bb3SDaniel Vetter return 0; 327cb597bb3SDaniel Vetter } else if (interruptible && slow) { 32851fd371bSRob Clark ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); 32951fd371bSRob Clark } else if (interruptible) { 33051fd371bSRob Clark ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); 33151fd371bSRob Clark } else if (slow) { 33251fd371bSRob Clark ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx); 33351fd371bSRob Clark ret = 0; 33451fd371bSRob Clark } else { 33551fd371bSRob Clark ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx); 33651fd371bSRob Clark } 33751fd371bSRob Clark if (!ret) { 33851fd371bSRob Clark WARN_ON(!list_empty(&lock->head)); 33951fd371bSRob Clark list_add(&lock->head, &ctx->locked); 34051fd371bSRob Clark } else if (ret == -EALREADY) { 34151fd371bSRob Clark /* we already hold the lock.. this is fine. For atomic 34251fd371bSRob Clark * we will need to be able to drm_modeset_lock() things 34351fd371bSRob Clark * without having to keep track of what is already locked 34451fd371bSRob Clark * or not. 34551fd371bSRob Clark */ 34651fd371bSRob Clark ret = 0; 34751fd371bSRob Clark } else if (ret == -EDEADLK) { 34851fd371bSRob Clark ctx->contended = lock; 34951fd371bSRob Clark } 35051fd371bSRob Clark 35151fd371bSRob Clark return ret; 35251fd371bSRob Clark } 35351fd371bSRob Clark 35451fd371bSRob Clark static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, 35551fd371bSRob Clark bool interruptible) 35651fd371bSRob Clark { 35751fd371bSRob Clark struct drm_modeset_lock *contended = ctx->contended; 35851fd371bSRob Clark 35951fd371bSRob Clark ctx->contended = NULL; 36051fd371bSRob Clark 36151fd371bSRob Clark if (WARN_ON(!contended)) 36251fd371bSRob Clark return 0; 36351fd371bSRob Clark 36451fd371bSRob Clark drm_modeset_drop_locks(ctx); 36551fd371bSRob Clark 36651fd371bSRob Clark return modeset_lock(contended, ctx, interruptible, true); 36751fd371bSRob Clark } 36851fd371bSRob Clark 36951fd371bSRob Clark /** 37051fd371bSRob Clark * drm_modeset_backoff - deadlock avoidance backoff 37151fd371bSRob Clark * @ctx: the acquire context 37251fd371bSRob Clark * 37351fd371bSRob Clark * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK), 37451fd371bSRob Clark * you must call this function to drop all currently held locks and 37551fd371bSRob Clark * block until the contended lock becomes available. 37651fd371bSRob Clark */ 37751fd371bSRob Clark void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) 37851fd371bSRob Clark { 37951fd371bSRob Clark modeset_backoff(ctx, false); 38051fd371bSRob Clark } 38151fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_backoff); 38251fd371bSRob Clark 38351fd371bSRob Clark /** 38451fd371bSRob Clark * drm_modeset_backoff_interruptible - deadlock avoidance backoff 38551fd371bSRob Clark * @ctx: the acquire context 38651fd371bSRob Clark * 38751fd371bSRob Clark * Interruptible version of drm_modeset_backoff() 38851fd371bSRob Clark */ 38951fd371bSRob Clark int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx) 39051fd371bSRob Clark { 39151fd371bSRob Clark return modeset_backoff(ctx, true); 39251fd371bSRob Clark } 39351fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_backoff_interruptible); 39451fd371bSRob Clark 39551fd371bSRob Clark /** 39651fd371bSRob Clark * drm_modeset_lock - take modeset lock 39751fd371bSRob Clark * @lock: lock to take 39851fd371bSRob Clark * @ctx: acquire ctx 39951fd371bSRob Clark * 40051fd371bSRob Clark * If ctx is not NULL, then its ww acquire context is used and the 40151fd371bSRob Clark * lock will be tracked by the context and can be released by calling 40251fd371bSRob Clark * drm_modeset_drop_locks(). If -EDEADLK is returned, this means a 40351fd371bSRob Clark * deadlock scenario has been detected and it is an error to attempt 40451fd371bSRob Clark * to take any more locks without first calling drm_modeset_backoff(). 40551fd371bSRob Clark */ 40651fd371bSRob Clark int drm_modeset_lock(struct drm_modeset_lock *lock, 40751fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 40851fd371bSRob Clark { 40951fd371bSRob Clark if (ctx) 41051fd371bSRob Clark return modeset_lock(lock, ctx, false, false); 41151fd371bSRob Clark 41251fd371bSRob Clark ww_mutex_lock(&lock->mutex, NULL); 41351fd371bSRob Clark return 0; 41451fd371bSRob Clark } 41551fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_lock); 41651fd371bSRob Clark 41751fd371bSRob Clark /** 41851fd371bSRob Clark * drm_modeset_lock_interruptible - take modeset lock 41951fd371bSRob Clark * @lock: lock to take 42051fd371bSRob Clark * @ctx: acquire ctx 42151fd371bSRob Clark * 42251fd371bSRob Clark * Interruptible version of drm_modeset_lock() 42351fd371bSRob Clark */ 42451fd371bSRob Clark int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 42551fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 42651fd371bSRob Clark { 42751fd371bSRob Clark if (ctx) 42851fd371bSRob Clark return modeset_lock(lock, ctx, true, false); 42951fd371bSRob Clark 43051fd371bSRob Clark return ww_mutex_lock_interruptible(&lock->mutex, NULL); 43151fd371bSRob Clark } 43251fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_lock_interruptible); 43351fd371bSRob Clark 43451fd371bSRob Clark /** 43551fd371bSRob Clark * drm_modeset_unlock - drop modeset lock 43651fd371bSRob Clark * @lock: lock to release 43751fd371bSRob Clark */ 43851fd371bSRob Clark void drm_modeset_unlock(struct drm_modeset_lock *lock) 43951fd371bSRob Clark { 44051fd371bSRob Clark list_del_init(&lock->head); 44151fd371bSRob Clark ww_mutex_unlock(&lock->mutex); 44251fd371bSRob Clark } 44351fd371bSRob Clark EXPORT_SYMBOL(drm_modeset_unlock); 44451fd371bSRob Clark 44506eaae46SThierry Reding /** 44606eaae46SThierry Reding * drm_modeset_lock_all_ctx - take all modeset locks 44706eaae46SThierry Reding * @dev: DRM device 44806eaae46SThierry Reding * @ctx: lock acquisition context 44906eaae46SThierry Reding * 45006eaae46SThierry Reding * This function takes all modeset locks, suitable where a more fine-grained 45106eaae46SThierry Reding * scheme isn't (yet) implemented. 45206eaae46SThierry Reding * 45306eaae46SThierry Reding * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex 45406eaae46SThierry Reding * since that lock isn't required for modeset state changes. Callers which 45506eaae46SThierry Reding * need to grab that lock too need to do so outside of the acquire context 45606eaae46SThierry Reding * @ctx. 45706eaae46SThierry Reding * 45806eaae46SThierry Reding * Locks acquired with this function should be released by calling the 45906eaae46SThierry Reding * drm_modeset_drop_locks() function on @ctx. 46006eaae46SThierry Reding * 46106eaae46SThierry Reding * Returns: 0 on success or a negative error-code on failure. 46206eaae46SThierry Reding */ 46306eaae46SThierry Reding int drm_modeset_lock_all_ctx(struct drm_device *dev, 46451fd371bSRob Clark struct drm_modeset_acquire_ctx *ctx) 46551fd371bSRob Clark { 46651fd371bSRob Clark struct drm_crtc *crtc; 4674d02e2deSDaniel Vetter struct drm_plane *plane; 46806eaae46SThierry Reding int ret; 46906eaae46SThierry Reding 47006eaae46SThierry Reding ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); 47106eaae46SThierry Reding if (ret) 47206eaae46SThierry Reding return ret; 47351fd371bSRob Clark 474e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) { 47551fd371bSRob Clark ret = drm_modeset_lock(&crtc->mutex, ctx); 47651fd371bSRob Clark if (ret) 47751fd371bSRob Clark return ret; 47851fd371bSRob Clark } 47951fd371bSRob Clark 480e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) { 4814d02e2deSDaniel Vetter ret = drm_modeset_lock(&plane->mutex, ctx); 4824d02e2deSDaniel Vetter if (ret) 4834d02e2deSDaniel Vetter return ret; 4844d02e2deSDaniel Vetter } 4854d02e2deSDaniel Vetter 48651fd371bSRob Clark return 0; 48751fd371bSRob Clark } 48806eaae46SThierry Reding EXPORT_SYMBOL(drm_modeset_lock_all_ctx); 489