aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2017-09-12 09:37:44 -0400
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2017-09-13 03:50:52 -0400
commit6f8bcc744aad50d719845e4ce06a7831e96e1109 (patch)
treeb80456af140c02f8b25c778bd01f54acc85df2b5
parent9ab12e88a0b46b4e6fa32bb0a2875c813a928e73 (diff)
drm/atomic: Prepare drm_modeset_lock infrastructure for interruptible waiting, v2.
When we want to make drm_atomic_commit interruptible, there are a lot of places that call the lock function, which we don't have control over. Rather than trying to convert every single one, it's easier to toggle interruptible waiting per acquire_ctx. If drm_modeset_acquire_init is called with DRM_MODESET_ACQUIRE_INTERRUPTIBLE, then we will perform interruptible waits in drm_modeset_lock and drm_modeset_backoff. Changes since v1: - Fix locking example in drm_modeset_lock.c to be compatible with interruptible waiting (xexaxo) and make it default. Uninterruptible waiting shouldn't happen except in corner cases, but the example will still apply if the flag is removed. - Add drm_modeset_lock_single_interruptible() to documentation. - Fix dead link to removed drm_modeset_lock_interruptible() in drm_modeset_lock(). Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> #v1 Cc: Emil Velikov <emil.l.velikov@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20170912133749.6532-2-maarten.lankhorst@linux.intel.com Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
-rw-r--r--drivers/gpu/drm/drm_debugfs_crc.c2
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c96
-rw-r--r--include/drm/drm_modeset_lock.h12
3 files changed, 57 insertions, 53 deletions
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c
index f9e26dda56d6..9dd879589a2c 100644
--- a/drivers/gpu/drm/drm_debugfs_crc.c
+++ b/drivers/gpu/drm/drm_debugfs_crc.c
@@ -155,7 +155,7 @@ static int crtc_crc_open(struct inode *inode, struct file *filep)
155 int ret = 0; 155 int ret = 0;
156 156
157 if (drm_drv_uses_atomic_modeset(crtc->dev)) { 157 if (drm_drv_uses_atomic_modeset(crtc->dev)) {
158 ret = drm_modeset_lock_interruptible(&crtc->mutex, NULL); 158 ret = drm_modeset_lock_single_interruptible(&crtc->mutex);
159 if (ret) 159 if (ret)
160 return ret; 160 return ret;
161 161
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index af4e906c630d..e123497da0ca 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -39,23 +39,28 @@
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, DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
43 * retry: 43 * retry:
44 * foreach (lock in random_ordered_set_of_locks) { 44 * foreach (lock in random_ordered_set_of_locks) {
45 * ret = drm_modeset_lock(lock, &ctx) 45 * ret = drm_modeset_lock(lock, ctx)
46 * if (ret == -EDEADLK) { 46 * if (ret == -EDEADLK) {
47 * drm_modeset_backoff(&ctx); 47 * ret = drm_modeset_backoff(ctx);
48 * goto retry; 48 * if (!ret)
49 * goto retry;
49 * } 50 * }
51 * if (ret)
52 * goto out;
50 * } 53 * }
51 * ... do stuff ... 54 * ... do stuff ...
52 * drm_modeset_drop_locks(&ctx); 55 * out:
53 * drm_modeset_acquire_fini(&ctx); 56 * drm_modeset_drop_locks(ctx);
57 * drm_modeset_acquire_fini(ctx);
54 * 58 *
55 * If all that is needed is a single modeset lock, then the &struct 59 * If all that is needed is a single modeset lock, then the &struct
56 * drm_modeset_acquire_ctx is not needed and the locking can be simplified 60 * drm_modeset_acquire_ctx is not needed and the locking can be simplified
57 * by passing a NULL instead of ctx in the drm_modeset_lock() 61 * by passing a NULL instead of ctx in the drm_modeset_lock() call or
58 * call and, when done, by calling drm_modeset_unlock(). 62 * calling drm_modeset_lock_single_interruptible(). To unlock afterwards
63 * call drm_modeset_unlock().
59 * 64 *
60 * On top of these per-object locks using &ww_mutex there's also an overall 65 * On top of these per-object locks using &ww_mutex there's also an overall
61 * &drm_mode_config.mutex, for protecting everything else. Mostly this means 66 * &drm_mode_config.mutex, for protecting everything else. Mostly this means
@@ -178,7 +183,11 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
178/** 183/**
179 * drm_modeset_acquire_init - initialize acquire context 184 * drm_modeset_acquire_init - initialize acquire context
180 * @ctx: the acquire context 185 * @ctx: the acquire context
181 * @flags: for future 186 * @flags: 0 or %DRM_MODESET_ACQUIRE_INTERRUPTIBLE
187 *
188 * When passing %DRM_MODESET_ACQUIRE_INTERRUPTIBLE to @flags,
189 * all calls to drm_modeset_lock() will perform an interruptible
190 * wait.
182 */ 191 */
183void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 192void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
184 uint32_t flags) 193 uint32_t flags)
@@ -186,6 +195,9 @@ void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
186 memset(ctx, 0, sizeof(*ctx)); 195 memset(ctx, 0, sizeof(*ctx));
187 ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); 196 ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class);
188 INIT_LIST_HEAD(&ctx->locked); 197 INIT_LIST_HEAD(&ctx->locked);
198
199 if (flags & DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
200 ctx->interruptible = true;
189} 201}
190EXPORT_SYMBOL(drm_modeset_acquire_init); 202EXPORT_SYMBOL(drm_modeset_acquire_init);
191 203
@@ -261,8 +273,19 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
261 return ret; 273 return ret;
262} 274}
263 275
264static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, 276/**
265 bool interruptible) 277 * drm_modeset_backoff - deadlock avoidance backoff
278 * @ctx: the acquire context
279 *
280 * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK),
281 * you must call this function to drop all currently held locks and
282 * block until the contended lock becomes available.
283 *
284 * This function returns 0 on success, or -ERESTARTSYS if this context
285 * is initialized with %DRM_MODESET_ACQUIRE_INTERRUPTIBLE and the
286 * wait has been interrupted.
287 */
288int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
266{ 289{
267 struct drm_modeset_lock *contended = ctx->contended; 290 struct drm_modeset_lock *contended = ctx->contended;
268 291
@@ -273,36 +296,11 @@ static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx,
273 296
274 drm_modeset_drop_locks(ctx); 297 drm_modeset_drop_locks(ctx);
275 298
276 return modeset_lock(contended, ctx, interruptible, true); 299 return modeset_lock(contended, ctx, ctx->interruptible, true);
277}
278
279/**
280 * drm_modeset_backoff - deadlock avoidance backoff
281 * @ctx: the acquire context
282 *
283 * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK),
284 * you must call this function to drop all currently held locks and
285 * block until the contended lock becomes available.
286 */
287void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
288{
289 modeset_backoff(ctx, false);
290} 300}
291EXPORT_SYMBOL(drm_modeset_backoff); 301EXPORT_SYMBOL(drm_modeset_backoff);
292 302
293/** 303/**
294 * drm_modeset_backoff_interruptible - deadlock avoidance backoff
295 * @ctx: the acquire context
296 *
297 * Interruptible version of drm_modeset_backoff()
298 */
299int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx)
300{
301 return modeset_backoff(ctx, true);
302}
303EXPORT_SYMBOL(drm_modeset_backoff_interruptible);
304
305/**
306 * drm_modeset_lock_init - initialize lock 304 * drm_modeset_lock_init - initialize lock
307 * @lock: lock to init 305 * @lock: lock to init
308 */ 306 */
@@ -324,14 +322,18 @@ EXPORT_SYMBOL(drm_modeset_lock_init);
324 * deadlock scenario has been detected and it is an error to attempt 322 * deadlock scenario has been detected and it is an error to attempt
325 * to take any more locks without first calling drm_modeset_backoff(). 323 * to take any more locks without first calling drm_modeset_backoff().
326 * 324 *
325 * If the @ctx is not NULL and initialized with
326 * %DRM_MODESET_ACQUIRE_INTERRUPTIBLE, this function will fail with
327 * -ERESTARTSYS when interrupted.
328 *
327 * If @ctx is NULL then the function call behaves like a normal, 329 * If @ctx is NULL then the function call behaves like a normal,
328 * non-nesting mutex_lock() call. 330 * uninterruptible non-nesting mutex_lock() call.
329 */ 331 */
330int drm_modeset_lock(struct drm_modeset_lock *lock, 332int drm_modeset_lock(struct drm_modeset_lock *lock,
331 struct drm_modeset_acquire_ctx *ctx) 333 struct drm_modeset_acquire_ctx *ctx)
332{ 334{
333 if (ctx) 335 if (ctx)
334 return modeset_lock(lock, ctx, false, false); 336 return modeset_lock(lock, ctx, ctx->interruptible, false);
335 337
336 ww_mutex_lock(&lock->mutex, NULL); 338 ww_mutex_lock(&lock->mutex, NULL);
337 return 0; 339 return 0;
@@ -339,21 +341,19 @@ int drm_modeset_lock(struct drm_modeset_lock *lock,
339EXPORT_SYMBOL(drm_modeset_lock); 341EXPORT_SYMBOL(drm_modeset_lock);
340 342
341/** 343/**
342 * drm_modeset_lock_interruptible - take modeset lock 344 * drm_modeset_lock_single_interruptible - take a single modeset lock
343 * @lock: lock to take 345 * @lock: lock to take
344 * @ctx: acquire ctx
345 * 346 *
346 * Interruptible version of drm_modeset_lock() 347 * This function behaves as drm_modeset_lock() with a NULL context,
348 * but performs interruptible waits.
349 *
350 * This function returns 0 on success, or -ERESTARTSYS when interrupted.
347 */ 351 */
348int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 352int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock)
349 struct drm_modeset_acquire_ctx *ctx)
350{ 353{
351 if (ctx)
352 return modeset_lock(lock, ctx, true, false);
353
354 return ww_mutex_lock_interruptible(&lock->mutex, NULL); 354 return ww_mutex_lock_interruptible(&lock->mutex, NULL);
355} 355}
356EXPORT_SYMBOL(drm_modeset_lock_interruptible); 356EXPORT_SYMBOL(drm_modeset_lock_single_interruptible);
357 357
358/** 358/**
359 * drm_modeset_unlock - drop modeset lock 359 * drm_modeset_unlock - drop modeset lock
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
index 4b27c2bb955c..a685d1bb21f2 100644
--- a/include/drm/drm_modeset_lock.h
+++ b/include/drm/drm_modeset_lock.h
@@ -34,6 +34,7 @@ struct drm_modeset_lock;
34 * @contended: used internally for -EDEADLK handling 34 * @contended: used internally for -EDEADLK handling
35 * @locked: list of held locks 35 * @locked: list of held locks
36 * @trylock_only: trylock mode used in atomic contexts/panic notifiers 36 * @trylock_only: trylock mode used in atomic contexts/panic notifiers
37 * @interruptible: whether interruptible locking should be used.
37 * 38 *
38 * Each thread competing for a set of locks must use one acquire 39 * Each thread competing for a set of locks must use one acquire
39 * ctx. And if any lock fxn returns -EDEADLK, it must backoff and 40 * ctx. And if any lock fxn returns -EDEADLK, it must backoff and
@@ -59,6 +60,9 @@ struct drm_modeset_acquire_ctx {
59 * Trylock mode, use only for panic handlers! 60 * Trylock mode, use only for panic handlers!
60 */ 61 */
61 bool trylock_only; 62 bool trylock_only;
63
64 /* Perform interruptible waits on this context. */
65 bool interruptible;
62}; 66};
63 67
64/** 68/**
@@ -82,12 +86,13 @@ struct drm_modeset_lock {
82 struct list_head head; 86 struct list_head head;
83}; 87};
84 88
89#define DRM_MODESET_ACQUIRE_INTERRUPTIBLE BIT(0)
90
85void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 91void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
86 uint32_t flags); 92 uint32_t flags);
87void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); 93void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx);
88void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); 94void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx);
89void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); 95int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx);
90int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx);
91 96
92void drm_modeset_lock_init(struct drm_modeset_lock *lock); 97void drm_modeset_lock_init(struct drm_modeset_lock *lock);
93 98
@@ -111,8 +116,7 @@ static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock)
111 116
112int drm_modeset_lock(struct drm_modeset_lock *lock, 117int drm_modeset_lock(struct drm_modeset_lock *lock,
113 struct drm_modeset_acquire_ctx *ctx); 118 struct drm_modeset_acquire_ctx *ctx);
114int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 119int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock);
115 struct drm_modeset_acquire_ctx *ctx);
116void drm_modeset_unlock(struct drm_modeset_lock *lock); 120void drm_modeset_unlock(struct drm_modeset_lock *lock);
117 121
118struct drm_device; 122struct drm_device;