^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (C) 2014 Red Hat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Author: Rob Clark <robdclark@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Permission is hereby granted, free of charge, to any person obtaining a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * copy of this software and associated documentation files (the "Software"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * to deal in the Software without restriction, including without limitation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * the rights to use, copy, modify, merge, publish, distribute, sublicense,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and/or sell copies of the Software, and to permit persons to whom the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Software is furnished to do so, subject to the following conditions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * The above copyright notice and this permission notice shall be included in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * all copies or substantial portions of the Software.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * OTHER DEALINGS IN THE SOFTWARE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifndef DRM_MODESET_LOCK_H_
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define DRM_MODESET_LOCK_H_
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/ww_mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct drm_modeset_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * @ww_ctx: base acquire ctx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * @contended: used internally for -EDEADLK handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * @locked: list of held locks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * @trylock_only: trylock mode used in atomic contexts/panic notifiers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * @interruptible: whether interruptible locking should be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Each thread competing for a set of locks must use one acquire
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * ctx. And if any lock fxn returns -EDEADLK, it must backoff and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * retry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct drm_modeset_acquire_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct ww_acquire_ctx ww_ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Contended lock: if a lock is contended you should only call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * drm_modeset_backoff() which drops locks and slow-locks the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * contended lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct drm_modeset_lock *contended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * list of held locks (drm_modeset_lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct list_head locked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Trylock mode, use only for panic handlers!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) bool trylock_only;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* Perform interruptible waits on this context. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) bool interruptible;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * struct drm_modeset_lock - used for locking modeset resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * @mutex: resource locking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * @head: used to hold its place on &drm_atomi_state.locked list when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * part of an atomic update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Used for locking CRTCs and other modeset resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct drm_modeset_lock {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * modeset lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct ww_mutex mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * Resources that are locked as part of an atomic update are added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * to a list (so we know what to unlock at the end).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct list_head head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define DRM_MODESET_ACQUIRE_INTERRUPTIBLE BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) uint32_t flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) void drm_modeset_lock_init(struct drm_modeset_lock *lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * drm_modeset_lock_fini - cleanup lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * @lock: lock to cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static inline void drm_modeset_lock_fini(struct drm_modeset_lock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) WARN_ON(!list_empty(&lock->head));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * drm_modeset_is_locked - equivalent to mutex_is_locked()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * @lock: lock to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return ww_mutex_is_locked(&lock->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * drm_modeset_lock_assert_held - equivalent to lockdep_assert_held()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * @lock: lock to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static inline void drm_modeset_lock_assert_held(struct drm_modeset_lock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) lockdep_assert_held(&lock->mutex.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) int drm_modeset_lock(struct drm_modeset_lock *lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct drm_modeset_acquire_ctx *ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) void drm_modeset_unlock(struct drm_modeset_lock *lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct drm_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct drm_crtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct drm_plane;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) void drm_modeset_lock_all(struct drm_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) void drm_modeset_unlock_all(struct drm_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int drm_modeset_lock_all_ctx(struct drm_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct drm_modeset_acquire_ctx *ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * @dev: drm device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * @ctx: local modeset acquire context, will be dereferenced
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @ret: local ret/err/etc variable to track error status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * Use these macros to simplify grabbing all modeset locks using a local
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * context. This has the advantage of reducing boilerplate, but also properly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * checking return values where appropriate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * Any code run between BEGIN and END will be holding the modeset locks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * forth between the labels on deadlock and error conditions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * Drivers can acquire additional modeset locks. If any lock acquisition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * the @ret parameter containing the return value of drm_modeset_lock().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * is 0, so no error checking is necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (!drm_drv_uses_atomic_modeset(dev)) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) mutex_lock(&dev->mode_config.mutex); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) drm_modeset_acquire_init(&ctx, flags); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) modeset_lock_retry: \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) ret = drm_modeset_lock_all_ctx(dev, &ctx); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto modeset_lock_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * @dev: drm device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * @ctx: local modeset acquire context, will be dereferenced
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * @ret: local ret/err/etc variable to track error status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * if ret is -EDEADLK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * It's important that you use the same ret variable for begin and end so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * deadlock conditions are properly handled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * ret will be untouched unless it is -EDEADLK on entry. That means that if you
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * successfully acquire the locks, ret will be whatever your code sets it to. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * there is a deadlock or other failure with acquire or backoff, ret will be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * to that failure. In both of these cases the code between BEGIN/END will not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * be run, so the failure will reflect the inability to grab the locks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) #define DRM_MODESET_LOCK_ALL_END(dev, ctx, ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) modeset_lock_fail: \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (ret == -EDEADLK) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) ret = drm_modeset_backoff(&ctx); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (!ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto modeset_lock_retry; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) drm_modeset_drop_locks(&ctx); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) drm_modeset_acquire_fini(&ctx); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (!drm_drv_uses_atomic_modeset(dev)) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) mutex_unlock(&dev->mode_config.mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #endif /* DRM_MODESET_LOCK_H_ */