Line data Source code
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 : #ifndef DRM_MODESET_LOCK_H_ 25 : #define DRM_MODESET_LOCK_H_ 26 : 27 : #include <linux/types.h> /* stackdepot.h is not self-contained */ 28 : #include <linux/stackdepot.h> 29 : #include <linux/ww_mutex.h> 30 : 31 : struct drm_modeset_lock; 32 : 33 : /** 34 : * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) 35 : * @ww_ctx: base acquire ctx 36 : * @contended: used internally for -EDEADLK handling 37 : * @stack_depot: used internally for contention debugging 38 : * @locked: list of held locks 39 : * @trylock_only: trylock mode used in atomic contexts/panic notifiers 40 : * @interruptible: whether interruptible locking should be used. 41 : * 42 : * Each thread competing for a set of locks must use one acquire 43 : * ctx. And if any lock fxn returns -EDEADLK, it must backoff and 44 : * retry. 45 : */ 46 : struct drm_modeset_acquire_ctx { 47 : 48 : struct ww_acquire_ctx ww_ctx; 49 : 50 : /* 51 : * Contended lock: if a lock is contended you should only call 52 : * drm_modeset_backoff() which drops locks and slow-locks the 53 : * contended lock. 54 : */ 55 : struct drm_modeset_lock *contended; 56 : 57 : /* 58 : * Stack depot for debugging when a contended lock was not backed off 59 : * from. 60 : */ 61 : depot_stack_handle_t stack_depot; 62 : 63 : /* 64 : * list of held locks (drm_modeset_lock) 65 : */ 66 : struct list_head locked; 67 : 68 : /* 69 : * Trylock mode, use only for panic handlers! 70 : */ 71 : bool trylock_only; 72 : 73 : /* Perform interruptible waits on this context. */ 74 : bool interruptible; 75 : }; 76 : 77 : /** 78 : * struct drm_modeset_lock - used for locking modeset resources. 79 : * @mutex: resource locking 80 : * @head: used to hold its place on &drm_atomi_state.locked list when 81 : * part of an atomic update 82 : * 83 : * Used for locking CRTCs and other modeset resources. 84 : */ 85 : struct drm_modeset_lock { 86 : /* 87 : * modeset lock 88 : */ 89 : struct ww_mutex mutex; 90 : 91 : /* 92 : * Resources that are locked as part of an atomic update are added 93 : * to a list (so we know what to unlock at the end). 94 : */ 95 : struct list_head head; 96 : }; 97 : 98 : #define DRM_MODESET_ACQUIRE_INTERRUPTIBLE BIT(0) 99 : 100 : void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 101 : uint32_t flags); 102 : void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); 103 : void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); 104 : int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); 105 : 106 : void drm_modeset_lock_init(struct drm_modeset_lock *lock); 107 : 108 : /** 109 : * drm_modeset_lock_fini - cleanup lock 110 : * @lock: lock to cleanup 111 : */ 112 : static inline void drm_modeset_lock_fini(struct drm_modeset_lock *lock) 113 : { 114 44 : WARN_ON(!list_empty(&lock->head)); 115 : } 116 : 117 : /** 118 : * drm_modeset_is_locked - equivalent to mutex_is_locked() 119 : * @lock: lock to check 120 : */ 121 : static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock) 122 : { 123 0 : return ww_mutex_is_locked(&lock->mutex); 124 : } 125 : 126 : /** 127 : * drm_modeset_lock_assert_held - equivalent to lockdep_assert_held() 128 : * @lock: lock to check 129 : */ 130 : static inline void drm_modeset_lock_assert_held(struct drm_modeset_lock *lock) 131 : { 132 : lockdep_assert_held(&lock->mutex.base); 133 : } 134 : 135 : int drm_modeset_lock(struct drm_modeset_lock *lock, 136 : struct drm_modeset_acquire_ctx *ctx); 137 : int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock); 138 : void drm_modeset_unlock(struct drm_modeset_lock *lock); 139 : 140 : struct drm_device; 141 : struct drm_crtc; 142 : struct drm_plane; 143 : 144 : void drm_modeset_lock_all(struct drm_device *dev); 145 : void drm_modeset_unlock_all(struct drm_device *dev); 146 : void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); 147 : 148 : int drm_modeset_lock_all_ctx(struct drm_device *dev, 149 : struct drm_modeset_acquire_ctx *ctx); 150 : 151 : /** 152 : * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks 153 : * @dev: drm device 154 : * @ctx: local modeset acquire context, will be dereferenced 155 : * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init() 156 : * @ret: local ret/err/etc variable to track error status 157 : * 158 : * Use these macros to simplify grabbing all modeset locks using a local 159 : * context. This has the advantage of reducing boilerplate, but also properly 160 : * checking return values where appropriate. 161 : * 162 : * Any code run between BEGIN and END will be holding the modeset locks. 163 : * 164 : * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and 165 : * forth between the labels on deadlock and error conditions. 166 : * 167 : * Drivers can acquire additional modeset locks. If any lock acquisition 168 : * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with 169 : * the @ret parameter containing the return value of drm_modeset_lock(). 170 : * 171 : * Returns: 172 : * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN() 173 : * is 0, so no error checking is necessary 174 : */ 175 : #define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret) \ 176 : if (!drm_drv_uses_atomic_modeset(dev)) \ 177 : mutex_lock(&dev->mode_config.mutex); \ 178 : drm_modeset_acquire_init(&ctx, flags); \ 179 : modeset_lock_retry: \ 180 : ret = drm_modeset_lock_all_ctx(dev, &ctx); \ 181 : if (ret) \ 182 : goto modeset_lock_fail; 183 : 184 : /** 185 : * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks 186 : * @dev: drm device 187 : * @ctx: local modeset acquire context, will be dereferenced 188 : * @ret: local ret/err/etc variable to track error status 189 : * 190 : * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN 191 : * if ret is -EDEADLK. 192 : * 193 : * It's important that you use the same ret variable for begin and end so 194 : * deadlock conditions are properly handled. 195 : * 196 : * Returns: 197 : * ret will be untouched unless it is -EDEADLK on entry. That means that if you 198 : * successfully acquire the locks, ret will be whatever your code sets it to. If 199 : * there is a deadlock or other failure with acquire or backoff, ret will be set 200 : * to that failure. In both of these cases the code between BEGIN/END will not 201 : * be run, so the failure will reflect the inability to grab the locks. 202 : */ 203 : #define DRM_MODESET_LOCK_ALL_END(dev, ctx, ret) \ 204 : modeset_lock_fail: \ 205 : if (ret == -EDEADLK) { \ 206 : ret = drm_modeset_backoff(&ctx); \ 207 : if (!ret) \ 208 : goto modeset_lock_retry; \ 209 : } \ 210 : drm_modeset_drop_locks(&ctx); \ 211 : drm_modeset_acquire_fini(&ctx); \ 212 : if (!drm_drv_uses_atomic_modeset(dev)) \ 213 : mutex_unlock(&dev->mode_config.mutex); 214 : 215 : #endif /* DRM_MODESET_LOCK_H_ */