From: Alexandre Courbot <acourbot@nvidia.com>
To: "Joel Fernandes" <joelagnelf@nvidia.com>,
"Yury Norov" <yury.norov@gmail.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>
Cc: John Hubbard <jhubbard@nvidia.com>,
Alistair Popple <apopple@nvidia.com>,
Timur Tabi <ttabi@nvidia.com>, Zhi Wang <zhiw@nvidia.com>,
Eliot Courtney <ecourtney@nvidia.com>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
driver-core@lists.linux.dev, dri-devel@lists.freedesktop.org,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
Date: Thu, 09 Apr 2026 23:58:47 +0900 [thread overview]
Message-ID: <20260409-bitfield-v2-1-23ac400071cb@nvidia.com> (raw)
In-Reply-To: <20260409-bitfield-v2-0-23ac400071cb@nvidia.com>
Extract the bitfield-defining part of the `register!` macro into an
independent macro used to define bitfield types with bounds-checked
accessors.
Each field is represented as a `Bounded` of the appropriate bit width,
ensuring field values are never silently truncated.
Fields can optionally be converted to/from custom types, either fallibly
or infallibly.
Appropriate documentation is also added, and a MAINTAINERS entry created
for the new module.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
MAINTAINERS | 8 +
rust/kernel/bitfield.rs | 491 +++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/io/register.rs | 246 +----------------------
rust/kernel/lib.rs | 1 +
4 files changed, 502 insertions(+), 244 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index b01791963e25..77f2617ade5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23186,6 +23186,14 @@ F: scripts/*rust*
F: tools/testing/selftests/rust/
K: \b(?i:rust)\b
+RUST [BITFIELD]
+M: Alexandre Courbot <acourbot@nvidia.com>
+M: Joel Fernandes <joelagnelf@nvidia.com>
+R: Yury Norov <yury.norov@gmail.com>
+L: rust-for-linux@vger.kernel.org
+S: Maintained
+F: rust/kernel/bitfield.rs
+
RUST [ALLOC]
M: Danilo Krummrich <dakr@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
new file mode 100644
index 000000000000..f5948eec8a76
--- /dev/null
+++ b/rust/kernel/bitfield.rs
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Support for defining bitfields as Rust structures.
+//!
+//! The [`bitfield!`](kernel::bitfield!) macro declares integer types that are split into distinct
+//! bit fields of arbitrary length. Each field is typed using [`Bounded`](kernel::num::Bounded) to
+//! ensure values are properly validated and to avoid implicit data loss.
+//!
+//! # Example
+//!
+//! ```rust
+//! use kernel::bitfield;
+//! use kernel::num::Bounded;
+//!
+//! bitfield! {
+//! pub struct Rgb(u16) {
+//! 15:11 blue;
+//! 10:5 green;
+//! 4:0 red;
+//! }
+//! }
+//!
+//! // Valid value for the `blue` field.
+//! let blue = Bounded::<u16, 5>::new::<0x18>();
+//!
+//! // Setters can be chained. Values ranges are checked at compile-time.
+//! let color = Rgb::zeroed()
+//! // Compile-time bounds check of constant value.
+//! .with_const_red::<0x10>()
+//! .with_const_green::<0x1f>()
+//! // A `Bounded` can also be passed.
+//! .with_blue(blue);
+//!
+//! assert_eq!(color.red(), 0x10);
+//! assert_eq!(color.green(), 0x1f);
+//! assert_eq!(color.blue(), 0x18);
+//! assert_eq!(
+//! color.into_raw(),
+//! (0x18 << Rgb::BLUE_SHIFT) + (0x1f << Rgb::GREEN_SHIFT) + 0x10,
+//! );
+//!
+//! // Convert to/from the backing storage type.
+//! let raw: u16 = color.into();
+//! assert_eq!(Rgb::from(raw), color);
+//! ```
+//!
+//! # Syntax
+//!
+//! ```text
+//! bitfield! {
+//! #[attributes]
+//! // Documentation for `Name`.
+//! pub struct Name(storage_type) {
+//! // `field_1` documentation.
+//! hi:lo field_1;
+//! // `field_2` documentation.
+//! hi:lo field_2 => ConvertedType;
+//! // `field_3` documentation.
+//! hi:lo field_3 ?=> ConvertedType;
+//! ...
+//! }
+//! }
+//! ```
+//!
+//! - `storage_type`: The underlying integer type (`u8`, `u16`, `u32`, `u64`).
+//! - `hi:lo`: Bit range (inclusive), where `hi >= lo`.
+//! - `=> Type`: Optional infallible conversion (see [below](#infallible-conversion-)).
+//! - `?=> Type`: Optional fallible conversion (see [below](#fallible-conversion-)).
+//! - Documentation strings and attributes are optional.
+//!
+//! # Generated code
+//!
+//! Each field is internally represented as a [`Bounded`] parameterized by its bit width. Field
+//! values can either be set/retrieved directly, or converted from/to another type.
+//!
+//! The use of `Bounded` for each field enforces bounds-checking (at build time or runtime) of every
+//! value assigned to a field. This ensures that data is never accidentally truncated.
+//!
+//! The macro generates the bitfield type, [`From`] and [`Into`] implementations for its storage
+//! type, as well as [`Debug`] and [`Zeroable`](pin_init::Zeroable) implementations.
+//!
+//! For each field, it also generates:
+//!
+//! - `with_field(value)` — infallible setter; the argument type must be statically known to fit
+//! the field width.
+//! - `with_const_field::<VALUE>()` — const setter; the value is validated at compile time.
+//! Usually shorter to use than `with_field` for constant values as it doesn't require
+//! constructing a `Bounded`.
+//! - `try_with_field(value)` — fallible setter. Returns an error if the value is out of range.
+//! - `FIELD_MASK`, `FIELD_SHIFT`, `FIELD_RANGE` - constants for manual bit manipulation.
+//!
+//! # Implicit conversions
+//!
+//! Types that fit entirely within a field's bit width can be used directly with setters. For
+//! example, `bool` works with single-bit fields, and `u8` works with 8-bit fields:
+//!
+//! ```rust
+//! use kernel::bitfield;
+//!
+//! bitfield! {
+//! pub struct Flags(u32) {
+//! 15:8 byte_field;
+//! 0:0 flag;
+//! }
+//! }
+//!
+//! let flags = Flags::zeroed()
+//! .with_byte_field(0x42_u8)
+//! .with_flag(true);
+//!
+//! assert_eq!(flags.into_raw(), (0x42 << Flags::BYTE_FIELD_SHIFT) | 1);
+//! ```
+//!
+//! # Runtime bounds checking
+//!
+//! When a value is not known at compile time, use `try_with_field()` to check bounds at runtime:
+//!
+//! ```rust
+//! use kernel::bitfield;
+//!
+//! bitfield! {
+//! pub struct Config(u8) {
+//! 3:0 nibble;
+//! }
+//! }
+//!
+//! fn set_nibble(config: Config, value: u8) -> Result<Config, Error> {
+//! // Returns `EOVERFLOW` if `value > 0xf`.
+//! config.try_with_nibble(value)
+//! }
+//! # Ok::<(), Error>(())
+//! ```
+//!
+//! # Type conversion
+//!
+//! Fields can be automatically converted to/from a custom type using `=>` (infallible) or `?=>`
+//! (fallible). The custom type must implement the appropriate `From` or `TryFrom` traits with
+//! `Bounded`.
+//!
+//! ## Infallible conversion (`=>`)
+//!
+//! Use this when all possible bit patterns of a field map to valid values:
+//!
+//! ```rust
+//! use kernel::bitfield;
+//! use kernel::num::Bounded;
+//!
+//! #[derive(Debug, Clone, Copy, PartialEq)]
+//! enum Power {
+//! Off,
+//! On,
+//! }
+//!
+//! impl From<Bounded<u32, 1>> for Power {
+//! fn from(v: Bounded<u32, 1>) -> Self {
+//! match *v {
+//! 0 => Power::Off,
+//! _ => Power::On,
+//! }
+//! }
+//! }
+//!
+//! impl From<Power> for Bounded<u32, 1> {
+//! fn from(p: Power) -> Self {
+//! (p as u32 != 0).into()
+//! }
+//! }
+//!
+//! bitfield! {
+//! pub struct Control(u32) {
+//! 0:0 power => Power;
+//! }
+//! }
+//!
+//! let ctrl = Control::zeroed().with_power(Power::On);
+//! assert_eq!(ctrl.power(), Power::On);
+//! ```
+//!
+//! ## Fallible conversion (`?=>`)
+//!
+//! Use this when some bit patterns of a field are invalid. The getter returns a [`Result`]:
+//!
+//! ```rust
+//! use kernel::bitfield;
+//! use kernel::num::Bounded;
+//!
+//! #[derive(Debug, Clone, Copy, PartialEq)]
+//! enum Mode {
+//! Low = 0,
+//! High = 1,
+//! Auto = 2,
+//! // 3 is invalid
+//! }
+//!
+//! impl TryFrom<Bounded<u32, 2>> for Mode {
+//! type Error = u32;
+//!
+//! fn try_from(v: Bounded<u32, 2>) -> Result<Self, u32> {
+//! match *v {
+//! 0 => Ok(Mode::Low),
+//! 1 => Ok(Mode::High),
+//! 2 => Ok(Mode::Auto),
+//! n => Err(n),
+//! }
+//! }
+//! }
+//!
+//! impl From<Mode> for Bounded<u32, 2> {
+//! fn from(m: Mode) -> Self {
+//! match m {
+//! Mode::Low => Bounded::<u32, _>::new::<0>(),
+//! Mode::High => Bounded::<u32, _>::new::<1>(),
+//! Mode::Auto => Bounded::<u32, _>::new::<2>(),
+//! }
+//! }
+//! }
+//!
+//! bitfield! {
+//! pub struct Config(u32) {
+//! 1:0 mode ?=> Mode;
+//! }
+//! }
+//!
+//! let cfg = Config::zeroed().with_mode(Mode::Auto);
+//! assert_eq!(cfg.mode(), Ok(Mode::Auto));
+//!
+//! // Invalid bit pattern returns an error.
+//! assert_eq!(Config::from(0b11).mode(), Err(3));
+//! ```
+//!
+//! [`Bounded`]: kernel::num::Bounded
+
+/// Defines a bitfield struct with bounds-checked accessors for individual bit ranges.
+///
+/// See the [`mod@kernel::bitfield`] module for full documentation and examples.
+#[macro_export]
+macro_rules! bitfield {
+ // Entry point defining the bitfield struct, its implementations and its field accessors.
+ (
+ $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
+ ) => {
+ $crate::bitfield!(@core
+ #[allow(non_camel_case_types)]
+ $(#[$attr])* $vis $name $storage
+ );
+ $crate::bitfield!(@fields $vis $name $storage { $($fields)* });
+ };
+
+ // All rules below are helpers.
+
+ // Defines the wrapper `$name` type and its conversions from/to the storage type.
+ (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
+ $(#[$attr])*
+ #[repr(transparent)]
+ #[derive(Clone, Copy, PartialEq, Eq)]
+ $vis struct $name {
+ inner: $storage,
+ }
+
+ #[allow(dead_code)]
+ impl $name {
+ /// Creates a bitfield from a raw value.
+ #[inline(always)]
+ $vis const fn from_raw(value: $storage) -> Self {
+ Self{ inner: value }
+ }
+
+ /// Turns this bitfield into its raw value.
+ ///
+ /// This is similar to the [`From`] implementation, but is shorter to invoke in
+ /// most cases.
+ #[inline(always)]
+ $vis const fn into_raw(self) -> $storage {
+ self.inner
+ }
+ }
+
+ // SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
+ unsafe impl ::pin_init::Zeroable for $name {}
+
+ impl ::core::convert::From<$name> for $storage {
+ #[inline(always)]
+ fn from(val: $name) -> $storage {
+ val.into_raw()
+ }
+ }
+
+ impl ::core::convert::From<$storage> for $name {
+ #[inline(always)]
+ fn from(val: $storage) -> $name {
+ Self::from_raw(val)
+ }
+ }
+ };
+
+ // Definitions requiring knowledge of individual fields: private and public field accessors,
+ // and `Debug` implementation.
+ (@fields $vis:vis $name:ident $storage:ty {
+ $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
+ $(?=> $try_into_type:ty)?
+ $(=> $into_type:ty)?
+ ;
+ )*
+ }
+ ) => {
+ #[allow(dead_code)]
+ impl $name {
+ $(
+ $crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
+ $crate::bitfield!(
+ @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
+ $(?=> $try_into_type)?
+ $(=> $into_type)?
+ );
+ )*
+ }
+
+ $crate::bitfield!(@debug $name { $($field;)* });
+ };
+
+ // Private field accessors working with the exact `Bounded` type for the field.
+ (
+ @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
+ ) => {
+ ::kernel::macros::paste!(
+ $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
+ $vis const [<$field:upper _MASK>]: $storage =
+ ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
+ $vis const [<$field:upper _SHIFT>]: u32 = $lo;
+ );
+
+ ::kernel::macros::paste!(
+ fn [<__ $field>](self) ->
+ ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
+ // Left shift to align the field's MSB with the storage MSB.
+ const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
+ // Right shift to move the top-aligned field to bit 0 of the storage.
+ const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
+
+ // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
+ // output type.
+ let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
+ self.inner << ALIGN_TOP
+ );
+ val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
+ }
+
+ const fn [<__with_ $field>](
+ mut self,
+ value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
+ ) -> Self
+ {
+ const MASK: $storage = <$name>::[<$field:upper _MASK>];
+ const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
+
+ let value = value.get() << SHIFT;
+ self.inner = (self.inner & !MASK) | value;
+
+ self
+ }
+ );
+ };
+
+ // Public accessors for fields infallibly (`=>`) converted to a type.
+ (
+ @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
+ $hi:literal:$lo:literal $field:ident => $into_type:ty
+ ) => {
+ ::kernel::macros::paste!(
+
+ $(#[doc = $doc])*
+ #[doc = "Returns the value of this field."]
+ #[inline(always)]
+ $vis fn $field(self) -> $into_type
+ {
+ self.[<__ $field>]().into()
+ }
+
+ $(#[doc = $doc])*
+ #[doc = "Sets this field to the given `value`."]
+ #[inline(always)]
+ $vis fn [<with_ $field>](self, value: $into_type) -> Self
+ {
+ self.[<__with_ $field>](value.into())
+ }
+
+ );
+ };
+
+ // Public accessors for fields fallibly (`?=>`) converted to a type.
+ (
+ @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
+ $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
+ ) => {
+ ::kernel::macros::paste!(
+
+ $(#[doc = $doc])*
+ #[doc = "Returns the value of this field."]
+ #[inline(always)]
+ $vis fn $field(self) ->
+ Result<
+ $try_into_type,
+ <$try_into_type as ::core::convert::TryFrom<
+ ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
+ >>::Error
+ >
+ {
+ self.[<__ $field>]().try_into()
+ }
+
+ $(#[doc = $doc])*
+ #[doc = "Sets this field to the given `value`."]
+ #[inline(always)]
+ $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
+ {
+ self.[<__with_ $field>](value.into())
+ }
+
+ );
+ };
+
+ // Public accessors for fields not converted to a type.
+ (
+ @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
+ $hi:tt:$lo:tt $field:ident
+ ) => {
+ ::kernel::macros::paste!(
+
+ $(#[doc = $doc])*
+ #[doc = "Returns the value of this field."]
+ #[inline(always)]
+ $vis fn $field(self) ->
+ ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
+ {
+ self.[<__ $field>]()
+ }
+
+ $(#[doc = $doc])*
+ #[doc = "Sets this field to the compile-time constant `VALUE`."]
+ #[inline(always)]
+ $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
+ self.[<__with_ $field>](
+ ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
+ )
+ }
+
+ $(#[doc = $doc])*
+ #[doc = "Sets this field to the given `value`."]
+ #[inline(always)]
+ $vis fn [<with_ $field>]<T>(
+ self,
+ value: T,
+ ) -> Self
+ where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
+ {
+ self.[<__with_ $field>](value.into())
+ }
+
+ $(#[doc = $doc])*
+ #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
+ #[inline(always)]
+ $vis fn [<try_with_ $field>]<T>(
+ self,
+ value: T,
+ ) -> ::kernel::error::Result<Self>
+ where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
+ {
+ Ok(
+ self.[<__with_ $field>](
+ value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
+ )
+ )
+ }
+
+ );
+ };
+
+ // `Debug` implementation.
+ (@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.inner))
+ $(
+ .field(stringify!($field), &self.$field())
+ )*
+ .finish()
+ }
+ }
+ };
+}
diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs
index abc49926abfe..388647f28292 100644
--- a/rust/kernel/io/register.rs
+++ b/rust/kernel/io/register.rs
@@ -956,11 +956,10 @@ macro_rules! register {
(
@bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
) => {
- $crate::register!(@bitfield_core
+ $crate::bitfield!(
#[allow(non_camel_case_types)]
- $(#[$attr])* $vis $name $storage
+ $(#[$attr])* $vis struct $name($storage) { $($fields)* }
);
- $crate::register!(@bitfield_fields $vis $name $storage { $($fields)* });
};
// Implementations shared by all registers types.
@@ -1016,245 +1015,4 @@ impl $crate::io::register::RegisterArray for $name {
impl $crate::io::register::RelativeRegisterArray for $name {}
};
-
- // Defines the wrapper `$name` type and its conversions from/to the storage type.
- (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
- $(#[$attr])*
- #[repr(transparent)]
- #[derive(Clone, Copy, PartialEq, Eq)]
- $vis struct $name {
- inner: $storage,
- }
-
- #[allow(dead_code)]
- impl $name {
- /// Creates a bitfield from a raw value.
- #[inline(always)]
- $vis const fn from_raw(value: $storage) -> Self {
- Self{ inner: value }
- }
-
- /// Turns this bitfield into its raw value.
- ///
- /// This is similar to the [`From`] implementation, but is shorter to invoke in
- /// most cases.
- #[inline(always)]
- $vis const fn into_raw(self) -> $storage {
- self.inner
- }
- }
-
- // SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
- unsafe impl ::pin_init::Zeroable for $name {}
-
- impl ::core::convert::From<$name> for $storage {
- #[inline(always)]
- fn from(val: $name) -> $storage {
- val.into_raw()
- }
- }
-
- impl ::core::convert::From<$storage> for $name {
- #[inline(always)]
- fn from(val: $storage) -> $name {
- Self::from_raw(val)
- }
- }
- };
-
- // Definitions requiring knowledge of individual fields: private and public field accessors,
- // and `Debug` implementation.
- (@bitfield_fields $vis:vis $name:ident $storage:ty {
- $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
- $(?=> $try_into_type:ty)?
- $(=> $into_type:ty)?
- ;
- )*
- }
- ) => {
- #[allow(dead_code)]
- impl $name {
- $(
- $crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
- $crate::register!(
- @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
- $(?=> $try_into_type)?
- $(=> $into_type)?
- );
- )*
- }
-
- $crate::register!(@debug $name { $($field;)* });
- };
-
- // Private field accessors working with the exact `Bounded` type for the field.
- (
- @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
- ) => {
- ::kernel::macros::paste!(
- $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
- $vis const [<$field:upper _MASK>]: $storage =
- ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
- $vis const [<$field:upper _SHIFT>]: u32 = $lo;
- );
-
- ::kernel::macros::paste!(
- fn [<__ $field>](self) ->
- ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
- // Left shift to align the field's MSB with the storage MSB.
- const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
- // Right shift to move the top-aligned field to bit 0 of the storage.
- const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
-
- // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
- // output type.
- let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
- self.inner << ALIGN_TOP
- );
- val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
- }
-
- const fn [<__with_ $field>](
- mut self,
- value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
- ) -> Self
- {
- const MASK: $storage = <$name>::[<$field:upper _MASK>];
- const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
-
- let value = value.get() << SHIFT;
- self.inner = (self.inner & !MASK) | value;
-
- self
- }
- );
- };
-
- // Public accessors for fields infallibly (`=>`) converted to a type.
- (
- @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
- $hi:literal:$lo:literal $field:ident => $into_type:ty
- ) => {
- ::kernel::macros::paste!(
-
- $(#[doc = $doc])*
- #[doc = "Returns the value of this field."]
- #[inline(always)]
- $vis fn $field(self) -> $into_type
- {
- self.[<__ $field>]().into()
- }
-
- $(#[doc = $doc])*
- #[doc = "Sets this field to the given `value`."]
- #[inline(always)]
- $vis fn [<with_ $field>](self, value: $into_type) -> Self
- {
- self.[<__with_ $field>](value.into())
- }
-
- );
- };
-
- // Public accessors for fields fallibly (`?=>`) converted to a type.
- (
- @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
- $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
- ) => {
- ::kernel::macros::paste!(
-
- $(#[doc = $doc])*
- #[doc = "Returns the value of this field."]
- #[inline(always)]
- $vis fn $field(self) ->
- Result<
- $try_into_type,
- <$try_into_type as ::core::convert::TryFrom<
- ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
- >>::Error
- >
- {
- self.[<__ $field>]().try_into()
- }
-
- $(#[doc = $doc])*
- #[doc = "Sets this field to the given `value`."]
- #[inline(always)]
- $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
- {
- self.[<__with_ $field>](value.into())
- }
-
- );
- };
-
- // Public accessors for fields not converted to a type.
- (
- @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
- $hi:tt:$lo:tt $field:ident
- ) => {
- ::kernel::macros::paste!(
-
- $(#[doc = $doc])*
- #[doc = "Returns the value of this field."]
- #[inline(always)]
- $vis fn $field(self) ->
- ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
- {
- self.[<__ $field>]()
- }
-
- $(#[doc = $doc])*
- #[doc = "Sets this field to the compile-time constant `VALUE`."]
- #[inline(always)]
- $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
- self.[<__with_ $field>](
- ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
- )
- }
-
- $(#[doc = $doc])*
- #[doc = "Sets this field to the given `value`."]
- #[inline(always)]
- $vis fn [<with_ $field>]<T>(
- self,
- value: T,
- ) -> Self
- where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
- {
- self.[<__with_ $field>](value.into())
- }
-
- $(#[doc = $doc])*
- #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
- #[inline(always)]
- $vis fn [<try_with_ $field>]<T>(
- self,
- value: T,
- ) -> ::kernel::error::Result<Self>
- where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
- {
- Ok(
- self.[<__with_ $field>](
- value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
- )
- )
- }
-
- );
- };
-
- // `Debug` implementation.
- (@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.inner))
- $(
- .field(stringify!($field), &self.$field())
- )*
- .finish()
- }
- }
- };
}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 40de00ce4f97..31e5f5908dfc 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -77,6 +77,7 @@
pub mod alloc;
#[cfg(CONFIG_AUXILIARY_BUS)]
pub mod auxiliary;
+pub mod bitfield;
pub mod bitmap;
pub mod bits;
#[cfg(CONFIG_BLOCK)]
--
2.53.0
next prev parent reply other threads:[~2026-04-09 14:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
2026-04-09 14:58 ` Alexandre Courbot [this message]
2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260409-bitfield-v2-1-23ac400071cb@nvidia.com \
--to=acourbot@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=joelagnelf@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
--cc=yury.norov@gmail.com \
--cc=zhiw@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox