Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rust: firmware: add `module_firmware!` macro

Analogous to the `module!` macro `module_firmware!` adds additional
firmware path strings to the .modinfo section.

In contrast to `module!`, where path strings need to be string literals,
path strings can be composed with the `firmware::ModInfoBuilder`.

Some drivers require a lot of firmware files (such as nova-core) and
hence benefit from more flexibility composing firmware path strings.

Acked-by: Jarkko Sakkinen <jarkko@kernel.org>
Link: https://lore.kernel.org/r/20250306222336.23482-4-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+90 -1
+90 -1
rust/kernel/firmware.rs
··· 116 116 // be used from any thread. 117 117 unsafe impl Sync for Firmware {} 118 118 119 + /// Create firmware .modinfo entries. 120 + /// 121 + /// This macro is the counterpart of the C macro `MODULE_FIRMWARE()`, but instead of taking a 122 + /// simple string literals, which is already covered by the `firmware` field of 123 + /// [`crate::prelude::module!`], it allows the caller to pass a builder type, based on the 124 + /// [`ModInfoBuilder`], which can create the firmware modinfo strings in a more flexible way. 125 + /// 126 + /// Drivers should extend the [`ModInfoBuilder`] with their own driver specific builder type. 127 + /// 128 + /// The `builder` argument must be a type which implements the following function. 129 + /// 130 + /// `const fn create(module_name: &'static CStr) -> ModInfoBuilder` 131 + /// 132 + /// `create` should pass the `module_name` to the [`ModInfoBuilder`] and, with the help of 133 + /// it construct the corresponding firmware modinfo. 134 + /// 135 + /// Typically, such contracts would be enforced by a trait, however traits do not (yet) support 136 + /// const functions. 137 + /// 138 + /// # Example 139 + /// 140 + /// ``` 141 + /// # mod module_firmware_test { 142 + /// # use kernel::firmware; 143 + /// # use kernel::prelude::*; 144 + /// # 145 + /// # struct MyModule; 146 + /// # 147 + /// # impl kernel::Module for MyModule { 148 + /// # fn init(_module: &'static ThisModule) -> Result<Self> { 149 + /// # Ok(Self) 150 + /// # } 151 + /// # } 152 + /// # 153 + /// # 154 + /// struct Builder<const N: usize>; 155 + /// 156 + /// impl<const N: usize> Builder<N> { 157 + /// const DIR: &'static str = "vendor/chip/"; 158 + /// const FILES: [&'static str; 3] = [ "foo", "bar", "baz" ]; 159 + /// 160 + /// const fn create(module_name: &'static kernel::str::CStr) -> firmware::ModInfoBuilder<N> { 161 + /// let mut builder = firmware::ModInfoBuilder::new(module_name); 162 + /// 163 + /// let mut i = 0; 164 + /// while i < Self::FILES.len() { 165 + /// builder = builder.new_entry() 166 + /// .push(Self::DIR) 167 + /// .push(Self::FILES[i]) 168 + /// .push(".bin"); 169 + /// 170 + /// i += 1; 171 + /// } 172 + /// 173 + /// builder 174 + /// } 175 + /// } 176 + /// 177 + /// module! { 178 + /// type: MyModule, 179 + /// name: "module_firmware_test", 180 + /// author: "Rust for Linux", 181 + /// description: "module_firmware! test module", 182 + /// license: "GPL", 183 + /// } 184 + /// 185 + /// kernel::module_firmware!(Builder); 186 + /// # } 187 + /// ``` 188 + #[macro_export] 189 + macro_rules! module_firmware { 190 + // The argument is the builder type without the const generic, since it's deferred from within 191 + // this macro. Hence, we can neither use `expr` nor `ty`. 192 + ($($builder:tt)*) => { 193 + const _: () = { 194 + const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr = if cfg!(MODULE) { 195 + $crate::c_str!("") 196 + } else { 197 + <LocalModule as $crate::ModuleMetadata>::NAME 198 + }; 199 + 200 + #[link_section = ".modinfo"] 201 + #[used] 202 + static __MODULE_FIRMWARE: [u8; $($builder)*::create(__MODULE_FIRMWARE_PREFIX) 203 + .build_length()] = $($builder)*::create(__MODULE_FIRMWARE_PREFIX).build(); 204 + }; 205 + }; 206 + } 207 + 119 208 /// Builder for firmware module info. 120 209 /// 121 210 /// [`ModInfoBuilder`] is a helper component to flexibly compose firmware paths strings for the ··· 214 125 /// [`ModInfoBuilder::push`], where the latter is used to push path components and the former to 215 126 /// mark the beginning of a new path string. 216 127 /// 217 - /// [`ModInfoBuilder`] is meant to be used in combination with `kernel::module_firmware!`. 128 + /// [`ModInfoBuilder`] is meant to be used in combination with [`kernel::module_firmware!`]. 218 129 /// 219 130 /// The const generic `N` as well as the `module_name` parameter of [`ModInfoBuilder::new`] is an 220 131 /// internal implementation detail and supplied through the above macro.