drivers/base/firmware_loader/main.c | 100 ++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
From: Corentin LABBE <clabbe@baylibre.com>
Checking if some firmware is missing need to check dmesg for error message,
and on some machine this information could be lost since dmesg uses a ring buffer.
Having the list of all firmware requests is useful in many situations,
like selecting the minimal list when doing some buildroot config
or reducing the size of linux-firmware on gentoo via saveconfig.
So for letting thoses tasks to be automated easily, it is better to have all
loaded firmware in one place.
This patch adds a debugfs with all firmware that was tried to be loaded and the
result of those actions.
Signed-off-by: Corentin LABBE <clabbe@baylibre.com>
---
Hello
I believe the list could setup more appropriate elsewhere in /sys, but
without idea, I used debugfs.
If you have better idea, let me know it.
Regards
drivers/base/firmware_loader/main.c | 100 ++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index 24213a0ea831..786d9b2b096e 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -11,7 +11,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/capability.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/errname.h>
#include <linux/kernel_read_file.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -35,6 +37,7 @@
#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <linux/security.h>
+#include <linux/seq_file.h>
#include <linux/zstd.h>
#include <linux/xz.h>
@@ -48,6 +51,95 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
MODULE_DESCRIPTION("Multi purpose firmware loading support");
MODULE_LICENSE("GPL");
+struct fw_loaded_entry {
+ struct list_head node;
+ const char *driver;
+ const char *fw_name;
+ int result;
+};
+
+static LIST_HEAD(fw_loaded_list);
+static DEFINE_MUTEX(fw_loaded_lock);
+static struct dentry *fw_debugfs_dir;
+
+static void fw_record_request(struct device *device, const char *name, int ret)
+{
+ const char *driver = device ? dev_driver_string(device) : "(none)";
+ struct fw_loaded_entry *entry;
+
+ if (!name || name[0] == '\0')
+ return;
+
+ guard(mutex)(&fw_loaded_lock);
+
+ /* Update in place if we have already seen this request. */
+ list_for_each_entry(entry, &fw_loaded_list, node) {
+ if (!strcmp(entry->driver, driver) &&
+ !strcmp(entry->fw_name, name)) {
+ entry->result = ret;
+ return;
+ }
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return;
+
+ entry->driver = kstrdup(driver, GFP_KERNEL);
+ entry->fw_name = kstrdup(name, GFP_KERNEL);
+ if (!entry->driver || !entry->fw_name) {
+ kfree(entry->driver);
+ kfree(entry->fw_name);
+ kfree(entry);
+ return;
+ }
+
+ entry->result = ret;
+ list_add_tail(&entry->node, &fw_loaded_list);
+}
+
+static int fw_list_show(struct seq_file *m, void *v)
+{
+ struct fw_loaded_entry *entry;
+
+ guard(mutex)(&fw_loaded_lock);
+
+ list_for_each_entry(entry, &fw_loaded_list, node) {
+ const char *name;
+
+ if (entry->result >= 0) {
+ seq_printf(m, "%s %s OK\n",
+ entry->driver, entry->fw_name);
+ continue;
+ }
+
+ name = errname(-entry->result);
+ if (name)
+ seq_printf(m, "%s %s %s\n",
+ entry->driver, entry->fw_name, name);
+ else
+ seq_printf(m, "%s %s %d\n",
+ entry->driver, entry->fw_name, entry->result);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(fw_list);
+
+static void fw_loaded_list_free(void)
+{
+ struct fw_loaded_entry *entry, *tmp;
+
+ guard(mutex)(&fw_loaded_lock);
+
+ list_for_each_entry_safe(entry, tmp, &fw_loaded_list, node) {
+ list_del(&entry->node);
+ kfree(entry->driver);
+ kfree(entry->fw_name);
+ kfree(entry);
+ }
+}
+
struct firmware_cache {
/* firmware_buf instance will be added into the below list */
spinlock_t lock;
@@ -911,6 +1003,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
fw_log_firmware_info(fw, name, device);
}
+ fw_record_request(device, name, ret);
+
*firmware_p = fw;
return ret;
}
@@ -1727,6 +1821,10 @@ static int __init firmware_class_init(void)
if (ret)
goto out;
+ fw_debugfs_dir = debugfs_create_dir("firmware_loader", NULL);
+ debugfs_create_file("firmware_list", 0444, fw_debugfs_dir, NULL,
+ &fw_list_fops);
+
return register_sysfs_loader();
out:
@@ -1739,6 +1837,8 @@ static void __exit firmware_class_exit(void)
unregister_fw_pm_ops();
unregister_reboot_notifier(&fw_shutdown_nb);
unregister_sysfs_loader();
+ debugfs_remove_recursive(fw_debugfs_dir);
+ fw_loaded_list_free();
}
fs_initcall(firmware_class_init);
--
2.53.0
(Cc: driver-core; please make sure to Cc all relevant mailing lists)
On Wed Jul 15, 2026 at 3:13 PM CEST, Corentin Labbe wrote:
> From: Corentin LABBE <clabbe@baylibre.com>
>
> Checking if some firmware is missing need to check dmesg for error message,
> and on some machine this information could be lost since dmesg uses a ring buffer.
> Having the list of all firmware requests is useful in many situations,
> like selecting the minimal list when doing some buildroot config
> or reducing the size of linux-firmware on gentoo via saveconfig.
The proposed implementation aside, I don't see why this needs a new kernel
interface.
- Why can't you use 'modinfo -F firmware' for all compiled modules?
- Don't you have a journal persisting the dmesg logs?
- Why can't you use kprobe_event on the kernel command line if you really need
a runtime trace?
Untested, but something like
kprobe_event=p:fw_req,_request_firmware,name=+0(%si):string
should work I think.
Thanks,
Danilo
Le Wed, Jul 15, 2026 at 07:23:25PM +0200, Danilo Krummrich a écrit : > (Cc: driver-core; please make sure to Cc all relevant mailing lists) > > On Wed Jul 15, 2026 at 3:13 PM CEST, Corentin Labbe wrote: > > From: Corentin LABBE <clabbe@baylibre.com> > > > > Checking if some firmware is missing need to check dmesg for error message, > > and on some machine this information could be lost since dmesg uses a ring buffer. > > Having the list of all firmware requests is useful in many situations, > > like selecting the minimal list when doing some buildroot config > > or reducing the size of linux-firmware on gentoo via saveconfig. > > The proposed implementation aside, I don't see why this needs a new kernel > interface. Hello You miss the point that I propose an easy way to know. All your proposals imply scripting, grepping in difference place. I propose a unique easy way to know the list, without any requirement > > - Why can't you use 'modinfo -F firmware' for all compiled modules? Because it display all possible firmware for each module, I want only required/tried module for the host system > - Don't you have a journal persisting the dmesg logs? > I propose something that work with embeded devices without storage and/or without syslog/journald. > - Why can't you use kprobe_event on the kernel command line if you really need > a runtime trace? > > Untested, but something like > > kprobe_event=p:fw_req,_request_firmware,name=+0(%si):string > > should work I think. This imply command line hacking, something I prefer to avoid, it is better when it just works without change. Thanks Regards
On Thu Jul 16, 2026 at 11:29 AM CEST, Corentin LABBE wrote: > Le Wed, Jul 15, 2026 at 07:23:25PM +0200, Danilo Krummrich a écrit : >> (Cc: driver-core; please make sure to Cc all relevant mailing lists) >> >> On Wed Jul 15, 2026 at 3:13 PM CEST, Corentin Labbe wrote: >> > From: Corentin LABBE <clabbe@baylibre.com> >> > >> > Checking if some firmware is missing need to check dmesg for error message, >> > and on some machine this information could be lost since dmesg uses a ring buffer. >> > Having the list of all firmware requests is useful in many situations, >> > like selecting the minimal list when doing some buildroot config >> > or reducing the size of linux-firmware on gentoo via saveconfig. >> >> The proposed implementation aside, I don't see why this needs a new kernel >> interface. > > Hello > > You miss the point that I propose an easy way to know. > All your proposals imply scripting, grepping in difference place. > I propose a unique easy way to know the list, without any requirement No, I get that, but I think that the overhead of the proposed patch is not justified, given that there are reasonable alternatives. >> Untested, but something like >> >> kprobe_event=p:fw_req,_request_firmware,name=+0(%si):string >> >> should work I think. > This imply command line hacking, something I prefer to avoid, it is better when it just works without change. Adding a kernel command line parameter seems perfectly reasonable for your use-case. We could maybe consider a dedicated TRACE_EVENT for firmware being loaded if this turns out to be a thing people commonly want to have, but for now it seems a kprobe_event works for your case.
© 2016 - 2026 Red Hat, Inc.