Skip to content

Commit af46044

Browse files
Joel Fernandesgregkh
authored andcommitted
gpu: nova-core: bitfield: Move bitfield-specific code from register! into new macro
[ Upstream commit 71ea85b ] Move the bitfield-specific code from the register macro into a new macro called bitfield. This will be used to define structs with bitfields, similar to C language. Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Edwin Peer <epeer@nvidia.com> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Message-ID: <20251016151323.1201196-3-joelagnelf@nvidia.com> Stable-dep-of: de0aca1 ("gpu: nova-core: bitfield: fix broken Default implementation") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e6b0e1f commit af46044

3 files changed

Lines changed: 332 additions & 249 deletions

File tree

drivers/gpu/nova-core/bitfield.rs

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
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+
/// struct ControlReg {
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+
/// - Debug and Default implementations.
74+
///
75+
/// Fields are defined as follows:
76+
///
77+
/// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or
78+
/// `bool`. Note that `bool` fields must have a range of 1 bit.
79+
/// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns
80+
/// the result.
81+
/// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation
82+
/// and returns the result. This is useful with fields for which not all values are valid.
83+
macro_rules! bitfield {
84+
// Main entry point - defines the bitfield struct with fields
85+
(struct $name:ident $(, $comment:literal)? { $($fields:tt)* }) => {
86+
bitfield!(@core $name $(, $comment)? { $($fields)* });
87+
};
88+
89+
// All rules below are helpers.
90+
91+
// Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`,
92+
// `Default`, `BitOr`, and conversion to the value type) and field accessor methods.
93+
(@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => {
94+
$(
95+
#[doc=$comment]
96+
)?
97+
#[repr(transparent)]
98+
#[derive(Clone, Copy)]
99+
pub(crate) struct $name(u32);
100+
101+
impl ::core::ops::BitOr for $name {
102+
type Output = Self;
103+
104+
fn bitor(self, rhs: Self) -> Self::Output {
105+
Self(self.0 | rhs.0)
106+
}
107+
}
108+
109+
impl ::core::convert::From<$name> for u32 {
110+
fn from(val: $name) -> u32 {
111+
val.0
112+
}
113+
}
114+
115+
bitfield!(@fields_dispatcher $name { $($fields)* });
116+
};
117+
118+
// Captures the fields and passes them to all the implementers that require field information.
119+
//
120+
// Used to simplify the matching rules for implementers, so they don't need to match the entire
121+
// complex fields rule even though they only make use of part of it.
122+
(@fields_dispatcher $name:ident {
123+
$($hi:tt:$lo:tt $field:ident as $type:tt
124+
$(?=> $try_into_type:ty)?
125+
$(=> $into_type:ty)?
126+
$(, $comment:literal)?
127+
;
128+
)*
129+
}
130+
) => {
131+
bitfield!(@field_accessors $name {
132+
$(
133+
$hi:$lo $field as $type
134+
$(?=> $try_into_type)?
135+
$(=> $into_type)?
136+
$(, $comment)?
137+
;
138+
)*
139+
});
140+
bitfield!(@debug $name { $($field;)* });
141+
bitfield!(@default $name { $($field;)* });
142+
};
143+
144+
// Defines all the field getter/setter methods for `$name`.
145+
(
146+
@field_accessors $name:ident {
147+
$($hi:tt:$lo:tt $field:ident as $type:tt
148+
$(?=> $try_into_type:ty)?
149+
$(=> $into_type:ty)?
150+
$(, $comment:literal)?
151+
;
152+
)*
153+
}
154+
) => {
155+
$(
156+
bitfield!(@check_field_bounds $hi:$lo $field as $type);
157+
)*
158+
159+
#[allow(dead_code)]
160+
impl $name {
161+
$(
162+
bitfield!(@field_accessor $name $hi:$lo $field as $type
163+
$(?=> $try_into_type)?
164+
$(=> $into_type)?
165+
$(, $comment)?
166+
;
167+
);
168+
)*
169+
}
170+
};
171+
172+
// Boolean fields must have `$hi == $lo`.
173+
(@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {
174+
#[allow(clippy::eq_op)]
175+
const _: () = {
176+
::kernel::build_assert!(
177+
$hi == $lo,
178+
concat!("boolean field `", stringify!($field), "` covers more than one bit")
179+
);
180+
};
181+
};
182+
183+
// Non-boolean fields must have `$hi >= $lo`.
184+
(@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {
185+
#[allow(clippy::eq_op)]
186+
const _: () = {
187+
::kernel::build_assert!(
188+
$hi >= $lo,
189+
concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")
190+
);
191+
};
192+
};
193+
194+
// Catches fields defined as `bool` and convert them into a boolean value.
195+
(
196+
@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty
197+
$(, $comment:literal)?;
198+
) => {
199+
bitfield!(
200+
@leaf_accessor $name $hi:$lo $field
201+
{ |f| <$into_type>::from(if f != 0 { true } else { false }) }
202+
bool $into_type => $into_type $(, $comment)?;
203+
);
204+
};
205+
206+
// Shortcut for fields defined as `bool` without the `=>` syntax.
207+
(
208+
@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?;
209+
) => {
210+
bitfield!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;);
211+
};
212+
213+
// Catches the `?=>` syntax for non-boolean fields.
214+
(
215+
@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty
216+
$(, $comment:literal)?;
217+
) => {
218+
bitfield!(@leaf_accessor $name $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 $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty
230+
$(, $comment:literal)?;
231+
) => {
232+
bitfield!(@leaf_accessor $name $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 $name:ident $hi:tt:$lo:tt $field:ident as $type:tt
239+
$(, $comment:literal)?;
240+
) => {
241+
bitfield!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;);
242+
};
243+
244+
// Generates the accessor methods for a single field.
245+
(
246+
@leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident
247+
{ $process:expr } $prim_type:tt $to_type:ty => $res_type:ty $(, $comment:literal)?;
248+
) => {
249+
::kernel::macros::paste!(
250+
const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
251+
const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
252+
const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros();
253+
);
254+
255+
$(
256+
#[doc="Returns the value of this field:"]
257+
#[doc=$comment]
258+
)?
259+
#[inline(always)]
260+
pub(crate) fn $field(self) -> $res_type {
261+
::kernel::macros::paste!(
262+
const MASK: u32 = $name::[<$field:upper _MASK>];
263+
const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
264+
);
265+
let field = ((self.0 & MASK) >> SHIFT);
266+
267+
$process(field)
268+
}
269+
270+
::kernel::macros::paste!(
271+
$(
272+
#[doc="Sets the value of this field:"]
273+
#[doc=$comment]
274+
)?
275+
#[inline(always)]
276+
pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self {
277+
const MASK: u32 = $name::[<$field:upper _MASK>];
278+
const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
279+
let value = (u32::from($prim_type::from(value)) << SHIFT) & MASK;
280+
self.0 = (self.0 & !MASK) | value;
281+
282+
self
283+
}
284+
);
285+
};
286+
287+
// Generates the `Debug` implementation for `$name`.
288+
(@debug $name:ident { $($field:ident;)* }) => {
289+
impl ::kernel::fmt::Debug for $name {
290+
fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
291+
f.debug_struct(stringify!($name))
292+
.field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0))
293+
$(
294+
.field(stringify!($field), &self.$field())
295+
)*
296+
.finish()
297+
}
298+
}
299+
};
300+
301+
// Generates the `Default` implementation for `$name`.
302+
(@default $name:ident { $($field:ident;)* }) => {
303+
/// Returns a value for the bitfield where all fields are set to their default value.
304+
impl ::core::default::Default for $name {
305+
fn default() -> Self {
306+
#[allow(unused_mut)]
307+
let mut value = Self(Default::default());
308+
309+
::kernel::macros::paste!(
310+
$(
311+
value.[<set_ $field>](Default::default());
312+
)*
313+
);
314+
315+
value
316+
}
317+
}
318+
};
319+
}

drivers/gpu/nova-core/nova_core.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
//! Nova Core GPU Driver
44
5+
#[macro_use]
6+
mod bitfield;
7+
58
mod dma;
69
mod driver;
710
mod falcon;

0 commit comments

Comments
 (0)