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