File Index
Files and directories
Sign in
FILE

bitfield.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/nova-core/bitfield.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! Bitfield library for Rust structures
  4//!
  5//! Support for defining bitfields in Rust structures. Also used by the [`register!`] macro.
  6
  7/// Defines a struct with accessors to access bits within an inner unsigned integer.
  8///
  9/// # Syntax
 10///
 11/// ```rust
 12/// use nova_core::bitfield;
 13///
 14/// #[derive(Debug, Clone, Copy, Default)]
 15/// enum Mode {
 16///     #[default]
 17///     Low = 0,
 18///     High = 1,
 19///     Auto = 2,
 20/// }
 21///
 22/// impl TryFrom<u8> for Mode {
 23///     type Error = u8;
 24///     fn try_from(value: u8) -> Result<Self, Self::Error> {
 25///         match value {
 26///             0 => Ok(Mode::Low),
 27///             1 => Ok(Mode::High),
 28///             2 => Ok(Mode::Auto),
 29///             _ => Err(value),
 30///         }
 31///     }
 32/// }
 33///
 34/// impl From<Mode> for u8 {
 35///     fn from(mode: Mode) -> u8 {
 36///         mode as u8
 37///     }
 38/// }
 39///
 40/// #[derive(Debug, Clone, Copy, Default)]
 41/// enum State {
 42///     #[default]
 43///     Inactive = 0,
 44///     Active = 1,
 45/// }
 46///
 47/// impl From<bool> for State {
 48///     fn from(value: bool) -> Self {
 49///         if value { State::Active } else { State::Inactive }
 50///     }
 51/// }
 52///
 53/// impl From<State> for bool {
 54///     fn from(state: State) -> bool {
 55///         match state {
 56///             State::Inactive => false,
 57///             State::Active => true,
 58///         }
 59///     }
 60/// }
 61///
 62/// bitfield! {
 63///     pub struct ControlReg(u32) {
 64///         7:7 state as bool => State;
 65///         3:0 mode as u8 ?=> Mode;
 66///     }
 67/// }
 68/// ```
 69///
 70/// This generates a struct with:
 71/// - Field accessors: `mode()`, `state()`, etc.
 72/// - Field setters: `set_mode()`, `set_state()`, etc. (supports chaining with builder pattern).
 73///   Note that the compiler will error out if the size of the setter's arg exceeds the
 74///   struct's storage size.
 75/// - Debug and Default implementations.
 76///
 77/// Note: Field accessors and setters inherit the same visibility as the struct itself.
 78/// In the example above, both `mode()` and `set_mode()` methods will be `pub`.
 79///
 80/// Fields are defined as follows:
 81///
 82/// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or
 83///   `bool`. Note that `bool` fields must have a range of 1 bit.
 84/// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns
 85///   the result.
 86/// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation
 87///   and returns the result. This is useful with fields for which not all values are valid.
 88macro_rules! bitfield {
 89    // Main entry point - defines the bitfield struct with fields
 90    ($vis:vis struct $name:ident($storage:ty) $(, $comment:literal)? { $($fields:tt)* }) => {
 91        bitfield!(@core $vis $name $storage $(, $comment)? { $($fields)* });
 92    };
 93
 94    // All rules below are helpers.
 95
 96    // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`,
 97    // `Default`, and conversion to the value type) and field accessor methods.
 98    (@core $vis:vis $name:ident $storage:ty $(, $comment:literal)? { $($fields:tt)* }) => {
 99        $(
100        #[doc=$comment]
101        )?
102        #[repr(transparent)]
103        #[derive(Clone, Copy)]
104        $vis struct $name($storage);
105
106        impl ::core::convert::From<$name> for $storage {
107            fn from(val: $name) -> $storage {
108                val.0
109            }
110        }
111
112        bitfield!(@fields_dispatcher $vis $name $storage { $($fields)* });
113    };
114
115    // Captures the fields and passes them to all the implementers that require field information.
116    //
117    // Used to simplify the matching rules for implementers, so they don't need to match the entire
118    // complex fields rule even though they only make use of part of it.
119    (@fields_dispatcher $vis:vis $name:ident $storage:ty {
120        $($hi:tt:$lo:tt $field:ident as $type:tt
121            $(?=> $try_into_type:ty)?
122            $(=> $into_type:ty)?
123            $(, $comment:literal)?
124        ;
125        )*
126    }
127    ) => {
128        bitfield!(@field_accessors $vis $name $storage {
129            $(
130                $hi:$lo $field as $type
131                $(?=> $try_into_type)?
132                $(=> $into_type)?
133                $(, $comment)?
134            ;
135            )*
136        });
137        bitfield!(@debug $name { $($field;)* });
138        bitfield!(@default $name { $($field;)* });
139    };
140
141    // Defines all the field getter/setter methods for `$name`.
142    (
143        @field_accessors $vis:vis $name:ident $storage:ty {
144        $($hi:tt:$lo:tt $field:ident as $type:tt
145            $(?=> $try_into_type:ty)?
146            $(=> $into_type:ty)?
147            $(, $comment:literal)?
148        ;
149        )*
150        }
151    ) => {
152        $(
153            bitfield!(@check_field_bounds $hi:$lo $field as $type);
154        )*
155
156        #[allow(dead_code)]
157        impl $name {
158            $(
159            bitfield!(@field_accessor $vis $name $storage, $hi:$lo $field as $type
160                $(?=> $try_into_type)?
161                $(=> $into_type)?
162                $(, $comment)?
163                ;
164            );
165            )*
166        }
167    };
168
169    // Boolean fields must have `$hi == $lo`.
170    (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {
171        #[allow(clippy::eq_op)]
172        const _: () = {
173            ::kernel::build_assert!(
174                $hi == $lo,
175                concat!("boolean field `", stringify!($field), "` covers more than one bit")
176            );
177        };
178    };
179
180    // Non-boolean fields must have `$hi >= $lo`.
181    (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {
182        #[allow(clippy::eq_op)]
183        const _: () = {
184            ::kernel::build_assert!(
185                $hi >= $lo,
186                concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")
187            );
188        };
189    };
190
191    // Catches fields defined as `bool` and convert them into a boolean value.
192    (
193        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool
194            => $into_type:ty $(, $comment:literal)?;
195    ) => {
196        bitfield!(
197            @leaf_accessor $vis $name $storage, $hi:$lo $field
198            { |f| <$into_type>::from(f != 0) }
199            bool $into_type => $into_type $(, $comment)?;
200        );
201    };
202
203    // Shortcut for fields defined as `bool` without the `=>` syntax.
204    (
205        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool
206            $(, $comment:literal)?;
207    ) => {
208        bitfield!(
209            @field_accessor $vis $name $storage, $hi:$lo $field as bool => bool $(, $comment)?;
210        );
211    };
212
213    // Catches the `?=>` syntax for non-boolean fields.
214    (
215        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
216            ?=> $try_into_type:ty $(, $comment:literal)?;
217    ) => {
218        bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field
219            { |f| <$try_into_type>::try_from(f as $type) } $type $try_into_type =>
220            ::core::result::Result<
221                $try_into_type,
222                <$try_into_type as ::core::convert::TryFrom<$type>>::Error
223            >
224            $(, $comment)?;);
225    };
226
227    // Catches the `=>` syntax for non-boolean fields.
228    (
229        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
230            => $into_type:ty $(, $comment:literal)?;
231    ) => {
232        bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field
233            { |f| <$into_type>::from(f as $type) } $type $into_type => $into_type $(, $comment)?;);
234    };
235
236    // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax.
237    (
238        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
239            $(, $comment:literal)?;
240    ) => {
241        bitfield!(
242            @field_accessor $vis $name $storage, $hi:$lo $field as $type => $type $(, $comment)?;
243        );
244    };
245
246    // Generates the accessor methods for a single field.
247    (
248        @leaf_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident
249            { $process:expr } $prim_type:tt $to_type:ty => $res_type:ty $(, $comment:literal)?;
250    ) => {
251        ::kernel::macros::paste!(
252        const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
253        const [<$field:upper _MASK>]: $storage = {
254            // Generate mask for shifting
255            match ::core::mem::size_of::<$storage>() {
256                1 => ::kernel::bits::genmask_u8($lo..=$hi) as $storage,
257                2 => ::kernel::bits::genmask_u16($lo..=$hi) as $storage,
258                4 => ::kernel::bits::genmask_u32($lo..=$hi) as $storage,
259                8 => ::kernel::bits::genmask_u64($lo..=$hi) as $storage,
260                _ => ::kernel::build_error!("Unsupported storage type size")
261            }
262        };
263        const [<$field:upper _SHIFT>]: u32 = $lo;
264        );
265
266        $(
267        #[doc="Returns the value of this field:"]
268        #[doc=$comment]
269        )?
270        #[inline(always)]
271        $vis fn $field(self) -> $res_type {
272            ::kernel::macros::paste!(
273            const MASK: $storage = $name::[<$field:upper _MASK>];
274            const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
275            );
276            let field = ((self.0 & MASK) >> SHIFT);
277
278            $process(field)
279        }
280
281        ::kernel::macros::paste!(
282        $(
283        #[doc="Sets the value of this field:"]
284        #[doc=$comment]
285        )?
286        #[inline(always)]
287        $vis fn [<set_ $field>](mut self, value: $to_type) -> Self {
288            const MASK: $storage = $name::[<$field:upper _MASK>];
289            const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
290            let value = ($storage::from($prim_type::from(value)) << SHIFT) & MASK;
291            self.0 = (self.0 & !MASK) | value;
292
293            self
294        }
295        );
296    };
297
298    // Generates the `Debug` implementation for `$name`.
299    (@debug $name:ident { $($field:ident;)* }) => {
300        impl ::kernel::fmt::Debug for $name {
301            fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
302                f.debug_struct(stringify!($name))
303                    .field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0))
304                $(
305                    .field(stringify!($field), &self.$field())
306                )*
307                    .finish()
308            }
309        }
310    };
311
312    // Generates the `Default` implementation for `$name`.
313    (@default $name:ident { $($field:ident;)* }) => {
314        /// Returns a value for the bitfield where all fields are set to their default value.
315        impl ::core::default::Default for $name {
316            fn default() -> Self {
317                #[allow(unused_mut)]
318                let mut value = Self(Default::default());
319
320                ::kernel::macros::paste!(
321                $(
322                value.[<set_ $field>](Default::default());
323                )*
324                );
325
326                value
327            }
328        }
329    };
330}
~/ Read-only file preview.