* [PATCH v3] firmware: tegra: bpmp: populate debugfs in the background
@ 2026-11-03 6:11 Austin Schuh
0 siblings, 0 replies; only message in thread
From: Austin Schuh @ 2026-11-03 6:11 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter
Cc: Austin Schuh, Mikko Perttunen, Aniruddha Rao, linux-tegra,
linux-kernel
Populating the BPMP debugfs mirror takes several synchronous BPMP requests
per directory, which on Tegra234 adds up to seconds. The BPMP probe waits
for it, and nearly every other device on the SoC waits for the BPMP.
Nothing in the kernel uses the mirror, so populate it from the freezable
workqueue instead, which system suspend waits for. Create the mirror as
.debug-populating and rename it to debug once it is complete, so that
userspace never sees an incomplete state. Count the users of the shared
root, so that one BPMP failing doesn't remove it while another is still
populating.
On an Orin Nano with v7.3-rc1, the BPMP probe now takes 0.5 seconds
instead of 2.6.
Assisted-by: LLM
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
---
Notes:
Changes in v3:
- Shorten the commit message and comments.
- Populate several BPMPs in parallel, and count the users of the shared
root instead of holding its lock across the whole population.
Changes in v2:
- Embed the work_struct in struct tegra_bpmp, and cancel it with
cancel_work_sync() from a devm action.
- Create the mirror as .debug-populating and rename it to debug once it
is complete.
- Queue the work on system_freezable_wq, so that system suspend waits
for it.
- Hold bpmp_debugfs_root_lock across the whole population.
v2: https://lore.kernel.org/r/20261024055055.602558-1-austin.linux@gmail.com
v1: https://lore.kernel.org/r/20261017065012.3063980-1-austin.linux@gmail.com
drivers/firmware/tegra/bpmp-debugfs.c | 62 ++++++++++++++++++++++++---
include/soc/tegra/bpmp.h | 2 +
2 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c
index 2efc48b522ac..d90ef912b66c 100644
--- a/drivers/firmware/tegra/bpmp-debugfs.c
+++ b/drivers/firmware/tegra/bpmp-debugfs.c
@@ -774,6 +774,7 @@ static int bpmp_populate_debugfs_shmem(struct tegra_bpmp *bpmp)
static DEFINE_MUTEX(bpmp_debugfs_root_lock);
static struct dentry *bpmp_debugfs_root;
+static unsigned int bpmp_debugfs_root_users;
static bool bpmp_debugfs_enabled = true;
module_param_named(debugfs, bpmp_debugfs_enabled, bool, 0444);
@@ -785,19 +786,18 @@ static struct dentry *bpmp_debugfs_get_root(void)
guard(mutex)(&bpmp_debugfs_root_lock);
if (!bpmp_debugfs_root)
bpmp_debugfs_root = debugfs_create_dir("bpmp", NULL);
+ if (!IS_ERR(bpmp_debugfs_root))
+ bpmp_debugfs_root_users++;
return bpmp_debugfs_root;
}
-int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
+static int tegra_bpmp_populate_debugfs(struct tegra_bpmp *bpmp)
{
struct dentry *root, *d;
char name[32];
bool inband;
int err;
- if (!bpmp_debugfs_enabled)
- return 0;
-
inband = tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUG);
if (!inband && !tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
@@ -818,7 +818,11 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
}
}
- bpmp->debugfs_mirror = debugfs_create_dir("debug", d);
+ /*
+ * Name the mirror "debug" only once it is complete, so that userspace
+ * never sees an incomplete state.
+ */
+ bpmp->debugfs_mirror = debugfs_create_dir(".debug-populating", d);
if (IS_ERR(bpmp->debugfs_mirror)) {
err = PTR_ERR(bpmp->debugfs_mirror);
goto out;
@@ -830,15 +834,19 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
else
err = bpmp_populate_debugfs_shmem(bpmp);
+ if (!err)
+ err = debugfs_change_name(bpmp->debugfs_mirror, "debug");
+
out:
if (err < 0) {
if (!IS_ERR(d))
debugfs_remove_recursive(d);
guard(mutex)(&bpmp_debugfs_root_lock);
+ bpmp_debugfs_root_users--;
if (root == d) {
bpmp_debugfs_root = NULL;
- } else if (simple_empty(root)) {
+ } else if (!bpmp_debugfs_root_users) {
debugfs_remove(root);
bpmp_debugfs_root = NULL;
}
@@ -846,3 +854,45 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
return err;
}
+
+static void tegra_bpmp_debugfs_work(struct work_struct *work)
+{
+ struct tegra_bpmp *bpmp =
+ container_of(work, struct tegra_bpmp, debugfs_work);
+ int err;
+
+ err = tegra_bpmp_populate_debugfs(bpmp);
+ if (err < 0)
+ dev_err(bpmp->dev, "debugfs initialization failed: %d\n", err);
+}
+
+static void tegra_bpmp_cancel_debugfs(void *data)
+{
+ struct tegra_bpmp *bpmp = data;
+
+ cancel_work_sync(&bpmp->debugfs_work);
+}
+
+int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
+{
+ int err;
+
+ if (!bpmp_debugfs_enabled)
+ return 0;
+
+ INIT_WORK(&bpmp->debugfs_work, tegra_bpmp_debugfs_work);
+
+ err = devm_add_action_or_reset(bpmp->dev, tegra_bpmp_cancel_debugfs,
+ bpmp);
+ if (err < 0)
+ return err;
+
+ /*
+ * Mirroring the BPMP's debugfs tree can take several seconds, so do
+ * it asynchronously, on the freezable workqueue so that system
+ * suspend doesn't make its requests fail.
+ */
+ queue_work(system_freezable_wq, &bpmp->debugfs_work);
+
+ return 0;
+}
diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h
index f55db918ccb1..f961c265326c 100644
--- a/include/soc/tegra/bpmp.h
+++ b/include/soc/tegra/bpmp.h
@@ -12,6 +12,7 @@
#include <linux/reset-controller.h>
#include <linux/semaphore.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <soc/tegra/bpmp-abi.h>
@@ -103,6 +104,7 @@ struct tegra_bpmp {
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_mirror;
+ struct work_struct debugfs_work;
#endif
bool suspended;
base-commit: 1bbcf4a19f1495f769b69e9569d8c1e81df074f5
--
2.47.3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-03 6:11 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 6:11 [PATCH v3] firmware: tegra: bpmp: populate debugfs in the background Austin Schuh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox