diff options
Diffstat (limited to 'drivers/gpu/nova-core/regs/macros.rs')
| -rw-r--r-- | drivers/gpu/nova-core/regs/macros.rs | 287 |
1 files changed, 24 insertions, 263 deletions
diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs index 8058e1696df9..fd1a815fa57d 100644 --- a/drivers/gpu/nova-core/regs/macros.rs +++ b/drivers/gpu/nova-core/regs/macros.rs @@ -8,7 +8,8 @@ //! //! The `register!` macro in this module provides an intuitive and readable syntax for defining a //! dedicated type for each register. Each such type comes with its own field accessors that can -//! return an error if a field's value is invalid. +//! return an error if a field's value is invalid. Please look at the [`bitfield`] macro for the +//! complete syntax of fields definitions. /// Trait providing a base address to be added to the offset of a relative register to obtain /// its actual offset. @@ -51,18 +52,9 @@ pub(crate) trait RegisterBase<T> { /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); /// /// // Or, just read and update the register in a single step: -/// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); +/// BOOT_0::update(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); /// ``` /// -/// Fields are defined as follows: -/// -/// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or -/// `bool`. Note that `bool` fields must have a range of 1 bit. -/// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns -/// the result. -/// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation -/// and returns the result. This is useful with fields for which not all values are valid. -/// /// The documentation strings are optional. If present, they will be added to the type's /// definition, or the field getter and setter methods they are attached to. /// @@ -144,15 +136,15 @@ pub(crate) trait RegisterBase<T> { /// 0:0 start as bool, "Start the CPU core"; /// }); /// -/// // The `read`, `write` and `alter` methods of relative registers take an extra `base` argument +/// // The `read`, `write` and `update` methods of relative registers take an extra `base` argument /// // that is used to resolve its final address by adding its `BASE` to the offset of the /// // register. /// /// // Start `CPU0`. -/// CPU_CTL::alter(bar, &CPU0, |r| r.set_start(true)); +/// CPU_CTL::update(bar, &CPU0, |r| r.set_start(true)); /// /// // Start `CPU1`. -/// CPU_CTL::alter(bar, &CPU1, |r| r.set_start(true)); +/// CPU_CTL::update(bar, &CPU1, |r| r.set_start(true)); /// /// // Aliases can also be defined for relative register. /// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { @@ -160,7 +152,7 @@ pub(crate) trait RegisterBase<T> { /// }); /// /// // Start the aliased `CPU0`. -/// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true)); +/// CPU_CTL_ALIAS::update(bar, &CPU0, |r| r.set_alias_start(true)); /// ``` /// /// ## Arrays of registers @@ -168,7 +160,7 @@ pub(crate) trait RegisterBase<T> { /// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas /// can be defined as an array of identical registers, allowing them to be accessed by index with /// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add -/// an `idx` parameter to their `read`, `write` and `alter` methods: +/// an `idx` parameter to their `read`, `write` and `update` methods: /// /// ```no_run /// # fn no_run() -> Result<(), Error> { @@ -284,25 +276,25 @@ pub(crate) trait RegisterBase<T> { macro_rules! register { // Creates a register at a fixed offset of the MMIO space. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $offset); }; // Creates an alias register of fixed offset register `alias` with its own fields. ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET); }; // Creates a register at a relative offset from a base address provider. ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $offset ]); }; // Creates an alias register of relative offset register `alias` with its own fields. ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET ]); }; @@ -313,7 +305,7 @@ macro_rules! register { } ) => { static_assert!(::core::mem::size_of::<u32>() <= $stride); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_array $name @ $offset [ $size ; $stride ]); }; @@ -334,7 +326,7 @@ macro_rules! register { $(, $comment:literal)? { $($fields:tt)* } ) => { static_assert!(::core::mem::size_of::<u32>() <= $stride); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); }; @@ -356,7 +348,7 @@ macro_rules! register { } ) => { static_assert!($idx < $alias::SIZE); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); }; @@ -365,241 +357,10 @@ macro_rules! register { // to avoid it being interpreted in place of the relative register array alias rule. ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { static_assert!($idx < $alias::SIZE); - register!(@core $name $(, $comment)? { $($fields)* } ); + bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); }; - // All rules below are helpers. - - // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, - // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. - (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { - $( - #[doc=$comment] - )? - #[repr(transparent)] - #[derive(Clone, Copy)] - pub(crate) struct $name(u32); - - impl ::core::ops::BitOr for $name { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) - } - } - - impl ::core::convert::From<$name> for u32 { - fn from(reg: $name) -> u32 { - reg.0 - } - } - - register!(@fields_dispatcher $name { $($fields)* }); - }; - - // Captures the fields and passes them to all the implementers that require field information. - // - // Used to simplify the matching rules for implementers, so they don't need to match the entire - // complex fields rule even though they only make use of part of it. - (@fields_dispatcher $name:ident { - $($hi:tt:$lo:tt $field:ident as $type:tt - $(?=> $try_into_type:ty)? - $(=> $into_type:ty)? - $(, $comment:literal)? - ; - )* - } - ) => { - register!(@field_accessors $name { - $( - $hi:$lo $field as $type - $(?=> $try_into_type)? - $(=> $into_type)? - $(, $comment)? - ; - )* - }); - register!(@debug $name { $($field;)* }); - register!(@default $name { $($field;)* }); - }; - - // Defines all the field getter/methods methods for `$name`. - ( - @field_accessors $name:ident { - $($hi:tt:$lo:tt $field:ident as $type:tt - $(?=> $try_into_type:ty)? - $(=> $into_type:ty)? - $(, $comment:literal)? - ; - )* - } - ) => { - $( - register!(@check_field_bounds $hi:$lo $field as $type); - )* - - #[allow(dead_code)] - impl $name { - $( - register!(@field_accessor $name $hi:$lo $field as $type - $(?=> $try_into_type)? - $(=> $into_type)? - $(, $comment)? - ; - ); - )* - } - }; - - // Boolean fields must have `$hi == $lo`. - (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { - #[allow(clippy::eq_op)] - const _: () = { - ::kernel::build_assert!( - $hi == $lo, - concat!("boolean field `", stringify!($field), "` covers more than one bit") - ); - }; - }; - - // Non-boolean fields must have `$hi >= $lo`. - (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { - #[allow(clippy::eq_op)] - const _: () = { - ::kernel::build_assert!( - $hi >= $lo, - concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") - ); - }; - }; - - // Catches fields defined as `bool` and convert them into a boolean value. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty - $(, $comment:literal)?; - ) => { - register!( - @leaf_accessor $name $hi:$lo $field - { |f| <$into_type>::from(if f != 0 { true } else { false }) } - $into_type => $into_type $(, $comment)?; - ); - }; - - // Shortcut for fields defined as `bool` without the `=>` syntax. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; - ) => { - register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); - }; - - // Catches the `?=>` syntax for non-boolean fields. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty - $(, $comment:literal)?; - ) => { - register!(@leaf_accessor $name $hi:$lo $field - { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => - ::core::result::Result< - $try_into_type, - <$try_into_type as ::core::convert::TryFrom<$type>>::Error - > - $(, $comment)?;); - }; - - // Catches the `=>` syntax for non-boolean fields. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty - $(, $comment:literal)?; - ) => { - register!(@leaf_accessor $name $hi:$lo $field - { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); - }; - - // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. - ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt - $(, $comment:literal)?; - ) => { - register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); - }; - - // Generates the accessor methods for a single field. - ( - @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident - { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; - ) => { - ::kernel::macros::paste!( - const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; - const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); - const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); - ); - - $( - #[doc="Returns the value of this field:"] - #[doc=$comment] - )? - #[inline(always)] - pub(crate) fn $field(self) -> $res_type { - ::kernel::macros::paste!( - const MASK: u32 = $name::[<$field:upper _MASK>]; - const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; - ); - let field = ((self.0 & MASK) >> SHIFT); - - $process(field) - } - - ::kernel::macros::paste!( - $( - #[doc="Sets the value of this field:"] - #[doc=$comment] - )? - #[inline(always)] - pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { - const MASK: u32 = $name::[<$field:upper _MASK>]; - const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; - let value = (u32::from(value) << SHIFT) & MASK; - self.0 = (self.0 & !MASK) | value; - - self - } - ); - }; - - // Generates the `Debug` implementation for `$name`. - (@debug $name:ident { $($field:ident;)* }) => { - impl ::kernel::fmt::Debug for $name { - fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { - f.debug_struct(stringify!($name)) - .field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0)) - $( - .field(stringify!($field), &self.$field()) - )* - .finish() - } - } - }; - - // Generates the `Default` implementation for `$name`. - (@default $name:ident { $($field:ident;)* }) => { - /// Returns a value for the register where all fields are set to their default value. - impl ::core::default::Default for $name { - fn default() -> Self { - #[allow(unused_mut)] - let mut value = Self(Default::default()); - - ::kernel::macros::paste!( - $( - value.[<set_ $field>](Default::default()); - )* - ); - - value - } - } - }; - // Generates the IO accessors for a fixed offset register. (@io_fixed $name:ident @ $offset:expr) => { #[allow(dead_code)] @@ -625,7 +386,7 @@ macro_rules! register { /// Read the register from its address in `io` and run `f` on its value to obtain a new /// value to write back. #[inline(always)] - pub(crate) fn alter<const SIZE: usize, T, F>( + pub(crate) fn update<const SIZE: usize, T, F>( io: &T, f: F, ) where @@ -688,7 +449,7 @@ macro_rules! register { /// the register's offset to it, then run `f` on its value to obtain a new value to /// write back. #[inline(always)] - pub(crate) fn alter<const SIZE: usize, T, B, F>( + pub(crate) fn update<const SIZE: usize, T, B, F>( io: &T, base: &B, f: F, @@ -746,7 +507,7 @@ macro_rules! register { /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a /// new value to write back. #[inline(always)] - pub(crate) fn alter<const SIZE: usize, T, F>( + pub(crate) fn update<const SIZE: usize, T, F>( io: &T, idx: usize, f: F, @@ -801,7 +562,7 @@ macro_rules! register { /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the /// access was out-of-bounds. #[inline(always)] - pub(crate) fn try_alter<const SIZE: usize, T, F>( + pub(crate) fn try_update<const SIZE: usize, T, F>( io: &T, idx: usize, f: F, @@ -810,7 +571,7 @@ macro_rules! register { F: ::core::ops::FnOnce(Self) -> Self, { if idx < Self::SIZE { - Ok(Self::alter(io, idx, f)) + Ok(Self::update(io, idx, f)) } else { Err(EINVAL) } @@ -875,7 +636,7 @@ macro_rules! register { /// by `base` and adding the register's offset to it, then run `f` on its value to /// obtain a new value to write back. #[inline(always)] - pub(crate) fn alter<const SIZE: usize, T, B, F>( + pub(crate) fn update<const SIZE: usize, T, B, F>( io: &T, base: &B, idx: usize, @@ -939,7 +700,7 @@ macro_rules! register { /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the /// access was out-of-bounds. #[inline(always)] - pub(crate) fn try_alter<const SIZE: usize, T, B, F>( + pub(crate) fn try_update<const SIZE: usize, T, B, F>( io: &T, base: &B, idx: usize, @@ -950,7 +711,7 @@ macro_rules! register { F: ::core::ops::FnOnce(Self) -> Self, { if idx < Self::SIZE { - Ok(Self::alter(io, base, idx, f)) + Ok(Self::update(io, base, idx, f)) } else { Err(EINVAL) } |
