diff options
Diffstat (limited to 'drivers/gpu/nova-core/bitfield.rs')
| -rw-r--r-- | drivers/gpu/nova-core/bitfield.rs | 70 |
1 files changed, 41 insertions, 29 deletions
diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs index fb60800898c5..eff938937df4 100644 --- a/drivers/gpu/nova-core/bitfield.rs +++ b/drivers/gpu/nova-core/bitfield.rs @@ -60,7 +60,7 @@ /// } /// /// bitfield! { -/// struct ControlReg { +/// struct ControlReg(u32) { /// 7:7 state as bool => State; /// 3:0 mode as u8 ?=> Mode; /// } @@ -70,6 +70,8 @@ /// This generates a struct with: /// - Field accessors: `mode()`, `state()`, etc. /// - Field setters: `set_mode()`, `set_state()`, etc. (supports chaining with builder pattern). +/// Note that the compiler will error out if the size of the setter's arg exceeds the +/// struct's storage size. /// - Debug and Default implementations. /// /// Fields are defined as follows: @@ -82,21 +84,21 @@ /// and returns the result. This is useful with fields for which not all values are valid. macro_rules! bitfield { // Main entry point - defines the bitfield struct with fields - (struct $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { - bitfield!(@core $name $(, $comment)? { $($fields)* }); + (struct $name:ident($storage:ty) $(, $comment:literal)? { $($fields:tt)* }) => { + bitfield!(@core $name $storage $(, $comment)? { $($fields)* }); }; // 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)* }) => { + (@core $name:ident $storage:ty $(, $comment:literal)? { $($fields:tt)* }) => { $( #[doc=$comment] )? #[repr(transparent)] #[derive(Clone, Copy)] - pub(crate) struct $name(u32); + pub(crate) struct $name($storage); impl ::core::ops::BitOr for $name { type Output = Self; @@ -106,20 +108,20 @@ macro_rules! bitfield { } } - impl ::core::convert::From<$name> for u32 { - fn from(val: $name) -> u32 { + impl ::core::convert::From<$name> for $storage { + fn from(val: $name) -> $storage { val.0 } } - bitfield!(@fields_dispatcher $name { $($fields)* }); + bitfield!(@fields_dispatcher $name $storage { $($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 { + (@fields_dispatcher $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=> $try_into_type:ty)? $(=> $into_type:ty)? @@ -128,7 +130,7 @@ macro_rules! bitfield { )* } ) => { - bitfield!(@field_accessors $name { + bitfield!(@field_accessors $name $storage { $( $hi:$lo $field as $type $(?=> $try_into_type)? @@ -143,7 +145,7 @@ macro_rules! bitfield { // Defines all the field getter/setter methods for `$name`. ( - @field_accessors $name:ident { + @field_accessors $name:ident $storage:ty { $($hi:tt:$lo:tt $field:ident as $type:tt $(?=> $try_into_type:ty)? $(=> $into_type:ty)? @@ -159,7 +161,7 @@ macro_rules! bitfield { #[allow(dead_code)] impl $name { $( - bitfield!(@field_accessor $name $hi:$lo $field as $type + bitfield!(@field_accessor $name $storage, $hi:$lo $field as $type $(?=> $try_into_type)? $(=> $into_type)? $(, $comment)? @@ -193,11 +195,11 @@ macro_rules! bitfield { // 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 + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool => $into_type:ty $(, $comment:literal)?; ) => { bitfield!( - @leaf_accessor $name $hi:$lo $field + @leaf_accessor $name $storage, $hi:$lo $field { |f| <$into_type>::from(if f != 0 { true } else { false }) } bool $into_type => $into_type $(, $comment)?; ); @@ -205,17 +207,18 @@ macro_rules! bitfield { // Shortcut for fields defined as `bool` without the `=>` syntax. ( - @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool + $(, $comment:literal)?; ) => { - bitfield!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); + bitfield!(@field_accessor $name $storage, $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)?; + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt + ?=> $try_into_type:ty $(, $comment:literal)?; ) => { - bitfield!(@leaf_accessor $name $hi:$lo $field + bitfield!(@leaf_accessor $name $storage, $hi:$lo $field { |f| <$try_into_type>::try_from(f as $type) } $type $try_into_type => ::core::result::Result< $try_into_type, @@ -226,29 +229,38 @@ macro_rules! bitfield { // 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)?; + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt + => $into_type:ty $(, $comment:literal)?; ) => { - bitfield!(@leaf_accessor $name $hi:$lo $field + bitfield!(@leaf_accessor $name $storage, $hi:$lo $field { |f| <$into_type>::from(f as $type) } $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 + @field_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt $(, $comment:literal)?; ) => { - bitfield!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); + bitfield!(@field_accessor $name $storage, $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 + @leaf_accessor $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident { $process:expr } $prim_type:tt $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 _MASK>]: $storage = { + // Generate mask for shifting + match ::core::mem::size_of::<$storage>() { + 1 => ::kernel::bits::genmask_u8($lo..=$hi) as $storage, + 2 => ::kernel::bits::genmask_u16($lo..=$hi) as $storage, + 4 => ::kernel::bits::genmask_u32($lo..=$hi) as $storage, + 8 => ::kernel::bits::genmask_u64($lo..=$hi) as $storage, + _ => ::kernel::build_error!("Unsupported storage type size") + } + }; const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); ); @@ -259,7 +271,7 @@ macro_rules! bitfield { #[inline(always)] pub(crate) fn $field(self) -> $res_type { ::kernel::macros::paste!( - const MASK: u32 = $name::[<$field:upper _MASK>]; + const MASK: $storage = $name::[<$field:upper _MASK>]; const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; ); let field = ((self.0 & MASK) >> SHIFT); @@ -274,9 +286,9 @@ macro_rules! bitfield { )? #[inline(always)] pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { - const MASK: u32 = $name::[<$field:upper _MASK>]; + const MASK: $storage = $name::[<$field:upper _MASK>]; const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; - let value = (u32::from($prim_type::from(value)) << SHIFT) & MASK; + let value = ($storage::from($prim_type::from(value)) << SHIFT) & MASK; self.0 = (self.0 & !MASK) | value; self |