[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