mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Javier Martinez Canillas <javierm@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: Maxime Ripard <mripard@kernel.org>,
	Dave Airlie <airlied@redhat.com>,
	Peter Robinson <pbrobinson@gmail.com>,
	Hans de Goede <johannes.goede@oss.qualcomm.com>,
	Javier Martinez Canillas <javierm@redhat.com>,
	Danilo Krummrich <dakr@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Luis Chamberlain <mcgrof@kernel.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Russ Weight <russ.weight@linux.dev>,
	driver-core@lists.linux.dev
Subject: [PATCH] firmware_loader: Expose requested firmware names as sysfs entries
Date: Sat, 17 Oct 2026 16:27:33 +0200	[thread overview]
Message-ID: <20261017142826.2668881-1-javierm@redhat.com> (raw)

Most initramfs image creation tools (e.g., dracut or initramfs-tools) have
options to create initramfs images that are either generic or tailored to
a running system. For example, dracut has the --host-only option for this.

That option allows to have a smaller initramfs image which only contains a
sub-set of the kernel modules, libraries, binaries and configuration data.

One thing that can't be queried in a running system is the set of firmware
names that were requested by the kernel to support the different devices.

Let's expose this information as sysfs entries to allow initramfs creation
tools to determine the set of firmware names that are needed by a system.

On an AM625 BeaglePlay board, the following will be exposed through sysfs:

  $ grep -H . /sys/class/firmware/requested*
  /sys/class/firmware/requested0:powervr/rogue_33.15.11.3_v1.fw
  /sys/class/firmware/requested1:ath3k-1.fw
  /sys/class/firmware/requested2:regulatory.db
  /sys/class/firmware/requested3:regulatory.db.p7s
  /sys/class/firmware/requested4:ti-connectivity/wl1271-nvs.bin
  /sys/class/firmware/requested5:ti-connectivity/wl18xx-conf.bin
  /sys/class/firmware/requested6:ti-connectivity/wl18xx-fw-4.bin

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
---

 .../ABI/testing/sysfs-class-firmware          | 19 +++++
 drivers/base/firmware_loader/Kconfig          | 14 ++++
 drivers/base/firmware_loader/main.c           |  2 +
 drivers/base/firmware_loader/sysfs.c          | 75 +++++++++++++++++++
 drivers/base/firmware_loader/sysfs.h          |  8 ++
 5 files changed, 118 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-firmware b/Documentation/ABI/testing/sysfs-class-firmware
index 44ca1b78a0e1..bae9d4bca0fb 100644
--- a/Documentation/ABI/testing/sysfs-class-firmware
+++ b/Documentation/ABI/testing/sysfs-class-firmware
@@ -75,3 +75,22 @@ Description:	This file supports the timeout mechanism for firmware
 		fallback.  This file has no affect on firmware uploads. For
 		more information on timeouts please see the documentation
 		for firmware fallback.
+
+What:		/sys/class/firmware/requestedN
+Date:		October 2026
+KernelVersion:	7.4
+Contact:	driver-core@lists.linux.dev
+Description:
+		Read-only, each file contains a string with the name of a
+		firmware that was requested and successfully loaded via the
+		firmware loader. The N number is a monotonically increasing
+		integer starting at 0, assigned in the order that the names
+		were requested.
+
+		The entries are global and deduplicated, if multiple devices
+		request to load the same firmware, it will appear just once.
+
+		Entries are never removed, so they represent all the firmware
+		names that were requested since the system booted. This list
+		is useful for user-space tools (such as initramfs generators)
+		to determine the set of firmware required by a running system.
diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig
index 15eff8a4b505..368aa8289d4f 100644
--- a/drivers/base/firmware_loader/Kconfig
+++ b/drivers/base/firmware_loader/Kconfig
@@ -221,6 +221,20 @@ config FW_CACHE
 
 	  If unsure, say Y.
 
+config FW_REQUESTED_SYSFS
+	bool "Expose requested firmware files as sysfs entries"
+	select FW_LOADER_SYSFS
+	help
+	  Enabling this option will track the names of firmware files requested
+	  and successfully loaded by the firmware loader. Each requestedN file
+	  under /sys/class/firmware/ contains the name of a requested firmware
+	  file that was loaded since the system booted.
+
+	  This information is useful for userspace tools (e.g. initramfs image
+	  generators), to determine the set of firmware required by a system.
+
+	  If unsure, say N.
+
 config FW_UPLOAD
 	bool "Enable users to initiate firmware updates using sysfs"
 	select FW_LOADER_SYSFS
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index 24213a0ea831..409b6274156e 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -909,6 +909,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 		fw = NULL;
 	} else {
 		fw_log_firmware_info(fw, name, device);
+		fw_add_requested_name(name);
 	}
 
 	*firmware_p = fw;
@@ -1736,6 +1737,7 @@ static int __init firmware_class_init(void)
 
 static void __exit firmware_class_exit(void)
 {
+	fw_requested_cleanup();
 	unregister_fw_pm_ops();
 	unregister_reboot_notifier(&fw_shutdown_nb);
 	unregister_sysfs_loader();
diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c
index 29a10d2ad537..0bc603d0d10c 100644
--- a/drivers/base/firmware_loader/sysfs.c
+++ b/drivers/base/firmware_loader/sysfs.c
@@ -423,3 +423,78 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
 exit:
 	return fw_sysfs;
 }
+
+#ifdef CONFIG_FW_REQUESTED_SYSFS
+struct fw_requested_entry {
+	struct list_head list;
+	struct class_attribute_string cas;
+	char name[];
+};
+
+static LIST_HEAD(fw_requested_list);
+static DEFINE_MUTEX(fw_requested_lock);
+static unsigned int fw_requested_count;
+
+void fw_add_requested_name(const char *name)
+{
+	struct fw_requested_entry *entry, *iter;
+	size_t len;
+	int ret;
+
+	mutex_lock(&fw_requested_lock);
+
+	/*
+	 * First check if the name already exists in the list,
+	 * each requested firmware should be present just once.
+	 */
+	list_for_each_entry(iter, &fw_requested_list, list) {
+		if (!strcmp(iter->name, name))
+			goto out_unlock;
+	}
+
+	len = strlen(name);
+	entry = kzalloc(sizeof(*entry) + len + 1, GFP_KERNEL);
+	if (!entry)
+		goto out_unlock;
+
+	memcpy(entry->name, name, len + 1);
+	entry->cas.str = entry->name;
+
+	sysfs_attr_init(&entry->cas.attr.attr);
+	entry->cas.attr.attr.name = kasprintf(GFP_KERNEL, "requested%u",
+					      fw_requested_count);
+	if (!entry->cas.attr.attr.name)
+		goto out_free_entry;
+
+	entry->cas.attr.attr.mode = 0444;
+	entry->cas.attr.show = show_class_attr_string;
+
+	ret = class_create_file(&firmware_class, &entry->cas.attr);
+	if (ret)
+		goto out_free_name;
+
+	list_add_tail(&entry->list, &fw_requested_list);
+	fw_requested_count++;
+	mutex_unlock(&fw_requested_lock);
+	return;
+
+out_free_name:
+	kfree(entry->cas.attr.attr.name);
+out_free_entry:
+	kfree(entry);
+out_unlock:
+	mutex_unlock(&fw_requested_lock);
+}
+
+void __exit fw_requested_cleanup(void)
+{
+	struct fw_requested_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &fw_requested_list, list) {
+		list_del(&entry->list);
+		class_remove_file(&firmware_class, &entry->cas.attr);
+		kfree(entry->cas.attr.attr.name);
+		kfree(entry);
+	}
+}
+#endif /* CONFIG_FW_REQUESTED_SYSFS */
diff --git a/drivers/base/firmware_loader/sysfs.h b/drivers/base/firmware_loader/sysfs.h
index 1cabea544a40..6ed79ad7f6c7 100644
--- a/drivers/base/firmware_loader/sysfs.h
+++ b/drivers/base/firmware_loader/sysfs.h
@@ -115,4 +115,12 @@ static inline void fw_upload_free(struct fw_sysfs *fw_sysfs)
 }
 #endif
 
+#ifdef CONFIG_FW_REQUESTED_SYSFS
+void fw_add_requested_name(const char *name);
+void __exit fw_requested_cleanup(void);
+#else
+static inline void fw_add_requested_name(const char *name) {}
+static inline void fw_requested_cleanup(void) {}
+#endif
+
 #endif /* __FIRMWARE_SYSFS_H */
-- 
2.56.0

base-commit: 902fdc5e6662a96de71887ce4c2a591231aed82d
branch: add-fw-sysfs


                 reply	other threads:[~2026-10-17 14:28 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261017142826.2668881-1-javierm@redhat.com \
    --to=javierm@redhat.com \
    --cc=airlied@redhat.com \
    --cc=dakr@kernel.org \
    --cc=driver-core@lists.linux.dev \
    --cc=gregkh@linuxfoundation.org \
    --cc=johannes.goede@oss.qualcomm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=mripard@kernel.org \
    --cc=pbrobinson@gmail.com \
    --cc=rafael@kernel.org \
    --cc=russ.weight@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®