IGT needs to toggle Bandwidth Allocation Mode on a live tunnel to validate BWA disable/re-enable flows and confirm the driver recovers allocation correctly. Add a writable 'bw_alloc_enable' file under each tunnel's debugfs subdir; reading returns 0/1 (round-trippable via kstrtobool_from_user()), writing toggles the BWA state. The writer serializes against teardown via mgr->debugfs_lock.
Cc: Imre Deak <[email protected]> Assisted-by: Copilot:claude-sonnet-4-6 Signed-off-by: Kunal Joshi <[email protected]> --- drivers/gpu/drm/display/drm_dp_tunnel.c | 77 ++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c index 79d35d0be6b75..b29dd59263ae2 100644 --- a/drivers/gpu/drm/display/drm_dp_tunnel.c +++ b/drivers/gpu/drm/display/drm_dp_tunnel.c @@ -213,9 +213,17 @@ struct drm_dp_tunnel_mgr { * also taken when flipping tunnel->destroyed in * drm_dp_tunnel_destroy() so debugfs writers and * drm_dp_tunnel_debugfs_add() can observe the teardown and - * bail out. It does NOT synchronize against driver-side - * modeset paths; the debug knobs are intended for test / - * validation use only. + * bail out. + * + * Note: the bw_alloc_enable writer holds this lock across + * drm_dp_tunnel_{enable,disable}_bw_alloc(), which issue + * AUX/DPCD transactions. No driver-side path takes this lock, + * so there is no nesting against AUX-internal locks; however + * callers must not acquire this lock from any context that + * already holds an AUX or DPCD lock. + * + * It does NOT synchronize against driver-side modeset paths; + * the debug knobs are intended for test / validation use only. */ struct mutex debugfs_lock; #endif @@ -2019,6 +2027,67 @@ static int tunnel_info_show(struct seq_file *m, void *data) } DEFINE_SHOW_ATTRIBUTE(tunnel_info); +static int tunnel_bw_alloc_enable_show(struct seq_file *m, void *data) +{ + struct drm_dp_tunnel *tunnel = m->private; + + /* + * Print 0/1 so the file is round-trippable through + * kstrtobool_from_user(): cat foo > saved && cat saved > foo. + * The human-readable state is also available in 'info'. + */ + seq_printf(m, "%d\n", drm_dp_tunnel_bw_alloc_is_enabled(tunnel)); + + return 0; +} + +static ssize_t tunnel_bw_alloc_enable_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_dp_tunnel *tunnel = m->private; + bool enable; + int ret; + + ret = kstrtobool_from_user(ubuf, len, &enable); + if (ret) + return ret; + + mutex_lock(&tunnel->group->mgr->debugfs_lock); + + if (tunnel->destroyed) { + ret = -ENODEV; + goto unlock; + } + + if (enable == drm_dp_tunnel_bw_alloc_is_enabled(tunnel)) + ret = 0; + else if (enable) + ret = drm_dp_tunnel_enable_bw_alloc(tunnel); + else + ret = drm_dp_tunnel_disable_bw_alloc(tunnel); + +unlock: + mutex_unlock(&tunnel->group->mgr->debugfs_lock); + + return ret < 0 ? ret : len; +} + +static int tunnel_bw_alloc_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, tunnel_bw_alloc_enable_show, inode->i_private); +} + +static const struct file_operations tunnel_bw_alloc_enable_fops = { + .owner = THIS_MODULE, + .open = tunnel_bw_alloc_enable_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = tunnel_bw_alloc_enable_write, +}; + /** * drm_dp_tunnel_debugfs_add - Add DP tunnel debugfs entries * @tunnel: Tunnel object the entries are registered for @@ -2079,6 +2148,8 @@ void drm_dp_tunnel_debugfs_add(struct drm_dp_tunnel *tunnel, struct dentry *root list_add(&d->link, &tunnel->debugfs_dirs); debugfs_create_file("info", 0444, dir, tunnel, &tunnel_info_fops); + debugfs_create_file("bw_alloc_enable", 0644, dir, tunnel, + &tunnel_bw_alloc_enable_fops); unlock: mutex_unlock(&tunnel->group->mgr->debugfs_lock); -- 2.25.1
