diff options
Diffstat (limited to 'drivers/gpu/drm/drm_modeset_lock.c')
| -rw-r--r-- | drivers/gpu/drm/drm_modeset_lock.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index fcfe1a03c4a1..beb91a13a312 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -21,10 +21,13 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include <linux/export.h> + #include <drm/drm_atomic.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> #include <drm/drm_modeset_lock.h> +#include <drm/drm_print.h> /** * DOC: kms locking @@ -77,6 +80,53 @@ static DEFINE_WW_CLASS(crtc_ww_class); +#if IS_ENABLED(CONFIG_DRM_DEBUG_MODESET_LOCK) +static noinline depot_stack_handle_t __drm_stack_depot_save(void) +{ + unsigned long entries[8]; + unsigned int n; + + n = stack_trace_save(entries, ARRAY_SIZE(entries), 1); + + return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); +} + +static void __drm_stack_depot_print(depot_stack_handle_t stack_depot) +{ + struct drm_printer p = drm_dbg_printer(NULL, DRM_UT_KMS, "drm_modeset_lock"); + unsigned long *entries; + unsigned int nr_entries; + char *buf; + + buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); + if (!buf) + return; + + nr_entries = stack_depot_fetch(stack_depot, &entries); + stack_trace_snprint(buf, PAGE_SIZE, entries, nr_entries, 2); + + drm_printf(&p, "attempting to lock a contended lock without backoff:\n%s", buf); + + kfree(buf); +} + +static void __drm_stack_depot_init(void) +{ + stack_depot_init(); +} +#else /* CONFIG_DRM_DEBUG_MODESET_LOCK */ +static depot_stack_handle_t __drm_stack_depot_save(void) +{ + return 0; +} +static void __drm_stack_depot_print(depot_stack_handle_t stack_depot) +{ +} +static void __drm_stack_depot_init(void) +{ +} +#endif /* CONFIG_DRM_DEBUG_MODESET_LOCK */ + /** * drm_modeset_lock_all - take all modeset locks * @dev: DRM device @@ -225,7 +275,9 @@ EXPORT_SYMBOL(drm_modeset_acquire_fini); */ void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) { - WARN_ON(ctx->contended); + if (WARN_ON(ctx->contended)) + __drm_stack_depot_print(ctx->stack_depot); + while (!list_empty(&ctx->locked)) { struct drm_modeset_lock *lock; @@ -243,12 +295,13 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, { int ret; - WARN_ON(ctx->contended); + if (WARN_ON(ctx->contended)) + __drm_stack_depot_print(ctx->stack_depot); if (ctx->trylock_only) { lockdep_assert_held(&ctx->ww_ctx); - if (!ww_mutex_trylock(&lock->mutex)) + if (!ww_mutex_trylock(&lock->mutex, NULL)) return -EBUSY; else return 0; @@ -274,6 +327,7 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, ret = 0; } else if (ret == -EDEADLK) { ctx->contended = lock; + ctx->stack_depot = __drm_stack_depot_save(); } return ret; @@ -296,6 +350,7 @@ int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) struct drm_modeset_lock *contended = ctx->contended; ctx->contended = NULL; + ctx->stack_depot = 0; if (WARN_ON(!contended)) return 0; @@ -314,6 +369,7 @@ void drm_modeset_lock_init(struct drm_modeset_lock *lock) { ww_mutex_init(&lock->mutex, &crtc_ww_class); INIT_LIST_HEAD(&lock->head); + __drm_stack_depot_init(); } EXPORT_SYMBOL(drm_modeset_lock_init); |
