[PATCH v2 11/16] rust: io: register: support fixed offset register without bitfield
Gary Guo <[email protected]> Wed, 05 Aug 2026 17:35:54 +0100
| Newsgroups | org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
Add a rule to allow creating `IoLoc` in `regiser!()` using an existing type and not create a bitfield. Add an example to demonstrate this for FIFO registers. This rule is also going to be used to create subregions for registers; the example of doing so will be added later when relative registers are removed. Signed-off-by: Gary Guo <[email protected]> --- rust/kernel/io/register.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index dc800fc71172..49a61da106c7 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -182,6 +182,23 @@ fn offset(self) -> usize { } } +#[doc(hidden)] +pub struct OffsetLoc<Base: ?Sized, T>(usize, PhantomData<(T, Base)>); + +impl<Base: ?Sized, T> OffsetLoc<Base, T> { + #[inline] + pub const fn new(offset: usize) -> Self { + Self(offset, PhantomData) + } +} + +impl<Base: ?Sized, T> IoLoc<Base, T> for OffsetLoc<Base, T> { + #[inline(always)] + fn offset(self) -> usize { + self.0 + } +} + /// Trait providing a base address to be added to the offset of a relative register to obtain /// its actual offset. /// @@ -499,6 +516,19 @@ fn into_io_op(self) -> (FixedRegisterLoc<T>, T) { /// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing /// its own `completed` field. /// +/// If you do not wish to have a bitfield defined, you can also create a register using an existing +/// type. +/// +/// ```no_run +/// # use kernel::io::*; +/// register! { +/// base: Region<0x1000>; +/// +/// /// TX FIFO register. +/// pub TX_FIFO: u32 @ 0x00001000; +/// } +/// ``` +/// /// ## Relative registers /// /// Relative registers can be instantiated several times at a relative offset of a group of bases. @@ -826,6 +856,23 @@ fn into_io_op(self) -> (FixedRegisterLoc<T>, T) { macro_rules! register { (base: $reg_base:ty;) => {}; + // Creates a register at a fixed offset of the MMIO space with provided type. + ( + base: $reg_base:ty; + // `$ty` cannot be `:ty` due to follow-set restrictions. + $(#[$attr:meta])* $vis:vis $name:ident: $ty: ident $(:: $path_frag:ident)* + $(@ $offset:literal)? + $(=> $alias:path $([$alias_idx:expr])? )?; + $($rest:tt)* + ) => { + $(#[$attr])* $vis + const $name: $crate::io::register::OffsetLoc<$reg_base, $ty $(:: $path_frag)*> = + $crate::io::register::OffsetLoc::new( + $crate::register!(@offset $(@ $offset)? $(=> $alias $([$alias_idx])?)?) + ); + $crate::register!(base: $reg_base; $($rest)*); + }; + // Creates a register at a fixed offset of the MMIO space. // // This handles all of the fixed offset `@ offset`, alias of register `=> alias` and alias of -- 2.54.0