[PATCH v3 11/16] rust: io: register: support fixed offset register without bitfield

Gary Guo <[email protected]>
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 `register!()` 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 | 30 ++++++++++++++++
 rust/macros/io/register.rs | 86 +++++++++++++++++++++++++++++++---------------
 2 files changed, 89 insertions(+), 27 deletions(-)

diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs
index f622057f7346..63c054162e54 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.
 ///
@@ -521,6 +538,19 @@ pub const fn element_alias_offset<Base: ?Sized, Alias: RegisterArray<Base = Base
 /// 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>;
+///
+///     /// UART RX register.
+///     pub UART_RX: u8 @ 0x100;
+/// }
+/// ```
+///
 /// ## Relative registers
 ///
 /// Relative registers can be instantiated several times at a relative offset of a group of bases.
diff --git a/rust/macros/io/register.rs b/rust/macros/io/register.rs
index cb02e850b23f..0b4e0d1903dd 100644
--- a/rust/macros/io/register.rs
+++ b/rust/macros/io/register.rs
@@ -14,9 +14,11 @@
     bracketed,
     parenthesized,
     parse::Parse,
+    parse_quote,
     spanned::Spanned,
     token,
     Attribute,
+    Error,
     Expr,
     Ident,
     Path,
@@ -49,11 +51,11 @@ struct Reg {
     attrs: Vec<Attribute>,
     vis: Visibility,
     name: Ident,
-    storage: Type,
+    ty: Type,
     array: Option<RegArrayDef>,
     relative_base: Option<Path>,
     offset: RegOffset,
-    bitfield_args: Group,
+    bitfield: Option<(Type, Group)>,
 }
 
 impl Parse for Reg {
@@ -61,11 +63,23 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
         let attrs = input.call(Attribute::parse_outer)?;
         let vis = input.parse()?;
         let name = input.parse()?;
-        let storage = {
+
+        let lh = input.lookahead1();
+        let mut bitfield_storage = None;
+        let ty = if lh.peek(Token![:]) {
+            let _: Token![:] = input.parse()?;
+            input.parse()?
+        } else if lh.peek(token::Paren) {
             let content;
             parenthesized!(content in input);
-            content.parse()?
+            bitfield_storage = Some(content.parse()?);
+
+            // For bitfields, bitfield macro will generate a type with the same name as `name`.
+            parse_quote!(#name)
+        } else {
+            Err(lh.error())?
         };
+
         let array = if input.peek(token::Bracket) {
             let content;
             bracketed!(content in input);
@@ -119,22 +133,28 @@ fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
             Err(lh.error())?
         };
 
-        let lh = input.lookahead1();
-        let bitfield_args = if lh.peek(token::Brace) {
-            input.parse()?
+        let bitfield = if let Some(storage) = bitfield_storage {
+            let lh = input.lookahead1();
+            let args = if lh.peek(token::Brace) {
+                input.parse()?
+            } else {
+                Err(lh.error())?
+            };
+            Some((storage, args))
         } else {
-            Err(lh.error())?
+            let _: Token![;] = input.parse()?;
+            None
         };
 
         Ok(Self {
             attrs,
             vis,
             name,
-            storage,
+            ty,
             array,
             relative_base,
             offset,
-            bitfield_args,
+            bitfield,
         })
     }
 }
@@ -174,11 +194,11 @@ pub(crate) fn register(def: RegDef) -> Result<TokenStream> {
             attrs,
             vis,
             name,
-            storage,
+            ty,
             array,
             relative_base,
             offset,
-            bitfield_args,
+            bitfield,
         } = reg;
 
         // Use register name's span for generated code, so error messages (if any) can point to it
@@ -199,21 +219,33 @@ pub(crate) fn register(def: RegDef) -> Result<TokenStream> {
             }
         };
 
-        outputs.extend(quote_spanned!(span =>
-            ::kernel::bitfield!(
-                // `#[allow(non_camel_case_types)]` is added since register names typically use
-                // `SCREAMING_CASE`.
-                #[allow(non_camel_case_types)]
-                #(#attrs)* #vis struct #name(#storage) #bitfield_args
-            );
-
-            impl ::kernel::io::register::Register for #name {
-                type Base = #base;
-                const OFFSET: usize = #offset;
-            }
-        ));
+        if let Some((storage, args)) = &bitfield {
+            outputs.extend(quote_spanned!(span =>
+                ::kernel::bitfield!(
+                    // `#[allow(non_camel_case_types)]` is added since register names typically use
+                    // `SCREAMING_CASE`.
+                    #[allow(non_camel_case_types)]
+                    #(#attrs)* #vis struct #name(#storage) #args
+                );
+
+                impl ::kernel::io::register::Register for #name {
+                    type Base = #base;
+                    const OFFSET: usize = #offset;
+                }
+            ));
+        }
 
         match array {
+            None if bitfield.is_none() && relative_base.is_none() => outputs.extend(quote!(
+                #(#attrs)* #vis const #name: ::kernel::io::register::OffsetLoc<#base, #ty> =
+                    ::kernel::io::register::OffsetLoc::new(#offset);
+            )),
+
+            _ if bitfield.is_none() => Err(Error::new_spanned(
+                ty,
+                "defining without bitfield is not yet supported for this type of register",
+            ))?,
+
             None => match relative_base {
                 None => outputs.extend(quote_spanned!(span =>
                     impl ::kernel::io::register::FixedRegister for #name {}
@@ -235,12 +267,12 @@ impl ::kernel::io::register::RelativeRegister for #name {}
                 let stride = if let Some(stride) = &def.stride {
                     outputs.extend(quote_spanned!(stride.span().resolved_at(span) =>
                         ::kernel::build_assert::static_assert!(
-                            ::core::mem::size_of::<#storage>() <= #stride
+                            ::core::mem::size_of::<#ty>() <= #stride
                         );
                     ));
                     quote!(#stride)
                 } else {
-                    quote_spanned!(span => ::core::mem::size_of::<#storage>())
+                    quote_spanned!(span => ::core::mem::size_of::<#ty>())
                 };
 
                 outputs.extend(quote_spanned!(span =>

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.