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>
This commit is contained in:
parent
ef476b0dd9
commit
1d121a33ad
|
|
@ -116,6 +116,95 @@ unsafe impl Send for Firmware {}
|
|||
// be used from any thread.
|
||||
unsafe impl Sync for Firmware {}
|
||||
|
||||
/// Create firmware .modinfo entries.
|
||||
///
|
||||
/// This macro is the counterpart of the C macro `MODULE_FIRMWARE()`, but instead of taking a
|
||||
/// simple string literals, which is already covered by the `firmware` field of
|
||||
/// [`crate::prelude::module!`], it allows the caller to pass a builder type, based on the
|
||||
/// [`ModInfoBuilder`], which can create the firmware modinfo strings in a more flexible way.
|
||||
///
|
||||
/// Drivers should extend the [`ModInfoBuilder`] with their own driver specific builder type.
|
||||
///
|
||||
/// The `builder` argument must be a type which implements the following function.
|
||||
///
|
||||
/// `const fn create(module_name: &'static CStr) -> ModInfoBuilder`
|
||||
///
|
||||
/// `create` should pass the `module_name` to the [`ModInfoBuilder`] and, with the help of
|
||||
/// it construct the corresponding firmware modinfo.
|
||||
///
|
||||
/// Typically, such contracts would be enforced by a trait, however traits do not (yet) support
|
||||
/// const functions.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # mod module_firmware_test {
|
||||
/// # use kernel::firmware;
|
||||
/// # use kernel::prelude::*;
|
||||
/// #
|
||||
/// # struct MyModule;
|
||||
/// #
|
||||
/// # impl kernel::Module for MyModule {
|
||||
/// # fn init(_module: &'static ThisModule) -> Result<Self> {
|
||||
/// # Ok(Self)
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// #
|
||||
/// struct Builder<const N: usize>;
|
||||
///
|
||||
/// impl<const N: usize> Builder<N> {
|
||||
/// const DIR: &'static str = "vendor/chip/";
|
||||
/// const FILES: [&'static str; 3] = [ "foo", "bar", "baz" ];
|
||||
///
|
||||
/// const fn create(module_name: &'static kernel::str::CStr) -> firmware::ModInfoBuilder<N> {
|
||||
/// let mut builder = firmware::ModInfoBuilder::new(module_name);
|
||||
///
|
||||
/// let mut i = 0;
|
||||
/// while i < Self::FILES.len() {
|
||||
/// builder = builder.new_entry()
|
||||
/// .push(Self::DIR)
|
||||
/// .push(Self::FILES[i])
|
||||
/// .push(".bin");
|
||||
///
|
||||
/// i += 1;
|
||||
/// }
|
||||
///
|
||||
/// builder
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// module! {
|
||||
/// type: MyModule,
|
||||
/// name: "module_firmware_test",
|
||||
/// author: "Rust for Linux",
|
||||
/// description: "module_firmware! test module",
|
||||
/// license: "GPL",
|
||||
/// }
|
||||
///
|
||||
/// kernel::module_firmware!(Builder);
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! module_firmware {
|
||||
// The argument is the builder type without the const generic, since it's deferred from within
|
||||
// this macro. Hence, we can neither use `expr` nor `ty`.
|
||||
($($builder:tt)*) => {
|
||||
const _: () = {
|
||||
const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr = if cfg!(MODULE) {
|
||||
$crate::c_str!("")
|
||||
} else {
|
||||
<LocalModule as $crate::ModuleMetadata>::NAME
|
||||
};
|
||||
|
||||
#[link_section = ".modinfo"]
|
||||
#[used]
|
||||
static __MODULE_FIRMWARE: [u8; $($builder)*::create(__MODULE_FIRMWARE_PREFIX)
|
||||
.build_length()] = $($builder)*::create(__MODULE_FIRMWARE_PREFIX).build();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Builder for firmware module info.
|
||||
///
|
||||
/// [`ModInfoBuilder`] is a helper component to flexibly compose firmware paths strings for the
|
||||
|
|
@ -125,7 +214,7 @@ unsafe impl Sync for Firmware {}
|
|||
/// [`ModInfoBuilder::push`], where the latter is used to push path components and the former to
|
||||
/// mark the beginning of a new path string.
|
||||
///
|
||||
/// [`ModInfoBuilder`] is meant to be used in combination with `kernel::module_firmware!`.
|
||||
/// [`ModInfoBuilder`] is meant to be used in combination with [`kernel::module_firmware!`].
|
||||
///
|
||||
/// The const generic `N` as well as the `module_name` parameter of [`ModInfoBuilder::new`] is an
|
||||
/// internal implementation detail and supplied through the above macro.
|
||||
|
|
|
|||
Loading…
Reference in New Issue