1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <drm/drmP.h>
25#include <drm/drm_crtc.h>
26#include <drm/drm_modeset_lock.h>
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66void drm_modeset_lock_all(struct drm_device *dev)
67{
68 struct drm_mode_config *config = &dev->mode_config;
69 struct drm_modeset_acquire_ctx *ctx;
70 int ret;
71
72 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
73 if (WARN_ON(!ctx))
74 return;
75
76 mutex_lock(&config->mutex);
77
78 drm_modeset_acquire_init(ctx, 0);
79
80retry:
81 ret = drm_modeset_lock(&config->connection_mutex, ctx);
82 if (ret)
83 goto fail;
84 ret = drm_modeset_lock_all_crtcs(dev, ctx);
85 if (ret)
86 goto fail;
87
88 WARN_ON(config->acquire_ctx);
89
90
91
92
93 config->acquire_ctx = ctx;
94
95 drm_warn_on_modeset_not_all_locked(dev);
96
97 return;
98
99fail:
100 if (ret == -EDEADLK) {
101 drm_modeset_backoff(ctx);
102 goto retry;
103 }
104
105 kfree(ctx);
106}
107EXPORT_SYMBOL(drm_modeset_lock_all);
108
109
110
111
112
113
114
115void drm_modeset_unlock_all(struct drm_device *dev)
116{
117 struct drm_mode_config *config = &dev->mode_config;
118 struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
119
120 if (WARN_ON(!ctx))
121 return;
122
123 config->acquire_ctx = NULL;
124 drm_modeset_drop_locks(ctx);
125 drm_modeset_acquire_fini(ctx);
126
127 kfree(ctx);
128
129 mutex_unlock(&dev->mode_config.mutex);
130}
131EXPORT_SYMBOL(drm_modeset_unlock_all);
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146void drm_modeset_lock_crtc(struct drm_crtc *crtc,
147 struct drm_plane *plane)
148{
149 struct drm_modeset_acquire_ctx *ctx;
150 int ret;
151
152 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
153 if (WARN_ON(!ctx))
154 return;
155
156 drm_modeset_acquire_init(ctx, 0);
157
158retry:
159 ret = drm_modeset_lock(&crtc->mutex, ctx);
160 if (ret)
161 goto fail;
162
163 if (plane) {
164 ret = drm_modeset_lock(&plane->mutex, ctx);
165 if (ret)
166 goto fail;
167
168 if (plane->crtc) {
169 ret = drm_modeset_lock(&plane->crtc->mutex, ctx);
170 if (ret)
171 goto fail;
172 }
173 }
174
175 WARN_ON(crtc->acquire_ctx);
176
177
178
179
180 crtc->acquire_ctx = ctx;
181
182 return;
183
184fail:
185 if (ret == -EDEADLK) {
186 drm_modeset_backoff(ctx);
187 goto retry;
188 }
189}
190EXPORT_SYMBOL(drm_modeset_lock_crtc);
191
192
193
194
195
196
197
198
199
200
201struct drm_modeset_acquire_ctx *
202drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
203{
204 if (crtc->acquire_ctx)
205 return crtc->acquire_ctx;
206
207 WARN_ON(!crtc->dev->mode_config.acquire_ctx);
208
209 return crtc->dev->mode_config.acquire_ctx;
210}
211EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
212
213
214
215
216
217
218
219
220void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
221{
222 struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
223
224 if (WARN_ON(!ctx))
225 return;
226
227 crtc->acquire_ctx = NULL;
228 drm_modeset_drop_locks(ctx);
229 drm_modeset_acquire_fini(ctx);
230
231 kfree(ctx);
232}
233EXPORT_SYMBOL(drm_modeset_unlock_crtc);
234
235
236
237
238
239
240
241void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
242{
243 struct drm_crtc *crtc;
244
245
246 if (oops_in_progress)
247 return;
248
249 drm_for_each_crtc(crtc, dev)
250 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
251
252 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
253 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
254}
255EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
256
257
258
259
260
261
262void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
263 uint32_t flags)
264{
265 memset(ctx, 0, sizeof(*ctx));
266 ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class);
267 INIT_LIST_HEAD(&ctx->locked);
268}
269EXPORT_SYMBOL(drm_modeset_acquire_init);
270
271
272
273
274
275void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)
276{
277 ww_acquire_fini(&ctx->ww_ctx);
278}
279EXPORT_SYMBOL(drm_modeset_acquire_fini);
280
281
282
283
284
285
286
287void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)
288{
289 WARN_ON(ctx->contended);
290 while (!list_empty(&ctx->locked)) {
291 struct drm_modeset_lock *lock;
292
293 lock = list_first_entry(&ctx->locked,
294 struct drm_modeset_lock, head);
295
296 drm_modeset_unlock(lock);
297 }
298}
299EXPORT_SYMBOL(drm_modeset_drop_locks);
300
301static inline int modeset_lock(struct drm_modeset_lock *lock,
302 struct drm_modeset_acquire_ctx *ctx,
303 bool interruptible, bool slow)
304{
305 int ret;
306
307 WARN_ON(ctx->contended);
308
309 if (ctx->trylock_only) {
310 if (!ww_mutex_trylock(&lock->mutex))
311 return -EBUSY;
312 else
313 return 0;
314 } else if (interruptible && slow) {
315 ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
316 } else if (interruptible) {
317 ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
318 } else if (slow) {
319 ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx);
320 ret = 0;
321 } else {
322 ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx);
323 }
324 if (!ret) {
325 WARN_ON(!list_empty(&lock->head));
326 list_add(&lock->head, &ctx->locked);
327 } else if (ret == -EALREADY) {
328
329
330
331
332
333 ret = 0;
334 } else if (ret == -EDEADLK) {
335 ctx->contended = lock;
336 }
337
338 return ret;
339}
340
341static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx,
342 bool interruptible)
343{
344 struct drm_modeset_lock *contended = ctx->contended;
345
346 ctx->contended = NULL;
347
348 if (WARN_ON(!contended))
349 return 0;
350
351 drm_modeset_drop_locks(ctx);
352
353 return modeset_lock(contended, ctx, interruptible, true);
354}
355
356
357
358
359
360
361
362
363
364void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
365{
366 modeset_backoff(ctx, false);
367}
368EXPORT_SYMBOL(drm_modeset_backoff);
369
370
371
372
373
374
375
376int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx)
377{
378 return modeset_backoff(ctx, true);
379}
380EXPORT_SYMBOL(drm_modeset_backoff_interruptible);
381
382
383
384
385
386
387
388
389
390
391
392
393int drm_modeset_lock(struct drm_modeset_lock *lock,
394 struct drm_modeset_acquire_ctx *ctx)
395{
396 if (ctx)
397 return modeset_lock(lock, ctx, false, false);
398
399 ww_mutex_lock(&lock->mutex, NULL);
400 return 0;
401}
402EXPORT_SYMBOL(drm_modeset_lock);
403
404
405
406
407
408
409
410
411int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
412 struct drm_modeset_acquire_ctx *ctx)
413{
414 if (ctx)
415 return modeset_lock(lock, ctx, true, false);
416
417 return ww_mutex_lock_interruptible(&lock->mutex, NULL);
418}
419EXPORT_SYMBOL(drm_modeset_lock_interruptible);
420
421
422
423
424
425void drm_modeset_unlock(struct drm_modeset_lock *lock)
426{
427 list_del_init(&lock->head);
428 ww_mutex_unlock(&lock->mutex);
429}
430EXPORT_SYMBOL(drm_modeset_unlock);
431
432
433
434int drm_modeset_lock_all_crtcs(struct drm_device *dev,
435 struct drm_modeset_acquire_ctx *ctx)
436{
437 struct drm_crtc *crtc;
438 struct drm_plane *plane;
439 int ret = 0;
440
441 drm_for_each_crtc(crtc, dev) {
442 ret = drm_modeset_lock(&crtc->mutex, ctx);
443 if (ret)
444 return ret;
445 }
446
447 drm_for_each_plane(plane, dev) {
448 ret = drm_modeset_lock(&plane->mutex, ctx);
449 if (ret)
450 return ret;
451 }
452
453 return 0;
454}
455EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
456