0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <drm/drm_atomic.h>
0025 #include <drm/drm_crtc.h>
0026 #include <drm/drm_device.h>
0027 #include <drm/drm_modeset_lock.h>
0028 #include <drm/drm_print.h>
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 static DEFINE_WW_CLASS(crtc_ww_class);
0080
0081 #if IS_ENABLED(CONFIG_DRM_DEBUG_MODESET_LOCK)
0082 static noinline depot_stack_handle_t __drm_stack_depot_save(void)
0083 {
0084 unsigned long entries[8];
0085 unsigned int n;
0086
0087 n = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
0088
0089 return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN);
0090 }
0091
0092 static void __drm_stack_depot_print(depot_stack_handle_t stack_depot)
0093 {
0094 struct drm_printer p = drm_debug_printer("drm_modeset_lock");
0095 unsigned long *entries;
0096 unsigned int nr_entries;
0097 char *buf;
0098
0099 buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN);
0100 if (!buf)
0101 return;
0102
0103 nr_entries = stack_depot_fetch(stack_depot, &entries);
0104 stack_trace_snprint(buf, PAGE_SIZE, entries, nr_entries, 2);
0105
0106 drm_printf(&p, "attempting to lock a contended lock without backoff:\n%s", buf);
0107
0108 kfree(buf);
0109 }
0110
0111 static void __drm_stack_depot_init(void)
0112 {
0113 stack_depot_init();
0114 }
0115 #else
0116 static depot_stack_handle_t __drm_stack_depot_save(void)
0117 {
0118 return 0;
0119 }
0120 static void __drm_stack_depot_print(depot_stack_handle_t stack_depot)
0121 {
0122 }
0123 static void __drm_stack_depot_init(void)
0124 {
0125 }
0126 #endif
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143 void drm_modeset_lock_all(struct drm_device *dev)
0144 {
0145 struct drm_mode_config *config = &dev->mode_config;
0146 struct drm_modeset_acquire_ctx *ctx;
0147 int ret;
0148
0149 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
0150 if (WARN_ON(!ctx))
0151 return;
0152
0153 mutex_lock(&config->mutex);
0154
0155 drm_modeset_acquire_init(ctx, 0);
0156
0157 retry:
0158 ret = drm_modeset_lock_all_ctx(dev, ctx);
0159 if (ret < 0) {
0160 if (ret == -EDEADLK) {
0161 drm_modeset_backoff(ctx);
0162 goto retry;
0163 }
0164
0165 drm_modeset_acquire_fini(ctx);
0166 kfree(ctx);
0167 return;
0168 }
0169 ww_acquire_done(&ctx->ww_ctx);
0170
0171 WARN_ON(config->acquire_ctx);
0172
0173
0174
0175
0176
0177 config->acquire_ctx = ctx;
0178
0179 drm_warn_on_modeset_not_all_locked(dev);
0180 }
0181 EXPORT_SYMBOL(drm_modeset_lock_all);
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 void drm_modeset_unlock_all(struct drm_device *dev)
0198 {
0199 struct drm_mode_config *config = &dev->mode_config;
0200 struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
0201
0202 if (WARN_ON(!ctx))
0203 return;
0204
0205 config->acquire_ctx = NULL;
0206 drm_modeset_drop_locks(ctx);
0207 drm_modeset_acquire_fini(ctx);
0208
0209 kfree(ctx);
0210
0211 mutex_unlock(&dev->mode_config.mutex);
0212 }
0213 EXPORT_SYMBOL(drm_modeset_unlock_all);
0214
0215
0216
0217
0218
0219
0220
0221 void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
0222 {
0223 struct drm_crtc *crtc;
0224
0225
0226 if (oops_in_progress)
0227 return;
0228
0229 drm_for_each_crtc(crtc, dev)
0230 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
0231
0232 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
0233 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
0234 }
0235 EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
0247 uint32_t flags)
0248 {
0249 memset(ctx, 0, sizeof(*ctx));
0250 ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class);
0251 INIT_LIST_HEAD(&ctx->locked);
0252
0253 if (flags & DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
0254 ctx->interruptible = true;
0255 }
0256 EXPORT_SYMBOL(drm_modeset_acquire_init);
0257
0258
0259
0260
0261
0262 void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)
0263 {
0264 ww_acquire_fini(&ctx->ww_ctx);
0265 }
0266 EXPORT_SYMBOL(drm_modeset_acquire_fini);
0267
0268
0269
0270
0271
0272
0273
0274 void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)
0275 {
0276 if (WARN_ON(ctx->contended))
0277 __drm_stack_depot_print(ctx->stack_depot);
0278
0279 while (!list_empty(&ctx->locked)) {
0280 struct drm_modeset_lock *lock;
0281
0282 lock = list_first_entry(&ctx->locked,
0283 struct drm_modeset_lock, head);
0284
0285 drm_modeset_unlock(lock);
0286 }
0287 }
0288 EXPORT_SYMBOL(drm_modeset_drop_locks);
0289
0290 static inline int modeset_lock(struct drm_modeset_lock *lock,
0291 struct drm_modeset_acquire_ctx *ctx,
0292 bool interruptible, bool slow)
0293 {
0294 int ret;
0295
0296 if (WARN_ON(ctx->contended))
0297 __drm_stack_depot_print(ctx->stack_depot);
0298
0299 if (ctx->trylock_only) {
0300 lockdep_assert_held(&ctx->ww_ctx);
0301
0302 if (!ww_mutex_trylock(&lock->mutex, NULL))
0303 return -EBUSY;
0304 else
0305 return 0;
0306 } else if (interruptible && slow) {
0307 ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
0308 } else if (interruptible) {
0309 ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
0310 } else if (slow) {
0311 ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx);
0312 ret = 0;
0313 } else {
0314 ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx);
0315 }
0316 if (!ret) {
0317 WARN_ON(!list_empty(&lock->head));
0318 list_add(&lock->head, &ctx->locked);
0319 } else if (ret == -EALREADY) {
0320
0321
0322
0323
0324
0325 ret = 0;
0326 } else if (ret == -EDEADLK) {
0327 ctx->contended = lock;
0328 ctx->stack_depot = __drm_stack_depot_save();
0329 }
0330
0331 return ret;
0332 }
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
0347 {
0348 struct drm_modeset_lock *contended = ctx->contended;
0349
0350 ctx->contended = NULL;
0351 ctx->stack_depot = 0;
0352
0353 if (WARN_ON(!contended))
0354 return 0;
0355
0356 drm_modeset_drop_locks(ctx);
0357
0358 return modeset_lock(contended, ctx, ctx->interruptible, true);
0359 }
0360 EXPORT_SYMBOL(drm_modeset_backoff);
0361
0362
0363
0364
0365
0366 void drm_modeset_lock_init(struct drm_modeset_lock *lock)
0367 {
0368 ww_mutex_init(&lock->mutex, &crtc_ww_class);
0369 INIT_LIST_HEAD(&lock->head);
0370 __drm_stack_depot_init();
0371 }
0372 EXPORT_SYMBOL(drm_modeset_lock_init);
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392 int drm_modeset_lock(struct drm_modeset_lock *lock,
0393 struct drm_modeset_acquire_ctx *ctx)
0394 {
0395 if (ctx)
0396 return modeset_lock(lock, ctx, ctx->interruptible, false);
0397
0398 ww_mutex_lock(&lock->mutex, NULL);
0399 return 0;
0400 }
0401 EXPORT_SYMBOL(drm_modeset_lock);
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock)
0413 {
0414 return ww_mutex_lock_interruptible(&lock->mutex, NULL);
0415 }
0416 EXPORT_SYMBOL(drm_modeset_lock_single_interruptible);
0417
0418
0419
0420
0421
0422 void drm_modeset_unlock(struct drm_modeset_lock *lock)
0423 {
0424 list_del_init(&lock->head);
0425 ww_mutex_unlock(&lock->mutex);
0426 }
0427 EXPORT_SYMBOL(drm_modeset_unlock);
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449 int drm_modeset_lock_all_ctx(struct drm_device *dev,
0450 struct drm_modeset_acquire_ctx *ctx)
0451 {
0452 struct drm_private_obj *privobj;
0453 struct drm_crtc *crtc;
0454 struct drm_plane *plane;
0455 int ret;
0456
0457 ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
0458 if (ret)
0459 return ret;
0460
0461 drm_for_each_crtc(crtc, dev) {
0462 ret = drm_modeset_lock(&crtc->mutex, ctx);
0463 if (ret)
0464 return ret;
0465 }
0466
0467 drm_for_each_plane(plane, dev) {
0468 ret = drm_modeset_lock(&plane->mutex, ctx);
0469 if (ret)
0470 return ret;
0471 }
0472
0473 drm_for_each_privobj(privobj, dev) {
0474 ret = drm_modeset_lock(&privobj->lock, ctx);
0475 if (ret)
0476 return ret;
0477 }
0478
0479 return 0;
0480 }
0481 EXPORT_SYMBOL(drm_modeset_lock_all_ctx);