[PATCH v2 10/16] rust: io: register: make register have a typed base
Gary Guo <[email protected]> Wed, 05 Aug 2026 17:35:53 +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]> |
Previously `register!` defined registers can be used on any untyped I/O regions. With all users specifying their desired register type now, propagate the specified type and restrict I/O access only when type matches. Also, add an `io_project!` example which is enabled by this change. Signed-off-by: Gary Guo <[email protected]> --- rust/kernel/io.rs | 13 ++++++++++ rust/kernel/io/register.rs | 64 +++++++++++++++++++--------------------------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index d92e0b6adc99..d56c8faa7d7c 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -1798,21 +1798,34 @@ pub fn project_loc<U, L>(self, location: L) -> <T::Backend as IoBackend>::View<' /// The syntax is of form `io_project!(io, proj)` where `io` is an expression to a type that /// implements [`Io`] and `proj` is a [projection specification](kernel::ptr::project!). /// +/// `io_project!` can also project to subview of registers defined with [`register!`] macro. +/// Register projection has syntax `io_project!(io, try: REGISTER)` for fallible projection and +/// `io_project!(io, build: REGISTER)` for infallible projection. +/// /// # Examples /// /// ``` /// use kernel::io::{ /// io_project, +/// register, /// Mmio, /// }; /// #[repr(C)] /// struct MyStruct { field: u32, } /// +/// register! { +/// base: MyStruct; +/// FIELD(u32) @ 0 { +/// 31:0 val; +/// } +/// } +/// /// # fn test(mmio: Mmio<'_, [MyStruct]>) -> Result { /// // let mmio: Mmio<[MyStruct]>; /// let field: Mmio<'_, u32> = io_project!(mmio, [try: 1].field); /// let whole: Mmio<'_, MyStruct> = io_project!(mmio, [try: 2]); /// let nested: Mmio<'_, u32> = io_project!(whole, .field); +/// let reg: Mmio<'_, FIELD> = io_project!(whole, build: FIELD); /// # Ok::<(), Error>(()) } /// ``` #[macro_export] diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 7dca2437b551..dc800fc71172 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -121,10 +121,11 @@ io::IoLoc, // }; -use super::Region; - /// Trait implemented by all registers. pub trait Register: Sized { + /// Base type for this register. + type Base: ?Sized; + /// Start offset of the register. /// /// The interpretation of this offset depends on the type of the register. @@ -136,9 +137,9 @@ pub trait FixedRegister: Register {} /// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when /// passing a [`FixedRegister`] value. -impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for () +impl<Base: ?Sized, T> IoLoc<Base, T> for () where - T: FixedRegister, + T: FixedRegister<Base = Base>, { #[inline(always)] fn offset(self) -> usize { @@ -148,9 +149,9 @@ fn offset(self) -> usize { /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used /// as an [`IoLoc`]. -impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for T +impl<Base: ?Sized, T> IoLoc<Base, T> for T where - T: FixedRegister, + T: FixedRegister<Base = Base>, { #[inline(always)] fn offset(self) -> usize { @@ -171,9 +172,9 @@ pub const fn new() -> Self { } } -impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for FixedRegisterLoc<T> +impl<Base: ?Sized, T> IoLoc<Base, T> for FixedRegisterLoc<T> where - T: FixedRegister, + T: FixedRegister<Base = Base>, { #[inline(always)] fn offset(self) -> usize { @@ -240,9 +241,9 @@ const fn offset(self) -> usize { } } -impl<const SIZE: usize, T, B> IoLoc<Region<SIZE>, T> for RelativeRegisterLoc<T, B> +impl<SuperBase: ?Sized, T, B> IoLoc<SuperBase, T> for RelativeRegisterLoc<T, B> where - T: RelativeRegister, + T: RelativeRegister<Base = SuperBase>, B: RegisterBase<T::BaseFamily> + ?Sized, { #[inline(always)] @@ -282,9 +283,9 @@ pub fn try_new(idx: usize) -> Option<Self> { } } -impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for RegisterArrayLoc<T> +impl<Base: ?Sized, T> IoLoc<Base, T> for RegisterArrayLoc<T> where - T: RegisterArray, + T: RegisterArray<Base = Base>, { #[inline(always)] fn offset(self) -> usize { @@ -367,9 +368,9 @@ pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> { } } -impl<const SIZE: usize, T, B> IoLoc<Region<SIZE>, T> for RelativeRegisterArrayLoc<T, B> +impl<SuperBase: ?Sized, T, B> IoLoc<SuperBase, T> for RelativeRegisterArrayLoc<T, B> where - T: RelativeRegisterArray, + T: RelativeRegisterArray<Base = SuperBase>, B: RegisterBase<T::BaseFamily> + ?Sized, { #[inline(always)] @@ -393,9 +394,9 @@ pub trait LocatedRegister<Base: ?Sized> { fn into_io_op(self) -> (Self::Location, Self::Value); } -impl<const SIZE: usize, T> LocatedRegister<Region<SIZE>> for T +impl<Base: ?Sized, T> LocatedRegister<Base> for T where - T: FixedRegister, + T: FixedRegister<Base = Base>, { type Location = FixedRegisterLoc<Self::Value>; type Value = T; @@ -823,12 +824,7 @@ fn into_io_op(self) -> (FixedRegisterLoc<T>, T) { /// ``` #[macro_export] macro_rules! register { - (base: $reg_base:ty;) => { - const _: () = { - #[allow(unused)] - type Base = $reg_base; - }; - }; + (base: $reg_base:ty;) => {}; // Creates a register at a fixed offset of the MMIO space. // @@ -843,7 +839,7 @@ macro_rules! register { $($rest:tt)* ) => { $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name + $crate::register!(@io_base $reg_base; $name @ $crate::register!(@offset $(@ $offset)? $(=> $alias $([$alias_idx])?)?) ); $crate::register!(@io_fixed $(#[$attr])* $vis $name); @@ -858,7 +854,7 @@ macro_rules! register { $($rest:tt)* ) => { $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name @ $offset); + $crate::register!(@io_base $reg_base; $name @ $offset); $crate::register!(@io_relative $vis $name @ $base); $crate::register!(base: $reg_base; $($rest)*); }; @@ -871,7 +867,7 @@ macro_rules! register { $($rest:tt)* ) => { $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name @ $crate::register!(@offset => $alias)); + $crate::register!(@io_base $reg_base; $name @ $crate::register!(@offset => $alias)); $crate::register!(@io_relative $vis $name @ $base); $crate::register!(base: $reg_base; $($rest)*); }; @@ -884,7 +880,7 @@ macro_rules! register { $($rest:tt)* ) => { $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name @ $offset); + $crate::register!(@io_base $reg_base; $name @ $offset); $crate::register!(@io_array $vis $name [ $size, stride = $crate::register!(@stride $storage $(, $stride)?) ] ); @@ -900,7 +896,7 @@ macro_rules! register { $($rest:tt)* ) => { $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name @ $offset); + $crate::register!(@io_base $reg_base; $name @ $offset); $crate::register!(@io_relative_array $vis $name [ $size, stride = $crate::register!(@stride $storage $(, $stride)?) ] @ $base + $offset ); @@ -920,7 +916,7 @@ macro_rules! register { ); $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); - $crate::register!(@io_base $name @ $crate::register!(@offset => $alias [$idx])); + $crate::register!(@io_base $reg_base; $name @ $crate::register!(@offset => $alias [$idx])); $crate::register!(@io_relative $vis $name @ $base); $crate::register!(base: $reg_base; $($rest)*); }; @@ -960,8 +956,10 @@ macro_rules! register { (@stride $ty: ty) => { ::core::mem::size_of::<$ty>() }; // Implementations shared by all registers types. - (@io_base $name:ident @ $offset:expr) => { + (@io_base $reg_base:ty; $name:ident @ $offset:expr) => { impl $crate::io::register::Register for $name { + type Base = $reg_base; + const OFFSET: usize = $offset; } }; @@ -1010,12 +1008,4 @@ impl $crate::io::register::RegisterArray for $name { impl $crate::io::register::RelativeRegisterArray for $name {} }; - - // Compatibility rule when base is not specified. - ($($rest:tt)*) => { - $crate::register!( - base: $crate::io::Region; - $($rest)* - ); - } } -- 2.54.0