Rev 5060 | Rev 6084 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5060 | Rev 5271 | ||
---|---|---|---|
Line 33... | Line 33... | ||
33 | * to use ww_mutex and acquire-contexts to avoid deadlocks. But because |
33 | * to use ww_mutex and acquire-contexts to avoid deadlocks. But because |
34 | * the locking is more distributed around the driver code, we want a bit |
34 | * the locking is more distributed around the driver code, we want a bit |
35 | * of extra utility/tracking out of our acquire-ctx. This is provided |
35 | * of extra utility/tracking out of our acquire-ctx. This is provided |
36 | * by drm_modeset_lock / drm_modeset_acquire_ctx. |
36 | * by drm_modeset_lock / drm_modeset_acquire_ctx. |
37 | * |
37 | * |
38 | * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt |
38 | * For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt |
39 | * |
39 | * |
40 | * The basic usage pattern is to: |
40 | * The basic usage pattern is to: |
41 | * |
41 | * |
42 | * drm_modeset_acquire_init(&ctx) |
42 | * drm_modeset_acquire_init(&ctx) |
43 | * retry: |
43 | * retry: |
Line 55... | Line 55... | ||
55 | * drm_modeset_acquire_fini(&ctx); |
55 | * drm_modeset_acquire_fini(&ctx); |
56 | */ |
56 | */ |
Line 57... | Line 57... | ||
57 | 57 | ||
- | 58 | ||
- | 59 | /** |
|
- | 60 | * __drm_modeset_lock_all - internal helper to grab all modeset locks |
|
- | 61 | * @dev: DRM device |
|
- | 62 | * @trylock: trylock mode for atomic contexts |
|
- | 63 | * |
|
- | 64 | * This is a special version of drm_modeset_lock_all() which can also be used in |
|
- | 65 | * atomic contexts. Then @trylock must be set to true. |
|
- | 66 | * |
|
- | 67 | * Returns: |
|
- | 68 | * 0 on success or negative error code on failure. |
|
- | 69 | */ |
|
- | 70 | int __drm_modeset_lock_all(struct drm_device *dev, |
|
- | 71 | bool trylock) |
|
- | 72 | { |
|
- | 73 | struct drm_mode_config *config = &dev->mode_config; |
|
- | 74 | struct drm_modeset_acquire_ctx *ctx; |
|
- | 75 | int ret; |
|
- | 76 | ||
- | 77 | ctx = kzalloc(sizeof(*ctx), |
|
- | 78 | trylock ? GFP_ATOMIC : GFP_KERNEL); |
|
- | 79 | if (!ctx) |
|
- | 80 | return -ENOMEM; |
|
- | 81 | ||
- | 82 | if (trylock) { |
|
- | 83 | if (!mutex_trylock(&config->mutex)) |
|
- | 84 | return -EBUSY; |
|
- | 85 | } else { |
|
- | 86 | mutex_lock(&config->mutex); |
|
- | 87 | } |
|
- | 88 | ||
- | 89 | drm_modeset_acquire_init(ctx, 0); |
|
- | 90 | ctx->trylock_only = trylock; |
|
- | 91 | ||
- | 92 | retry: |
|
- | 93 | ret = drm_modeset_lock(&config->connection_mutex, ctx); |
|
- | 94 | if (ret) |
|
- | 95 | goto fail; |
|
- | 96 | ret = drm_modeset_lock_all_crtcs(dev, ctx); |
|
- | 97 | if (ret) |
|
- | 98 | goto fail; |
|
- | 99 | ||
- | 100 | WARN_ON(config->acquire_ctx); |
|
- | 101 | ||
- | 102 | /* now we hold the locks, so now that it is safe, stash the |
|
- | 103 | * ctx for drm_modeset_unlock_all(): |
|
- | 104 | */ |
|
- | 105 | config->acquire_ctx = ctx; |
|
- | 106 | ||
- | 107 | drm_warn_on_modeset_not_all_locked(dev); |
|
- | 108 | ||
- | 109 | return 0; |
|
- | 110 | ||
- | 111 | fail: |
|
- | 112 | if (ret == -EDEADLK) { |
|
- | 113 | drm_modeset_backoff(ctx); |
|
- | 114 | goto retry; |
|
- | 115 | } |
|
- | 116 | ||
- | 117 | return ret; |
|
- | 118 | } |
|
- | 119 | EXPORT_SYMBOL(__drm_modeset_lock_all); |
|
- | 120 | ||
- | 121 | /** |
|
- | 122 | * drm_modeset_lock_all - take all modeset locks |
|
- | 123 | * @dev: drm device |
|
- | 124 | * |
|
- | 125 | * This function takes all modeset locks, suitable where a more fine-grained |
|
- | 126 | * scheme isn't (yet) implemented. Locks must be dropped with |
|
- | 127 | * drm_modeset_unlock_all. |
|
- | 128 | */ |
|
- | 129 | void drm_modeset_lock_all(struct drm_device *dev) |
|
- | 130 | { |
|
- | 131 | WARN_ON(__drm_modeset_lock_all(dev, false) != 0); |
|
- | 132 | } |
|
- | 133 | EXPORT_SYMBOL(drm_modeset_lock_all); |
|
- | 134 | ||
- | 135 | /** |
|
- | 136 | * drm_modeset_unlock_all - drop all modeset locks |
|
- | 137 | * @dev: device |
|
- | 138 | * |
|
- | 139 | * This function drop all modeset locks taken by drm_modeset_lock_all. |
|
- | 140 | */ |
|
- | 141 | void drm_modeset_unlock_all(struct drm_device *dev) |
|
- | 142 | { |
|
- | 143 | struct drm_mode_config *config = &dev->mode_config; |
|
- | 144 | struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; |
|
- | 145 | ||
- | 146 | if (WARN_ON(!ctx)) |
|
- | 147 | return; |
|
- | 148 | ||
- | 149 | config->acquire_ctx = NULL; |
|
- | 150 | drm_modeset_drop_locks(ctx); |
|
- | 151 | drm_modeset_acquire_fini(ctx); |
|
- | 152 | ||
- | 153 | kfree(ctx); |
|
- | 154 | ||
- | 155 | mutex_unlock(&dev->mode_config.mutex); |
|
- | 156 | } |
|
- | 157 | EXPORT_SYMBOL(drm_modeset_unlock_all); |
|
- | 158 | ||
- | 159 | /** |
|
- | 160 | * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update |
|
- | 161 | * @crtc: DRM CRTC |
|
- | 162 | * @plane: DRM plane to be updated on @crtc |
|
- | 163 | * |
|
- | 164 | * This function locks the given crtc and plane (which should be either the |
|
- | 165 | * primary or cursor plane) using a hidden acquire context. This is necessary so |
|
- | 166 | * that drivers internally using the atomic interfaces can grab further locks |
|
- | 167 | * with the lock acquire context. |
|
- | 168 | * |
|
- | 169 | * Note that @plane can be NULL, e.g. when the cursor support hasn't yet been |
|
- | 170 | * converted to universal planes yet. |
|
- | 171 | */ |
|
- | 172 | void drm_modeset_lock_crtc(struct drm_crtc *crtc, |
|
- | 173 | struct drm_plane *plane) |
|
- | 174 | { |
|
- | 175 | struct drm_modeset_acquire_ctx *ctx; |
|
- | 176 | int ret; |
|
- | 177 | ||
- | 178 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
|
- | 179 | if (WARN_ON(!ctx)) |
|
- | 180 | return; |
|
- | 181 | ||
- | 182 | drm_modeset_acquire_init(ctx, 0); |
|
- | 183 | ||
- | 184 | retry: |
|
- | 185 | ret = drm_modeset_lock(&crtc->mutex, ctx); |
|
- | 186 | if (ret) |
|
- | 187 | goto fail; |
|
- | 188 | ||
- | 189 | if (plane) { |
|
- | 190 | ret = drm_modeset_lock(&plane->mutex, ctx); |
|
- | 191 | if (ret) |
|
- | 192 | goto fail; |
|
- | 193 | ||
- | 194 | if (plane->crtc) { |
|
- | 195 | ret = drm_modeset_lock(&plane->crtc->mutex, ctx); |
|
- | 196 | if (ret) |
|
- | 197 | goto fail; |
|
- | 198 | } |
|
- | 199 | } |
|
- | 200 | ||
- | 201 | WARN_ON(crtc->acquire_ctx); |
|
- | 202 | ||
- | 203 | /* now we hold the locks, so now that it is safe, stash the |
|
- | 204 | * ctx for drm_modeset_unlock_crtc(): |
|
- | 205 | */ |
|
- | 206 | crtc->acquire_ctx = ctx; |
|
- | 207 | ||
- | 208 | return; |
|
- | 209 | ||
- | 210 | fail: |
|
- | 211 | if (ret == -EDEADLK) { |
|
- | 212 | drm_modeset_backoff(ctx); |
|
- | 213 | goto retry; |
|
- | 214 | } |
|
- | 215 | } |
|
- | 216 | EXPORT_SYMBOL(drm_modeset_lock_crtc); |
|
- | 217 | ||
- | 218 | /** |
|
- | 219 | * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls |
|
- | 220 | * @crtc: drm crtc |
|
- | 221 | * |
|
- | 222 | * Legacy ioctl operations like cursor updates or page flips only have per-crtc |
|
- | 223 | * locking, and store the acquire ctx in the corresponding crtc. All other |
|
- | 224 | * legacy operations take all locks and use a global acquire context. This |
|
- | 225 | * function grabs the right one. |
|
- | 226 | */ |
|
- | 227 | struct drm_modeset_acquire_ctx * |
|
- | 228 | drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) |
|
- | 229 | { |
|
- | 230 | if (crtc->acquire_ctx) |
|
- | 231 | return crtc->acquire_ctx; |
|
- | 232 | ||
- | 233 | WARN_ON(!crtc->dev->mode_config.acquire_ctx); |
|
- | 234 | ||
- | 235 | return crtc->dev->mode_config.acquire_ctx; |
|
- | 236 | } |
|
- | 237 | EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); |
|
- | 238 | ||
- | 239 | /** |
|
- | 240 | * drm_modeset_unlock_crtc - drop crtc lock |
|
- | 241 | * @crtc: drm crtc |
|
- | 242 | * |
|
- | 243 | * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other |
|
- | 244 | * locks acquired through the hidden context. |
|
- | 245 | */ |
|
- | 246 | void drm_modeset_unlock_crtc(struct drm_crtc *crtc) |
|
- | 247 | { |
|
- | 248 | struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; |
|
- | 249 | ||
- | 250 | if (WARN_ON(!ctx)) |
|
- | 251 | return; |
|
- | 252 | ||
- | 253 | crtc->acquire_ctx = NULL; |
|
- | 254 | drm_modeset_drop_locks(ctx); |
|
- | 255 | drm_modeset_acquire_fini(ctx); |
|
- | 256 | ||
- | 257 | kfree(ctx); |
|
- | 258 | } |
|
- | 259 | EXPORT_SYMBOL(drm_modeset_unlock_crtc); |
|
- | 260 | ||
- | 261 | /** |
|
- | 262 | * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked |
|
- | 263 | * @dev: device |
|
- | 264 | * |
|
- | 265 | * Useful as a debug assert. |
|
- | 266 | */ |
|
- | 267 | void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) |
|
- | 268 | { |
|
- | 269 | struct drm_crtc *crtc; |
|
- | 270 | ||
- | 271 | /* Locking is currently fubar in the panic handler. */ |
|
- | 272 | // if (oops_in_progress) |
|
- | 273 | // return; |
|
- | 274 | ||
- | 275 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
|
- | 276 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); |
|
- | 277 | ||
- | 278 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); |
|
- | 279 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
|
- | 280 | } |
|
- | 281 | EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); |
|
58 | 282 | ||
59 | /** |
283 | /** |
60 | * drm_modeset_acquire_init - initialize acquire context |
284 | * drm_modeset_acquire_init - initialize acquire context |
61 | * @ctx: the acquire context |
285 | * @ctx: the acquire context |
62 | * @flags: for future |
286 | * @flags: for future |
Line 106... | Line 330... | ||
106 | { |
330 | { |
107 | int ret; |
331 | int ret; |
Line 108... | Line 332... | ||
108 | 332 | ||
Line -... | Line 333... | ||
- | 333 | WARN_ON(ctx->contended); |
|
- | 334 | ||
- | 335 | if (ctx->trylock_only) { |
|
- | 336 | if (!ww_mutex_trylock(&lock->mutex)) |
|
- | 337 | return -EBUSY; |
|
109 | WARN_ON(ctx->contended); |
338 | else |
110 | 339 | return 0; |
|
111 | if (interruptible && slow) { |
340 | } else if (interruptible && slow) { |
112 | ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); |
341 | ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); |
113 | } else if (interruptible) { |
342 | } else if (interruptible) { |
114 | ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); |
343 | ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); |
Line 224... | Line 453... | ||
224 | list_del_init(&lock->head); |
453 | list_del_init(&lock->head); |
225 | ww_mutex_unlock(&lock->mutex); |
454 | ww_mutex_unlock(&lock->mutex); |
226 | } |
455 | } |
227 | EXPORT_SYMBOL(drm_modeset_unlock); |
456 | EXPORT_SYMBOL(drm_modeset_unlock); |
Line 228... | Line -... | ||
228 | - | ||
229 | /* Temporary.. until we have sufficiently fine grained locking, there |
457 | |
230 | * are a couple scenarios where it is convenient to grab all crtc locks. |
458 | /* In some legacy codepaths it's convenient to just grab all the crtc and plane |
231 | * It is planned to remove this: |
- | |
232 | */ |
459 | * related locks. */ |
233 | int drm_modeset_lock_all_crtcs(struct drm_device *dev, |
460 | int drm_modeset_lock_all_crtcs(struct drm_device *dev, |
234 | struct drm_modeset_acquire_ctx *ctx) |
461 | struct drm_modeset_acquire_ctx *ctx) |
235 | { |
462 | { |
236 | struct drm_mode_config *config = &dev->mode_config; |
463 | struct drm_mode_config *config = &dev->mode_config; |
- | 464 | struct drm_crtc *crtc; |
|
237 | struct drm_crtc *crtc; |
465 | struct drm_plane *plane; |
Line 238... | Line 466... | ||
238 | int ret = 0; |
466 | int ret = 0; |
239 | 467 | ||
240 | list_for_each_entry(crtc, &config->crtc_list, head) { |
468 | list_for_each_entry(crtc, &config->crtc_list, head) { |
241 | ret = drm_modeset_lock(&crtc->mutex, ctx); |
469 | ret = drm_modeset_lock(&crtc->mutex, ctx); |
242 | if (ret) |
470 | if (ret) |
Line -... | Line 471... | ||
- | 471 | return ret; |
|
- | 472 | } |
|
- | 473 | ||
- | 474 | list_for_each_entry(plane, &config->plane_list, head) { |
|
- | 475 | ret = drm_modeset_lock(&plane->mutex, ctx); |
|
- | 476 | if (ret) |
|
243 | return ret; |
477 | return ret; |
244 | } |
478 | } |
245 | 479 |