public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] rust: add `bitfield!` macro
@ 2026-04-09 14:58 Alexandre Courbot
  2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
                   ` (3 more replies)
  0 siblings, 4 replies; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-09 14:58 UTC (permalink / raw)
  To: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel, Alexandre Courbot

This is the continuation of the `bitfield!` macro which started
alongside the `register!` one before being temporarily integrated into
it [1].

There were still ongoing discussions in [1], notably about improving the
ergonomics of setting bitfield values. This revision doesn't try to
address them yet (although the `with_const` setters partially solve the
issue); it just extracts the `bitfield!` macro and makes it available,
for the following reasons:

- To get the ball rolling again after several months of hiatus,
- Because it is already useful as-is, and ergonomics will be improved
  with macros built on top of the existing code,
- To allow dependencies over this series, notably the Nova MM series.

Thus, the discussions about ergonomics could take place as part of this
series, or as a follow-up - after all, bitfields are just registers
without I/O, so the present proposal does not introduce anything that is
not already in the kernel.

[1] https://lore.kernel.org/all/20260120-register-v1-0-723a1743b557@nvidia.com/

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Alexandre Courbot (2):
      rust: extract `bitfield!` macro from `register!`
      gpu: nova-core: switch to kernel bitfield macro

Joel Fernandes (1):
      rust: bitfield: Add KUNIT tests for bitfield

 MAINTAINERS                        |   8 +
 drivers/gpu/nova-core/bitfield.rs  | 329 ---------------
 drivers/gpu/nova-core/gsp/fw.rs    |  15 +-
 drivers/gpu/nova-core/nova_core.rs |   3 -
 rust/kernel/bitfield.rs            | 809 +++++++++++++++++++++++++++++++++++++
 rust/kernel/io/register.rs         | 246 +----------
 rust/kernel/lib.rs                 |   1 +
 7 files changed, 828 insertions(+), 583 deletions(-)
---
base-commit: a7a080bb4236ebe577b6776d940d1717912ff6dd
change-id: 20260408-bitfield-6e18254f4fdc

Best regards,
--  
Alexandre Courbot <acourbot@nvidia.com>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
  2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
@ 2026-04-09 14:58 ` Alexandre Courbot
  2026-04-13  2:29   ` Eliot Courtney
  2026-04-16  1:35   ` Yury Norov
  2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-09 14:58 UTC (permalink / raw)
  To: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel, Alexandre Courbot

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


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield
  2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
  2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
@ 2026-04-09 14:58 ` Alexandre Courbot
  2026-04-13  2:28   ` Eliot Courtney
  2026-04-16  2:44   ` Yury Norov
  2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
  2026-04-15 23:22 ` [PATCH v2 0/3] rust: add `bitfield!` macro John Hubbard
  3 siblings, 2 replies; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-09 14:58 UTC (permalink / raw)
  To: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel, Alexandre Courbot

From: Joel Fernandes <joelagnelf@nvidia.com>

Add KUNIT tests to make sure the macro is working correctly.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
[acourbot: update code to latest bitfield! macro.]
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 rust/kernel/bitfield.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 318 insertions(+)

diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
index f5948eec8a76..9ab8dafff36c 100644
--- a/rust/kernel/bitfield.rs
+++ b/rust/kernel/bitfield.rs
@@ -489,3 +489,321 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
         }
     };
 }
+
+#[::kernel::macros::kunit_tests(kernel_bitfield)]
+mod tests {
+    use core::convert::TryFrom;
+
+    use pin_init::Zeroable;
+
+    use kernel::num::Bounded;
+
+    // Enum types for testing => and ?=> conversions
+    #[derive(Debug, Clone, Copy, PartialEq)]
+    enum MemoryType {
+        Unmapped = 0,
+        Normal = 1,
+        Device = 2,
+        Reserved = 3,
+    }
+
+    impl TryFrom<Bounded<u64, 4>> for MemoryType {
+        type Error = u64;
+        fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> {
+            match value.get() {
+                0 => Ok(MemoryType::Unmapped),
+                1 => Ok(MemoryType::Normal),
+                2 => Ok(MemoryType::Device),
+                3 => Ok(MemoryType::Reserved),
+                _ => Err(value.get()),
+            }
+        }
+    }
+
+    impl From<MemoryType> for Bounded<u64, 4> {
+        fn from(mt: MemoryType) -> Bounded<u64, 4> {
+            Bounded::from_expr(mt as u64)
+        }
+    }
+
+    #[derive(Debug, Clone, Copy, PartialEq)]
+    enum Priority {
+        Low = 0,
+        Medium = 1,
+        High = 2,
+        Critical = 3,
+    }
+
+    impl From<Bounded<u16, 2>> for Priority {
+        fn from(value: Bounded<u16, 2>) -> Self {
+            match value & 0x3 {
+                0 => Priority::Low,
+                1 => Priority::Medium,
+                2 => Priority::High,
+                _ => Priority::Critical,
+            }
+        }
+    }
+
+    impl From<Priority> for Bounded<u16, 2> {
+        fn from(p: Priority) -> Bounded<u16, 2> {
+            Bounded::from_expr(p as u16)
+        }
+    }
+
+    bitfield! {
+        struct TestPageTableEntry(u64) {
+            0:0       present;
+            1:1       writable;
+            11:9      available;
+            15:12     mem_type ?=> MemoryType;
+            51:16     pfn;
+            61:52     available2;
+        }
+    }
+
+    bitfield! {
+        struct TestControlRegister(u16) {
+            0:0       enable;
+            3:1       mode;
+            5:4       priority => Priority;
+            7:4       priority_nibble;
+            15:8      channel;
+        }
+    }
+
+    bitfield! {
+        struct TestStatusRegister(u8) {
+            0:0       ready;
+            1:1       error;
+            3:2       state;
+            7:4       reserved;
+            7:0       full_byte;  // For entire register
+        }
+    }
+
+    #[test]
+    fn test_single_bits() {
+        let mut pte = TestPageTableEntry::zeroed();
+
+        assert!(!pte.present().into_bool());
+        assert!(!pte.writable().into_bool());
+        assert_eq!(u64::from(pte), 0x0);
+
+        pte = pte.with_present(true);
+        assert!(pte.present().into_bool());
+        assert_eq!(u64::from(pte), 0x1);
+
+        pte = pte.with_writable(true);
+        assert!(pte.writable().into_bool());
+        assert_eq!(u64::from(pte), 0x3);
+
+        pte = pte.with_writable(false);
+        assert!(!pte.writable().into_bool());
+        assert_eq!(u64::from(pte), 0x1);
+
+        assert_eq!(pte.available(), 0);
+        pte = pte.with_const_available::<0x5>();
+        assert_eq!(pte.available(), 0x5);
+        assert_eq!(u64::from(pte), 0xA01);
+    }
+
+    #[test]
+    fn test_range_fields() {
+        let mut pte = TestPageTableEntry::zeroed();
+        assert_eq!(u64::from(pte), 0x0);
+
+        pte = pte.with_const_pfn::<0x123456>();
+        assert_eq!(pte.pfn(), 0x123456);
+        assert_eq!(u64::from(pte), 0x1234560000);
+
+        pte = pte.with_const_available::<0x7>();
+        assert_eq!(pte.available(), 0x7);
+        assert_eq!(u64::from(pte), 0x1234560E00);
+
+        pte = pte.with_const_available2::<0x3FF>();
+        assert_eq!(pte.available2(), 0x3FF);
+        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_0E00u64);
+
+        // Test TryFrom with ?=> for MemoryType
+        pte = pte.with_mem_type(MemoryType::Device);
+        assert_eq!(pte.mem_type(), Ok(MemoryType::Device));
+        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_2E00u64);
+
+        pte = pte.with_mem_type(MemoryType::Normal);
+        assert_eq!(pte.mem_type(), Ok(MemoryType::Normal));
+        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_1E00u64);
+
+        // Test all valid values for mem_type
+        pte = pte.with_mem_type(MemoryType::Reserved);
+        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
+        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_3E00u64);
+
+        // Test failure case using mem_type field which has 4 bits (0-15)
+        // MemoryType only handles 0-3, so values 4-15 should return Err
+        let mut raw = pte.into_raw();
+        // Set bits 15:12 to 7 (invalid for MemoryType)
+        raw = (raw & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12);
+        let invalid_pte = TestPageTableEntry::from_raw(raw);
+        // Should return Err with the invalid value
+        assert_eq!(invalid_pte.mem_type(), Err(0x7));
+
+        // Test a valid value after testing invalid to ensure both cases work
+        // Set bits 15:12 to 2 (valid: Device)
+        raw = (raw & !::kernel::bits::genmask_u64(12..=15)) | (0x2 << 12);
+        let valid_pte = TestPageTableEntry::from_raw(raw);
+        assert_eq!(valid_pte.mem_type(), Ok(MemoryType::Device));
+
+        const MAX_PFN: u64 = ::kernel::bits::genmask_u64(0..=35);
+        pte = pte.with_const_pfn::<{ MAX_PFN }>();
+        assert_eq!(pte.pfn(), MAX_PFN);
+    }
+
+    #[test]
+    fn test_builder_pattern() {
+        let pte = TestPageTableEntry::zeroed()
+            .with_present(true)
+            .with_writable(true)
+            .with_const_available::<0x7>()
+            .with_const_pfn::<0xABCDEF>()
+            .with_mem_type(MemoryType::Reserved)
+            .with_const_available2::<0x3FF>();
+
+        assert!(pte.present().into_bool());
+        assert!(pte.writable().into_bool());
+        assert_eq!(pte.available(), 0x7);
+        assert_eq!(pte.pfn(), 0xABCDEF);
+        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
+        assert_eq!(pte.available2(), 0x3FF);
+    }
+
+    #[test]
+    fn test_raw_operations() {
+        let raw_value = 0x3FF0000031233E03u64;
+
+        let pte = TestPageTableEntry::from_raw(raw_value);
+        assert_eq!(u64::from(pte), raw_value);
+
+        assert!(pte.present().into_bool());
+        assert!(pte.writable().into_bool());
+        assert_eq!(pte.available(), 0x7);
+        assert_eq!(pte.pfn(), 0x3123);
+        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
+        assert_eq!(pte.available2(), 0x3FF);
+
+        // Test using direct constructor syntax TestStruct(value)
+        let pte2 = TestPageTableEntry::from_raw(raw_value);
+        assert_eq!(u64::from(pte2), raw_value);
+    }
+
+    #[test]
+    fn test_u16_bitfield() {
+        let mut ctrl = TestControlRegister::zeroed();
+
+        assert!(!ctrl.enable().into_bool());
+        assert_eq!(ctrl.mode(), 0);
+        assert_eq!(ctrl.priority(), Priority::Low);
+        assert_eq!(ctrl.priority_nibble(), 0);
+        assert_eq!(ctrl.channel(), 0);
+
+        ctrl = ctrl.with_enable(true);
+        assert!(ctrl.enable().into_bool());
+
+        ctrl = ctrl.with_const_mode::<0x5>();
+        assert_eq!(ctrl.mode(), 0x5);
+
+        // Test From conversion with =>
+        ctrl = ctrl.with_priority(Priority::High);
+        assert_eq!(ctrl.priority(), Priority::High);
+        assert_eq!(ctrl.priority_nibble(), 0x2); // High = 2 in bits 5:4
+
+        ctrl = ctrl.with_channel(0xAB);
+        assert_eq!(ctrl.channel(), 0xAB);
+
+        // Test overlapping fields
+        ctrl = ctrl.with_const_priority_nibble::<0xF>();
+        assert_eq!(ctrl.priority_nibble(), 0xF);
+        assert_eq!(ctrl.priority(), Priority::Critical); // bits 5:4 = 0x3
+
+        let ctrl2 = TestControlRegister::zeroed()
+            .with_enable(true)
+            .with_const_mode::<0x3>()
+            .with_priority(Priority::Medium)
+            .with_channel(0x42);
+
+        assert!(ctrl2.enable().into_bool());
+        assert_eq!(ctrl2.mode(), 0x3);
+        assert_eq!(ctrl2.priority(), Priority::Medium);
+        assert_eq!(ctrl2.channel(), 0x42);
+
+        let raw_value: u16 = 0x4217;
+        let ctrl3 = TestControlRegister::from_raw(raw_value);
+        assert_eq!(u16::from(ctrl3), raw_value);
+        assert!(ctrl3.enable().into_bool());
+        assert_eq!(ctrl3.priority(), Priority::Medium);
+        assert_eq!(ctrl3.priority_nibble(), 0x1);
+        assert_eq!(ctrl3.channel(), 0x42);
+    }
+
+    #[test]
+    fn test_u8_bitfield() {
+        let mut status = TestStatusRegister::zeroed();
+
+        assert!(!status.ready().into_bool());
+        assert!(!status.error().into_bool());
+        assert_eq!(status.state(), 0);
+        assert_eq!(status.reserved(), 0);
+        assert_eq!(status.full_byte(), 0);
+
+        status = status.with_ready(true);
+        assert!(status.ready().into_bool());
+        assert_eq!(status.full_byte(), 0x01);
+
+        status = status.with_error(true);
+        assert!(status.error().into_bool());
+        assert_eq!(status.full_byte(), 0x03);
+
+        status = status.with_const_state::<0x3>();
+        assert_eq!(status.state(), 0x3);
+        assert_eq!(status.full_byte(), 0x0F);
+
+        status = status.with_const_reserved::<0xA>();
+        assert_eq!(status.reserved(), 0xA);
+        assert_eq!(status.full_byte(), 0xAF);
+
+        // Test overlapping field
+        status = status.with_full_byte(0x55);
+        assert_eq!(status.full_byte(), 0x55);
+        assert!(status.ready().into_bool());
+        assert!(!status.error().into_bool());
+        assert_eq!(status.state(), 0x1);
+        assert_eq!(status.reserved(), 0x5);
+
+        let status2 = TestStatusRegister::zeroed()
+            .with_ready(true)
+            .with_const_state::<0x2>()
+            .with_const_reserved::<0x5>();
+
+        assert!(status2.ready().into_bool());
+        assert!(!status2.error().into_bool());
+        assert_eq!(status2.state(), 0x2);
+        assert_eq!(status2.reserved(), 0x5);
+        assert_eq!(status2.full_byte(), 0x59);
+
+        let raw_value: u8 = 0x59;
+        let status3 = TestStatusRegister::from_raw(raw_value);
+        assert_eq!(u8::from(status3), raw_value);
+        assert!(status3.ready().into_bool());
+        assert!(!status3.error().into_bool());
+        assert_eq!(status3.state(), 0x2);
+        assert_eq!(status3.reserved(), 0x5);
+        assert_eq!(status3.full_byte(), 0x59);
+
+        let status4 = TestStatusRegister::from_raw(0xFF);
+        assert!(status4.ready().into_bool());
+        assert!(status4.error().into_bool());
+        assert_eq!(status4.state(), 0x3);
+        assert_eq!(status4.reserved(), 0xF);
+        assert_eq!(status4.full_byte(), 0xFF);
+    }
+}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro
  2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
  2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
  2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
@ 2026-04-09 14:58 ` Alexandre Courbot
  2026-04-13  2:01   ` Eliot Courtney
  2026-04-15 23:20   ` John Hubbard
  2026-04-15 23:22 ` [PATCH v2 0/3] rust: add `bitfield!` macro John Hubbard
  3 siblings, 2 replies; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-09 14:58 UTC (permalink / raw)
  To: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel, Alexandre Courbot

Replace uses of the Nova-internal `bitfield!` macro by the kernel one,
and remove the now-unneeded local macro.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drivers/gpu/nova-core/bitfield.rs  | 329 -------------------------------------
 drivers/gpu/nova-core/gsp/fw.rs    |  15 +-
 drivers/gpu/nova-core/nova_core.rs |   3 -
 3 files changed, 8 insertions(+), 339 deletions(-)

diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs
deleted file mode 100644
index 02efdcf78d89..000000000000
--- a/drivers/gpu/nova-core/bitfield.rs
+++ /dev/null
@@ -1,329 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Bitfield library for Rust structures
-//!
-//! Support for defining bitfields in Rust structures. Also used by the [`register!`] macro.
-
-/// Defines a struct with accessors to access bits within an inner unsigned integer.
-///
-/// # Syntax
-///
-/// ```rust
-/// use nova_core::bitfield;
-///
-/// #[derive(Debug, Clone, Copy, Default)]
-/// enum Mode {
-///     #[default]
-///     Low = 0,
-///     High = 1,
-///     Auto = 2,
-/// }
-///
-/// impl TryFrom<u8> for Mode {
-///     type Error = u8;
-///     fn try_from(value: u8) -> Result<Self, Self::Error> {
-///         match value {
-///             0 => Ok(Mode::Low),
-///             1 => Ok(Mode::High),
-///             2 => Ok(Mode::Auto),
-///             _ => Err(value),
-///         }
-///     }
-/// }
-///
-/// impl From<Mode> for u8 {
-///     fn from(mode: Mode) -> u8 {
-///         mode as u8
-///     }
-/// }
-///
-/// #[derive(Debug, Clone, Copy, Default)]
-/// enum State {
-///     #[default]
-///     Inactive = 0,
-///     Active = 1,
-/// }
-///
-/// impl From<bool> for State {
-///     fn from(value: bool) -> Self {
-///         if value { State::Active } else { State::Inactive }
-///     }
-/// }
-///
-/// impl From<State> for bool {
-///     fn from(state: State) -> bool {
-///         match state {
-///             State::Inactive => false,
-///             State::Active => true,
-///         }
-///     }
-/// }
-///
-/// bitfield! {
-///     pub struct ControlReg(u32) {
-///         7:7 state as bool => State;
-///         3:0 mode as u8 ?=> Mode;
-///     }
-/// }
-/// ```
-///
-/// 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.
-///
-/// Note: Field accessors and setters inherit the same visibility as the struct itself.
-/// In the example above, both `mode()` and `set_mode()` methods will be `pub`.
-///
-/// 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.
-macro_rules! bitfield {
-    // Main entry point - defines the bitfield struct with fields
-    ($vis:vis struct $name:ident($storage:ty) $(, $comment:literal)? { $($fields:tt)* }) => {
-        bitfield!(@core $vis $name $storage $(, $comment)? { $($fields)* });
-    };
-
-    // All rules below are helpers.
-
-    // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`,
-    // `Default`, and conversion to the value type) and field accessor methods.
-    (@core $vis:vis $name:ident $storage:ty $(, $comment:literal)? { $($fields:tt)* }) => {
-        $(
-        #[doc=$comment]
-        )?
-        #[repr(transparent)]
-        #[derive(Clone, Copy)]
-        $vis struct $name($storage);
-
-        impl ::core::convert::From<$name> for $storage {
-            fn from(val: $name) -> $storage {
-                val.0
-            }
-        }
-
-        bitfield!(@fields_dispatcher $vis $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 $vis:vis $name:ident $storage:ty {
-        $($hi:tt:$lo:tt $field:ident as $type:tt
-            $(?=> $try_into_type:ty)?
-            $(=> $into_type:ty)?
-            $(, $comment:literal)?
-        ;
-        )*
-    }
-    ) => {
-        bitfield!(@field_accessors $vis $name $storage {
-            $(
-                $hi:$lo $field as $type
-                $(?=> $try_into_type)?
-                $(=> $into_type)?
-                $(, $comment)?
-            ;
-            )*
-        });
-        bitfield!(@debug $name { $($field;)* });
-        bitfield!(@default $name { $($field;)* });
-    };
-
-    // Defines all the field getter/setter methods for `$name`.
-    (
-        @field_accessors $vis:vis $name:ident $storage:ty {
-        $($hi:tt:$lo:tt $field:ident as $type:tt
-            $(?=> $try_into_type:ty)?
-            $(=> $into_type:ty)?
-            $(, $comment:literal)?
-        ;
-        )*
-        }
-    ) => {
-        $(
-            bitfield!(@check_field_bounds $hi:$lo $field as $type);
-        )*
-
-        #[allow(dead_code)]
-        impl $name {
-            $(
-            bitfield!(@field_accessor $vis $name $storage, $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 $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool
-            => $into_type:ty $(, $comment:literal)?;
-    ) => {
-        bitfield!(
-            @leaf_accessor $vis $name $storage, $hi:$lo $field
-            { |f| <$into_type>::from(f != 0) }
-            bool $into_type => $into_type $(, $comment)?;
-        );
-    };
-
-    // Shortcut for fields defined as `bool` without the `=>` syntax.
-    (
-        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as bool
-            $(, $comment:literal)?;
-    ) => {
-        bitfield!(
-            @field_accessor $vis $name $storage, $hi:$lo $field as bool => bool $(, $comment)?;
-        );
-    };
-
-    // Catches the `?=>` syntax for non-boolean fields.
-    (
-        @field_accessor $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
-            ?=> $try_into_type:ty $(, $comment:literal)?;
-    ) => {
-        bitfield!(@leaf_accessor $vis $name $storage, $hi:$lo $field
-            { |f| <$try_into_type>::try_from(f as $type) } $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 $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
-            => $into_type:ty $(, $comment:literal)?;
-    ) => {
-        bitfield!(@leaf_accessor $vis $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 $vis:vis $name:ident $storage:ty, $hi:tt:$lo:tt $field:ident as $type:tt
-            $(, $comment:literal)?;
-    ) => {
-        bitfield!(
-            @field_accessor $vis $name $storage, $hi:$lo $field as $type => $type $(, $comment)?;
-        );
-    };
-
-    // Generates the accessor methods for a single field.
-    (
-        @leaf_accessor $vis:vis $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>]: $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 = $lo;
-        );
-
-        $(
-        #[doc="Returns the value of this field:"]
-        #[doc=$comment]
-        )?
-        #[inline(always)]
-        $vis fn $field(self) -> $res_type {
-            ::kernel::macros::paste!(
-            const MASK: $storage = $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)]
-        $vis fn [<set_ $field>](mut self, value: $to_type) -> Self {
-            const MASK: $storage = $name::[<$field:upper _MASK>];
-            const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
-            let value = ($storage::from($prim_type::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 bitfield where all fields are set to their default value.
-        impl ::core::default::Default for $name {
-            fn default() -> Self {
-                let value = Self(Default::default());
-
-                ::kernel::macros::paste!(
-                $(
-                let value = value.[<set_ $field>](Default::default());
-                )*
-                );
-
-                value
-            }
-        }
-    };
-}
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 0c8a74f0e8ac..a7f75368c90e 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -9,6 +9,7 @@
 use core::ops::Range;
 
 use kernel::{
+    bitfield,
     dma::Coherent,
     prelude::*,
     ptr::{
@@ -17,8 +18,8 @@
         KnownSize, //
     },
     sizes::{
-        SZ_128K,
-        SZ_1M, //
+        SZ_128K, //
+        SZ_1M,
     },
     transmute::{
         AsBytes,
@@ -728,8 +729,8 @@ unsafe impl AsBytes for MsgqRxHeader {}
 
 bitfield! {
     struct MsgHeaderVersion(u32) {
-        31:24 major as u8;
-        23:16 minor as u8;
+        31:24 major;
+        23:16 minor;
     }
 }
 
@@ -738,9 +739,9 @@ impl MsgHeaderVersion {
     const MINOR_TOT: u8 = 0;
 
     fn new() -> Self {
-        Self::default()
-            .set_major(Self::MAJOR_TOT)
-            .set_minor(Self::MINOR_TOT)
+        Self::zeroed()
+            .with_major(Self::MAJOR_TOT)
+            .with_minor(Self::MINOR_TOT)
     }
 }
 
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 04a1fa6b25f8..3a0c45481a92 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -10,9 +10,6 @@
     InPlaceModule, //
 };
 
-#[macro_use]
-mod bitfield;
-
 mod driver;
 mod falcon;
 mod fb;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro
  2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
@ 2026-04-13  2:01   ` Eliot Courtney
  2026-04-15 23:20   ` John Hubbard
  1 sibling, 0 replies; 28+ messages in thread
From: Eliot Courtney @ 2026-04-13  2:01 UTC (permalink / raw)
  To: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel

On Thu Apr 9, 2026 at 11:58 PM JST, Alexandre Courbot wrote:
> Replace uses of the Nova-internal `bitfield!` macro by the kernel one,
> and remove the now-unneeded local macro.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield
  2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
@ 2026-04-13  2:28   ` Eliot Courtney
  2026-04-16  2:44   ` Yury Norov
  1 sibling, 0 replies; 28+ messages in thread
From: Eliot Courtney @ 2026-04-13  2:28 UTC (permalink / raw)
  To: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel

On Thu Apr 9, 2026 at 11:58 PM JST, Alexandre Courbot wrote:
> From: Joel Fernandes <joelagnelf@nvidia.com>
>
> Add KUNIT tests to make sure the macro is working correctly.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> [acourbot: update code to latest bitfield! macro.]
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
  2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
@ 2026-04-13  2:29   ` Eliot Courtney
  2026-04-15 23:18     ` John Hubbard
  2026-04-16  1:35   ` Yury Norov
  1 sibling, 1 reply; 28+ messages in thread
From: Eliot Courtney @ 2026-04-13  2:29 UTC (permalink / raw)
  To: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, David Airlie, Simona Vetter
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Zhi Wang,
	Eliot Courtney, linux-kernel, rust-for-linux, driver-core,
	dri-devel

On Thu Apr 9, 2026 at 11:58 PM JST, Alexandre Courbot wrote:
> 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>

nit: Should this be kept in alphabetical order (e.g. with ALLOC here
below?).

> 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

In the nova version of bitfield we had @check_field_bounds. If we put
in the bit numbers the wrong way around, this patch gives a compile
error like:

```
attempt to compute `4_u32 - 7_u32`, which would overflow
```

The original nova version looks like it used build_assert, but I think
we can do it with const assert!, so we should be able to get a better
build error message for this case:

```
const _: () = assert!($hi >= $lo, "bitfield: hi bit must be >= lo bit");
```

With just that we get an extra build error, although it still spams the
confusing build error. We could also consider adding a function like:

```
pub const fn bitfield_width(hi: u32, lo: u32) -> u32 {
  assert!(hi >= lo, "bitfield: hi bit must be >= lo bit");
  hi + 1 - lo
}
```

Using this instead gets rid of some confusing build errors since we can
also use it in type bounds. But to get rid of all of them we would need
to do it for the mask etc and others.

WDYT?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
  2026-04-13  2:29   ` Eliot Courtney
@ 2026-04-15 23:18     ` John Hubbard
  0 siblings, 0 replies; 28+ messages in thread
From: John Hubbard @ 2026-04-15 23:18 UTC (permalink / raw)
  To: Eliot Courtney, Alexandre Courbot, Joel Fernandes, Yury Norov,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, David Airlie, Simona Vetter
  Cc: Alistair Popple, Timur Tabi, Zhi Wang, linux-kernel,
	rust-for-linux, driver-core, dri-devel

On 4/12/26 7:29 PM, Eliot Courtney wrote:
> On Thu Apr 9, 2026 at 11:58 PM JST, Alexandre Courbot wrote:
...
> In the nova version of bitfield we had @check_field_bounds. If we put
> in the bit numbers the wrong way around, this patch gives a compile
> error like:
> 
> ```
> attempt to compute `4_u32 - 7_u32`, which would overflow
> ```
> 
> The original nova version looks like it used build_assert, but I think
> we can do it with const assert!, so we should be able to get a better
> build error message for this case:
> 
> ```
> const _: () = assert!($hi >= $lo, "bitfield: hi bit must be >= lo bit");
> ```
> 
> With just that we get an extra build error, although it still spams the
> confusing build error. We could also consider adding a function like:
> 
> ```
> pub const fn bitfield_width(hi: u32, lo: u32) -> u32 {
>   assert!(hi >= lo, "bitfield: hi bit must be >= lo bit");
>   hi + 1 - lo
> }
> ```
> 
> Using this instead gets rid of some confusing build errors since we can
> also use it in type bounds. But to get rid of all of them we would need
> to do it for the mask etc and others.
> 
> WDYT?

Just an admin note: if you do any or all of the above, please let's make
it a separate patch, so that this first patch remains just a "move the
code" (almost, anyway).


thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro
  2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
  2026-04-13  2:01   ` Eliot Courtney
@ 2026-04-15 23:20   ` John Hubbard
  1 sibling, 0 replies; 28+ messages in thread
From: John Hubbard @ 2026-04-15 23:20 UTC (permalink / raw)
  To: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, David Airlie, Simona Vetter
  Cc: Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On 4/9/26 7:58 AM, Alexandre Courbot wrote:
> Replace uses of the Nova-internal `bitfield!` macro by the kernel one,
> and remove the now-unneeded local macro.

"and". :)

Translation: this wants to be two patches: a "use the new kernel
macro", and a pure "delete unused code" patch.

...
> diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
> index 0c8a74f0e8ac..a7f75368c90e 100644
> --- a/drivers/gpu/nova-core/gsp/fw.rs
> +++ b/drivers/gpu/nova-core/gsp/fw.rs
> @@ -9,6 +9,7 @@
>  use core::ops::Range;
>  
>  use kernel::{
> +    bitfield,
>      dma::Coherent,
>      prelude::*,
>      ptr::{
> @@ -17,8 +18,8 @@
>          KnownSize, //
>      },
>      sizes::{
> -        SZ_128K,
> -        SZ_1M, //
> +        SZ_128K, //

Just a nit, but definitely one we don't want to leave alone: that
trailing // belongs on the next line.

> +        SZ_1M,
thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
                   ` (2 preceding siblings ...)
  2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
@ 2026-04-15 23:22 ` John Hubbard
  2026-04-16  1:08   ` Eliot Courtney
  2026-04-16 22:18   ` Danilo Krummrich
  3 siblings, 2 replies; 28+ messages in thread
From: John Hubbard @ 2026-04-15 23:22 UTC (permalink / raw)
  To: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, David Airlie, Simona Vetter
  Cc: Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On 4/9/26 7:58 AM, Alexandre Courbot wrote:
> This is the continuation of the `bitfield!` macro which started
> alongside the `register!` one before being temporarily integrated into
> it [1].
> 
> There were still ongoing discussions in [1], notably about improving the
> ergonomics of setting bitfield values. This revision doesn't try to
> address them yet (although the `with_const` setters partially solve the
> issue); it just extracts the `bitfield!` macro and makes it available,
> for the following reasons:
> 
> - To get the ball rolling again after several months of hiatus,
> - Because it is already useful as-is, and ergonomics will be improved

Yes, and I'm worried now that we can't write things such as Joel's page
tables without it.

Can we please put this into your drm-rust-next-staging ASAP? I don't
think we have any comments that would really need to hold that up.


thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-15 23:22 ` [PATCH v2 0/3] rust: add `bitfield!` macro John Hubbard
@ 2026-04-16  1:08   ` Eliot Courtney
  2026-04-16 22:18   ` Danilo Krummrich
  1 sibling, 0 replies; 28+ messages in thread
From: Eliot Courtney @ 2026-04-16  1:08 UTC (permalink / raw)
  To: John Hubbard, Alexandre Courbot, Joel Fernandes, Yury Norov,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, David Airlie, Simona Vetter
  Cc: Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On Thu Apr 16, 2026 at 8:22 AM JST, John Hubbard wrote:
> On 4/9/26 7:58 AM, Alexandre Courbot wrote:
>> This is the continuation of the `bitfield!` macro which started
>> alongside the `register!` one before being temporarily integrated into
>> it [1].
>> 
>> There were still ongoing discussions in [1], notably about improving the
>> ergonomics of setting bitfield values. This revision doesn't try to
>> address them yet (although the `with_const` setters partially solve the
>> issue); it just extracts the `bitfield!` macro and makes it available,
>> for the following reasons:
>> 
>> - To get the ball rolling again after several months of hiatus,
>> - Because it is already useful as-is, and ergonomics will be improved
>
> Yes, and I'm worried now that we can't write things such as Joel's page
> tables without it.
>
> Can we please put this into your drm-rust-next-staging ASAP? I don't
> think we have any comments that would really need to hold that up.
>
>
> thanks,

Yes this seems fine to me as well. I'm personally fine with improving
the build errors in a follow-up.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
  2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
  2026-04-13  2:29   ` Eliot Courtney
@ 2026-04-16  1:35   ` Yury Norov
  1 sibling, 0 replies; 28+ messages in thread
From: Yury Norov @ 2026-04-16  1:35 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter, John Hubbard, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Thu, Apr 09, 2026 at 11:58:47PM +0900, Alexandre Courbot wrote:
> 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;

Hi Alex,

Can you please describe those implied naming limitations we've
discussed on the previous round, like with_blue, BLUE_SHIFT etc.
in a separate top comment?

With that,

Acked-by: Yury Norov <ynorov@nvidia.com>

> +//!     }
> +//! }
> +//!
> +//! // 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

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield
  2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
  2026-04-13  2:28   ` Eliot Courtney
@ 2026-04-16  2:44   ` Yury Norov
  2026-04-16  6:59     ` Alice Ryhl
  1 sibling, 1 reply; 28+ messages in thread
From: Yury Norov @ 2026-04-16  2:44 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, David Airlie,
	Simona Vetter, John Hubbard, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Thu, Apr 09, 2026 at 11:58:48PM +0900, Alexandre Courbot wrote:
> From: Joel Fernandes <joelagnelf@nvidia.com>
> 
> Add KUNIT tests to make sure the macro is working correctly.
> 
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> [acourbot: update code to latest bitfield! macro.]
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  rust/kernel/bitfield.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 318 insertions(+)
> 
> diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
> index f5948eec8a76..9ab8dafff36c 100644
> --- a/rust/kernel/bitfield.rs
> +++ b/rust/kernel/bitfield.rs
> @@ -489,3 +489,321 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
>          }
>      };
>  }
> +
> +#[::kernel::macros::kunit_tests(kernel_bitfield)]

Reading the Documentation/rust/testing.rst, and can't understand how
should one configure it to _not_ build the tests? This should be the
default behavior.

There's half a dozen already existing unit tests, and I didn't find
a mechanism to individually control them.

> +mod tests {
> +    use core::convert::TryFrom;
> +
> +    use pin_init::Zeroable;
> +
> +    use kernel::num::Bounded;
> +
> +    // Enum types for testing => and ?=> conversions
> +    #[derive(Debug, Clone, Copy, PartialEq)]
> +    enum MemoryType {
> +        Unmapped = 0,
> +        Normal = 1,
> +        Device = 2,
> +        Reserved = 3,
> +    }
> +
> +    impl TryFrom<Bounded<u64, 4>> for MemoryType {
> +        type Error = u64;
> +        fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> {
> +            match value.get() {
> +                0 => Ok(MemoryType::Unmapped),
> +                1 => Ok(MemoryType::Normal),
> +                2 => Ok(MemoryType::Device),
> +                3 => Ok(MemoryType::Reserved),
> +                _ => Err(value.get()),
> +            }
> +        }
> +    }
> +
> +    impl From<MemoryType> for Bounded<u64, 4> {
> +        fn from(mt: MemoryType) -> Bounded<u64, 4> {
> +            Bounded::from_expr(mt as u64)
> +        }
> +    }
> +
> +    #[derive(Debug, Clone, Copy, PartialEq)]
> +    enum Priority {
> +        Low = 0,
> +        Medium = 1,
> +        High = 2,
> +        Critical = 3,
> +    }
> +
> +    impl From<Bounded<u16, 2>> for Priority {
> +        fn from(value: Bounded<u16, 2>) -> Self {
> +            match value & 0x3 {
> +                0 => Priority::Low,
> +                1 => Priority::Medium,
> +                2 => Priority::High,
> +                _ => Priority::Critical,
> +            }
> +        }
> +    }
> +
> +    impl From<Priority> for Bounded<u16, 2> {
> +        fn from(p: Priority) -> Bounded<u16, 2> {
> +            Bounded::from_expr(p as u16)
> +        }
> +    }
> +
> +    bitfield! {
> +        struct TestPageTableEntry(u64) {
> +            0:0       present;
> +            1:1       writable;
> +            11:9      available;
> +            15:12     mem_type ?=> MemoryType;
> +            51:16     pfn;
> +            61:52     available2;

Nit:

In the first patch you keep the high-to-low order, can you do the same
here:

            61:52     available2;
            51:16     pfn;
            15:12     mem_type ?=> MemoryType;
            ...

> +        }
> +    }
> +
> +    bitfield! {
> +        struct TestControlRegister(u16) {
> +            0:0       enable;
> +            3:1       mode;
> +            5:4       priority => Priority;
> +            7:4       priority_nibble;
> +            15:8      channel;
> +        }
> +    }
> +
> +    bitfield! {
> +        struct TestStatusRegister(u8) {
> +            0:0       ready;
> +            1:1       error;
> +            3:2       state;
> +            7:4       reserved;
> +            7:0       full_byte;  // For entire register
> +        }
> +    }
> +
> +    #[test]
> +    fn test_single_bits() {
> +        let mut pte = TestPageTableEntry::zeroed();
> +
> +        assert!(!pte.present().into_bool());
> +        assert!(!pte.writable().into_bool());
> +        assert_eq!(u64::from(pte), 0x0);
> +
> +        pte = pte.with_present(true);
> +        assert!(pte.present().into_bool());
> +        assert_eq!(u64::from(pte), 0x1);
> +
> +        pte = pte.with_writable(true);
> +        assert!(pte.writable().into_bool());
> +        assert_eq!(u64::from(pte), 0x3);
> +
> +        pte = pte.with_writable(false);
> +        assert!(!pte.writable().into_bool());
> +        assert_eq!(u64::from(pte), 0x1);
> +
> +        assert_eq!(pte.available(), 0);
> +        pte = pte.with_const_available::<0x5>();
> +        assert_eq!(pte.available(), 0x5);
> +        assert_eq!(u64::from(pte), 0xA01);
> +    }
> +
> +    #[test]
> +    fn test_range_fields() {
> +        let mut pte = TestPageTableEntry::zeroed();
> +        assert_eq!(u64::from(pte), 0x0);
> +
> +        pte = pte.with_const_pfn::<0x123456>();
> +        assert_eq!(pte.pfn(), 0x123456);
> +        assert_eq!(u64::from(pte), 0x1234560000);
> +
> +        pte = pte.with_const_available::<0x7>();
> +        assert_eq!(pte.available(), 0x7);
> +        assert_eq!(u64::from(pte), 0x1234560E00);
> +
> +        pte = pte.with_const_available2::<0x3FF>();
> +        assert_eq!(pte.available2(), 0x3FF);
> +        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_0E00u64);
> +
> +        // Test TryFrom with ?=> for MemoryType
> +        pte = pte.with_mem_type(MemoryType::Device);
> +        assert_eq!(pte.mem_type(), Ok(MemoryType::Device));
> +        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_2E00u64);
> +
> +        pte = pte.with_mem_type(MemoryType::Normal);
> +        assert_eq!(pte.mem_type(), Ok(MemoryType::Normal));
> +        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_1E00u64);
> +
> +        // Test all valid values for mem_type
> +        pte = pte.with_mem_type(MemoryType::Reserved);
> +        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
> +        assert_eq!(u64::from(pte), 0x3FF0_0012_3456_3E00u64);
> +
> +        // Test failure case using mem_type field which has 4 bits (0-15)
> +        // MemoryType only handles 0-3, so values 4-15 should return Err
> +        let mut raw = pte.into_raw();
> +        // Set bits 15:12 to 7 (invalid for MemoryType)
> +        raw = (raw & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12);
> +        let invalid_pte = TestPageTableEntry::from_raw(raw);
> +        // Should return Err with the invalid value
> +        assert_eq!(invalid_pte.mem_type(), Err(0x7));
> +
> +        // Test a valid value after testing invalid to ensure both cases work
> +        // Set bits 15:12 to 2 (valid: Device)
> +        raw = (raw & !::kernel::bits::genmask_u64(12..=15)) | (0x2 << 12);
> +        let valid_pte = TestPageTableEntry::from_raw(raw);
> +        assert_eq!(valid_pte.mem_type(), Ok(MemoryType::Device));
> +
> +        const MAX_PFN: u64 = ::kernel::bits::genmask_u64(0..=35);
> +        pte = pte.with_const_pfn::<{ MAX_PFN }>();
> +        assert_eq!(pte.pfn(), MAX_PFN);
> +    }
> +
> +    #[test]
> +    fn test_builder_pattern() {
> +        let pte = TestPageTableEntry::zeroed()
> +            .with_present(true)
> +            .with_writable(true)
> +            .with_const_available::<0x7>()
> +            .with_const_pfn::<0xABCDEF>()
> +            .with_mem_type(MemoryType::Reserved)
> +            .with_const_available2::<0x3FF>();
> +
> +        assert!(pte.present().into_bool());
> +        assert!(pte.writable().into_bool());
> +        assert_eq!(pte.available(), 0x7);
> +        assert_eq!(pte.pfn(), 0xABCDEF);
> +        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
> +        assert_eq!(pte.available2(), 0x3FF);
> +    }
> +
> +    #[test]
> +    fn test_raw_operations() {
> +        let raw_value = 0x3FF0000031233E03u64;
> +
> +        let pte = TestPageTableEntry::from_raw(raw_value);
> +        assert_eq!(u64::from(pte), raw_value);
> +
> +        assert!(pte.present().into_bool());
> +        assert!(pte.writable().into_bool());
> +        assert_eq!(pte.available(), 0x7);
> +        assert_eq!(pte.pfn(), 0x3123);
> +        assert_eq!(pte.mem_type(), Ok(MemoryType::Reserved));
> +        assert_eq!(pte.available2(), 0x3FF);
> +
> +        // Test using direct constructor syntax TestStruct(value)
> +        let pte2 = TestPageTableEntry::from_raw(raw_value);
> +        assert_eq!(u64::from(pte2), raw_value);

So what about bits not belonging to any field, like 8:2 in this case?
Are they RAZ, undef or not touched by any method except the raw
setters?

Can you discuss and add a test for it?

> +    }
> +
> +    #[test]
> +    fn test_u16_bitfield() {
> +        let mut ctrl = TestControlRegister::zeroed();
> +
> +        assert!(!ctrl.enable().into_bool());
> +        assert_eq!(ctrl.mode(), 0);
> +        assert_eq!(ctrl.priority(), Priority::Low);
> +        assert_eq!(ctrl.priority_nibble(), 0);
> +        assert_eq!(ctrl.channel(), 0);
> +
> +        ctrl = ctrl.with_enable(true);
> +        assert!(ctrl.enable().into_bool());
> +
> +        ctrl = ctrl.with_const_mode::<0x5>();
> +        assert_eq!(ctrl.mode(), 0x5);
> +
> +        // Test From conversion with =>
> +        ctrl = ctrl.with_priority(Priority::High);
> +        assert_eq!(ctrl.priority(), Priority::High);
> +        assert_eq!(ctrl.priority_nibble(), 0x2); // High = 2 in bits 5:4
> +
> +        ctrl = ctrl.with_channel(0xAB);
> +        assert_eq!(ctrl.channel(), 0xAB);
> +
> +        // Test overlapping fields
> +        ctrl = ctrl.with_const_priority_nibble::<0xF>();
> +        assert_eq!(ctrl.priority_nibble(), 0xF);
> +        assert_eq!(ctrl.priority(), Priority::Critical); // bits 5:4 = 0x3
> +
> +        let ctrl2 = TestControlRegister::zeroed()
> +            .with_enable(true)
> +            .with_const_mode::<0x3>()
> +            .with_priority(Priority::Medium)
> +            .with_channel(0x42);
> +
> +        assert!(ctrl2.enable().into_bool());
> +        assert_eq!(ctrl2.mode(), 0x3);
> +        assert_eq!(ctrl2.priority(), Priority::Medium);
> +        assert_eq!(ctrl2.channel(), 0x42);
> +
> +        let raw_value: u16 = 0x4217;
> +        let ctrl3 = TestControlRegister::from_raw(raw_value);
> +        assert_eq!(u16::from(ctrl3), raw_value);
> +        assert!(ctrl3.enable().into_bool());
> +        assert_eq!(ctrl3.priority(), Priority::Medium);
> +        assert_eq!(ctrl3.priority_nibble(), 0x1);
> +        assert_eq!(ctrl3.channel(), 0x42);
> +    }
> +
> +    #[test]
> +    fn test_u8_bitfield() {
> +        let mut status = TestStatusRegister::zeroed();
> +
> +        assert!(!status.ready().into_bool());
> +        assert!(!status.error().into_bool());
> +        assert_eq!(status.state(), 0);
> +        assert_eq!(status.reserved(), 0);
> +        assert_eq!(status.full_byte(), 0);
> +
> +        status = status.with_ready(true);
> +        assert!(status.ready().into_bool());
> +        assert_eq!(status.full_byte(), 0x01);
> +
> +        status = status.with_error(true);
> +        assert!(status.error().into_bool());
> +        assert_eq!(status.full_byte(), 0x03);
> +
> +        status = status.with_const_state::<0x3>();
> +        assert_eq!(status.state(), 0x3);
> +        assert_eq!(status.full_byte(), 0x0F);
> +
> +        status = status.with_const_reserved::<0xA>();
> +        assert_eq!(status.reserved(), 0xA);
> +        assert_eq!(status.full_byte(), 0xAF);
> +
> +        // Test overlapping field
> +        status = status.with_full_byte(0x55);
> +        assert_eq!(status.full_byte(), 0x55);
> +        assert!(status.ready().into_bool());
> +        assert!(!status.error().into_bool());
> +        assert_eq!(status.state(), 0x1);
> +        assert_eq!(status.reserved(), 0x5);
> +
> +        let status2 = TestStatusRegister::zeroed()
> +            .with_ready(true)
> +            .with_const_state::<0x2>()
> +            .with_const_reserved::<0x5>();
> +
> +        assert!(status2.ready().into_bool());
> +        assert!(!status2.error().into_bool());
> +        assert_eq!(status2.state(), 0x2);
> +        assert_eq!(status2.reserved(), 0x5);
> +        assert_eq!(status2.full_byte(), 0x59);
> +
> +        let raw_value: u8 = 0x59;
> +        let status3 = TestStatusRegister::from_raw(raw_value);
> +        assert_eq!(u8::from(status3), raw_value);
> +        assert!(status3.ready().into_bool());
> +        assert!(!status3.error().into_bool());
> +        assert_eq!(status3.state(), 0x2);
> +        assert_eq!(status3.reserved(), 0x5);
> +        assert_eq!(status3.full_byte(), 0x59);
> +
> +        let status4 = TestStatusRegister::from_raw(0xFF);
> +        assert!(status4.ready().into_bool());
> +        assert!(status4.error().into_bool());
> +        assert_eq!(status4.state(), 0x3);
> +        assert_eq!(status4.reserved(), 0xF);
> +        assert_eq!(status4.full_byte(), 0xFF);

Does it support signed fields? I recall there was a discussion about it.
If yes, can you add a test? The underlying Bounded does, so I think the
bitfield should do so. Can I save -EFAULT in a 16-bit IMM field? This is
what EX_TYPE_EFAULT_REG does in arch/x86/include/asm/extable_fixup_types.h.

Thanks,
Yury

> +    }
> +}
> 
> -- 
> 2.53.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield
  2026-04-16  2:44   ` Yury Norov
@ 2026-04-16  6:59     ` Alice Ryhl
  2026-04-16 12:48       ` Yury Norov
  0 siblings, 1 reply; 28+ messages in thread
From: Alice Ryhl @ 2026-04-16  6:59 UTC (permalink / raw)
  To: Yury Norov
  Cc: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, Danilo Krummrich, Daniel Almeida,
	David Airlie, Simona Vetter, John Hubbard, Alistair Popple,
	Timur Tabi, Zhi Wang, Eliot Courtney, linux-kernel,
	rust-for-linux, driver-core, dri-devel

On Wed, Apr 15, 2026 at 10:44:01PM -0400, Yury Norov wrote:
> On Thu, Apr 09, 2026 at 11:58:48PM +0900, Alexandre Courbot wrote:
> > From: Joel Fernandes <joelagnelf@nvidia.com>
> > 
> > Add KUNIT tests to make sure the macro is working correctly.
> > 
> > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> > [acourbot: update code to latest bitfield! macro.]
> > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> > ---
> >  rust/kernel/bitfield.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 318 insertions(+)
> > 
> > diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
> > index f5948eec8a76..9ab8dafff36c 100644
> > --- a/rust/kernel/bitfield.rs
> > +++ b/rust/kernel/bitfield.rs
> > @@ -489,3 +489,321 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
> >          }
> >      };
> >  }
> > +
> > +#[::kernel::macros::kunit_tests(kernel_bitfield)]
> 
> Reading the Documentation/rust/testing.rst, and can't understand how
> should one configure it to _not_ build the tests? This should be the
> default behavior.
> 
> There's half a dozen already existing unit tests, and I didn't find
> a mechanism to individually control them.

If you want this set of kunit tests to have its own config option, then
you can declare a Kconfig option for it and do this:

#[cfg(CONFIG_MY_RUST_KCONFIG_OPTION)]
#[kunit_tests(kernel_bitfield)]
mod tests {
    ...
}

Alice

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield
  2026-04-16  6:59     ` Alice Ryhl
@ 2026-04-16 12:48       ` Yury Norov
  0 siblings, 0 replies; 28+ messages in thread
From: Yury Norov @ 2026-04-16 12:48 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, Danilo Krummrich, Daniel Almeida,
	David Airlie, Simona Vetter, John Hubbard, Alistair Popple,
	Timur Tabi, Zhi Wang, Eliot Courtney, linux-kernel,
	rust-for-linux, driver-core, dri-devel

On Thu, Apr 16, 2026 at 06:59:46AM +0000, Alice Ryhl wrote:
> On Wed, Apr 15, 2026 at 10:44:01PM -0400, Yury Norov wrote:
> > On Thu, Apr 09, 2026 at 11:58:48PM +0900, Alexandre Courbot wrote:
> > > From: Joel Fernandes <joelagnelf@nvidia.com>
> > > 
> > > Add KUNIT tests to make sure the macro is working correctly.
> > > 
> > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> > > [acourbot: update code to latest bitfield! macro.]
> > > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> > > ---
> > >  rust/kernel/bitfield.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 318 insertions(+)
> > > 
> > > diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
> > > index f5948eec8a76..9ab8dafff36c 100644
> > > --- a/rust/kernel/bitfield.rs
> > > +++ b/rust/kernel/bitfield.rs
> > > @@ -489,3 +489,321 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
> > >          }
> > >      };
> > >  }
> > > +
> > > +#[::kernel::macros::kunit_tests(kernel_bitfield)]
> > 
> > Reading the Documentation/rust/testing.rst, and can't understand how
> > should one configure it to _not_ build the tests? This should be the
> > default behavior.
> > 
> > There's half a dozen already existing unit tests, and I didn't find
> > a mechanism to individually control them.
> 
> If you want this set of kunit tests to have its own config option, then
> you can declare a Kconfig option for it and do this:
> 
> #[cfg(CONFIG_MY_RUST_KCONFIG_OPTION)]
> #[kunit_tests(kernel_bitfield)]
> mod tests {
>     ...
> }

Thanks, Alce!

I suspected that, but you never know all the rust tricks. :)

Joel, can you do as suggested here, and I can send a patch for the
existing tests, if no objections?

Thanks,
Yury

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-15 23:22 ` [PATCH v2 0/3] rust: add `bitfield!` macro John Hubbard
  2026-04-16  1:08   ` Eliot Courtney
@ 2026-04-16 22:18   ` Danilo Krummrich
  2026-04-16 22:43     ` John Hubbard
                       ` (2 more replies)
  1 sibling, 3 replies; 28+ messages in thread
From: Danilo Krummrich @ 2026-04-16 22:18 UTC (permalink / raw)
  To: John Hubbard
  Cc: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
> Can we please put this into your drm-rust-next-staging ASAP? I don't
> think we have any comments that would really need to hold that up.

I would like to see the first patch being split up and we also need to agree the
merge strategy for this series and obtain the corresponding ACKs first.

That said, I'm not a huge fan of the drm-rust-next-staging thing. It started out
as part of Alex' (private) process of staging patches he's about to pick up
(which is fine of course).

But now it seems to develop into some semi-official "shadow infrastructure" for
when the drm-rust tree is closed after -rc6 and during the merge window, and
it's not part of the official drm-rust workflow and other maintainers don't have
oversight of it.

So, in order to not motivate workarounds, starting from the next cycle, the
drm-rust-next branch will be open for new features at all times.

Consequently, all patches applied to drm-rust-next after -rc6 do not target the
upcoming merge window, but the next one.

Fixes for code that is within drm-rust-next and was merged before -rc6 have to
go into drm-rust-next-fixes.

drm-rust-fixes will continue to be the target for fixes for the current -rc.

I will update all corresponding documentation in the next days and send another
announcement mail, so it is not only this one buried in a thread where no one
expects it. :)

- Danilo

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-16 22:18   ` Danilo Krummrich
@ 2026-04-16 22:43     ` John Hubbard
  2026-04-17  1:33     ` Alexandre Courbot
  2026-04-17  5:55     ` Miguel Ojeda
  2 siblings, 0 replies; 28+ messages in thread
From: John Hubbard @ 2026-04-16 22:43 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Alexandre Courbot, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On 4/16/26 3:18 PM, Danilo Krummrich wrote:
> On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
>> Can we please put this into your drm-rust-next-staging ASAP? I don't
>> think we have any comments that would really need to hold that up.
> 
> I would like to see the first patch being split up and we also need to agree the
> merge strategy for this series and obtain the corresponding ACKs first.
> 
> That said, I'm not a huge fan of the drm-rust-next-staging thing. It started out
> as part of Alex' (private) process of staging patches he's about to pick up
> (which is fine of course).
> 
> But now it seems to develop into some semi-official "shadow infrastructure" for
> when the drm-rust tree is closed after -rc6 and during the merge window, and
> it's not part of the official drm-rust workflow and other maintainers don't have
> oversight of it.

Yes, a patchset vaccuum existed. :)

> 
> So, in order to not motivate workarounds, starting from the next cycle, the
> drm-rust-next branch will be open for new features at all times.
> 
> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
> upcoming merge window, but the next one.
> 
> Fixes for code that is within drm-rust-next and was merged before -rc6 have to
> go into drm-rust-next-fixes.
> 
> drm-rust-fixes will continue to be the target for fixes for the current -rc.
> 

Perfect, that's what we were instintively trying to replicate, after all.

> I will update all corresponding documentation in the next days and send another
> announcement mail, so it is not only this one buried in a thread where no one
> expects it. :)
> 
> - Danilo

thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-16 22:18   ` Danilo Krummrich
  2026-04-16 22:43     ` John Hubbard
@ 2026-04-17  1:33     ` Alexandre Courbot
  2026-04-17  3:11       ` Alexandre Courbot
  2026-04-17  5:55     ` Miguel Ojeda
  2 siblings, 1 reply; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-17  1:33 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: John Hubbard, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Fri Apr 17, 2026 at 7:18 AM JST, Danilo Krummrich wrote:
> On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
>> Can we please put this into your drm-rust-next-staging ASAP? I don't
>> think we have any comments that would really need to hold that up.
>
> I would like to see the first patch being split up and we also need to agree the
> merge strategy for this series and obtain the corresponding ACKs first.
>
> That said, I'm not a huge fan of the drm-rust-next-staging thing. It started out
> as part of Alex' (private) process of staging patches he's about to pick up
> (which is fine of course).

Yeah, if we added this patch it would then become a mix of "things to
push when drm-rust-next" reopens, and "things NVIDIA depends on but are
not ready yet". For the record I was a bit slow to reply but would have
suggested carrying this patch outside of `drm-rust-next-staging` to not
mix things up.

>
> But now it seems to develop into some semi-official "shadow infrastructure" for
> when the drm-rust tree is closed after -rc6 and during the merge window, and
> it's not part of the official drm-rust workflow and other maintainers don't have
> oversight of it.
>
> So, in order to not motivate workarounds, starting from the next cycle, the
> drm-rust-next branch will be open for new features at all times.
>
> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
> upcoming merge window, but the next one.

If that doesn't add any burden to you and Alice, then I think that's a
definitely an improvement to our process.

>
> Fixes for code that is within drm-rust-next and was merged before -rc6 have to
> go into drm-rust-next-fixes.
>
> drm-rust-fixes will continue to be the target for fixes for the current -rc.
>
> I will update all corresponding documentation in the next days and send another
> announcement mail, so it is not only this one buried in a thread where no one
> expects it. :)

Appreciate it! Thanks for doing this.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  1:33     ` Alexandre Courbot
@ 2026-04-17  3:11       ` Alexandre Courbot
  2026-04-17  3:19         ` John Hubbard
  0 siblings, 1 reply; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-17  3:11 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: John Hubbard, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Fri Apr 17, 2026 at 10:33 AM JST, Alexandre Courbot wrote:
> On Fri Apr 17, 2026 at 7:18 AM JST, Danilo Krummrich wrote:
>> On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
>>> Can we please put this into your drm-rust-next-staging ASAP? I don't
>>> think we have any comments that would really need to hold that up.
>>
>> I would like to see the first patch being split up and we also need to agree the
>> merge strategy for this series and obtain the corresponding ACKs first.
>>
>> That said, I'm not a huge fan of the drm-rust-next-staging thing. It started out
>> as part of Alex' (private) process of staging patches he's about to pick up
>> (which is fine of course).
>
> Yeah, if we added this patch it would then become a mix of "things to
> push when drm-rust-next" reopens, and "things NVIDIA depends on but are
> not ready yet". For the record I was a bit slow to reply but would have
> suggested carrying this patch outside of `drm-rust-next-staging` to not
> mix things up.
>
>>
>> But now it seems to develop into some semi-official "shadow infrastructure" for
>> when the drm-rust tree is closed after -rc6 and during the merge window, and
>> it's not part of the official drm-rust workflow and other maintainers don't have
>> oversight of it.
>>
>> So, in order to not motivate workarounds, starting from the next cycle, the
>> drm-rust-next branch will be open for new features at all times.
>>
>> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
>> upcoming merge window, but the next one.
>
> If that doesn't add any burden to you and Alice, then I think that's a
> definitely an improvement to our process.

Actually thinking more about this, this might not be the improvement I
expected at first.

Take for instance the current time of the merge window: both `rust-next`
and `drm-rust-next` have been merged into `master`, which provides us an
ideal base for sending patches that will target `-rc1`.

But if we keep submitting to the pre-merge `drm-rust-next`, then we are
in a situation where the extra patches sent to `drm-rust-next` need to
be rebased when `-rc1` is released, with a clear potential for
conflicts.

So at the end of the day, it would still be cleaner to use `master` in
prevision of the `-rc1` tagging and we would be in more or less the same
situation as today. `drm-rust-next-staging` is currently based on
`master`.

I guess the problem is that my internal process has leaked a bit, when
it is really intended to be a temporary convenience (both for me and for
NVIDIA contributors) and something drm-rust maintainers can completely
ignore.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  3:11       ` Alexandre Courbot
@ 2026-04-17  3:19         ` John Hubbard
  2026-04-17  3:57           ` Alexandre Courbot
  0 siblings, 1 reply; 28+ messages in thread
From: John Hubbard @ 2026-04-17  3:19 UTC (permalink / raw)
  To: Alexandre Courbot, Danilo Krummrich
  Cc: Joel Fernandes, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, David Airlie, Simona Vetter,
	Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On 4/16/26 8:11 PM, Alexandre Courbot wrote:
> On Fri Apr 17, 2026 at 10:33 AM JST, Alexandre Courbot wrote:
>> On Fri Apr 17, 2026 at 7:18 AM JST, Danilo Krummrich wrote:
>>> On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
>>>> Can we please put this into your drm-rust-next-staging ASAP? I don't
>>>> think we have any comments that would really need to hold that up.
...
>>> But now it seems to develop into some semi-official "shadow infrastructure" for
>>> when the drm-rust tree is closed after -rc6 and during the merge window, and
>>> it's not part of the official drm-rust workflow and other maintainers don't have
>>> oversight of it.
>>>
>>> So, in order to not motivate workarounds, starting from the next cycle, the
>>> drm-rust-next branch will be open for new features at all times.
>>>
>>> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
>>> upcoming merge window, but the next one.
>>
>> If that doesn't add any burden to you and Alice, then I think that's a
>> definitely an improvement to our process.
> 
> Actually thinking more about this, this might not be the improvement I
> expected at first.
> 
> Take for instance the current time of the merge window: both `rust-next`
> and `drm-rust-next` have been merged into `master`, which provides us an
> ideal base for sending patches that will target `-rc1`.
> 
> But if we keep submitting to the pre-merge `drm-rust-next`, then we are
> in a situation where the extra patches sent to `drm-rust-next` need to
> be rebased when `-rc1` is released, with a clear potential for
> conflicts.

Yes, some conflicts, but probably not too bad, due to the much
newer base, right?

> 
> So at the end of the day, it would still be cleaner to use `master` in
> prevision of the `-rc1` tagging and we would be in more or less the same
> situation as today. `drm-rust-next-staging` is currently based on
> `master`.
> 
> I guess the problem is that my internal process has leaked a bit, when
> it is really intended to be a temporary convenience (both for me and for
> NVIDIA contributors) and something drm-rust maintainers can completely
> ignore.

The only reason that it leaked is because there was an underlying unmet
need, to begin with, which is: how to continue developing on some
"appropriate" branch during two weeks (20% of the year) when our main
branch is locked down and stale?

There is a real need to do something.


thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  3:19         ` John Hubbard
@ 2026-04-17  3:57           ` Alexandre Courbot
  2026-04-17  4:15             ` John Hubbard
  0 siblings, 1 reply; 28+ messages in thread
From: Alexandre Courbot @ 2026-04-17  3:57 UTC (permalink / raw)
  To: John Hubbard
  Cc: Danilo Krummrich, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On Fri Apr 17, 2026 at 12:19 PM JST, John Hubbard wrote:
> On 4/16/26 8:11 PM, Alexandre Courbot wrote:
>> On Fri Apr 17, 2026 at 10:33 AM JST, Alexandre Courbot wrote:
>>> On Fri Apr 17, 2026 at 7:18 AM JST, Danilo Krummrich wrote:
>>>> On Thu Apr 16, 2026 at 1:22 AM CEST, John Hubbard wrote:
>>>>> Can we please put this into your drm-rust-next-staging ASAP? I don't
>>>>> think we have any comments that would really need to hold that up.
> ...
>>>> But now it seems to develop into some semi-official "shadow infrastructure" for
>>>> when the drm-rust tree is closed after -rc6 and during the merge window, and
>>>> it's not part of the official drm-rust workflow and other maintainers don't have
>>>> oversight of it.
>>>>
>>>> So, in order to not motivate workarounds, starting from the next cycle, the
>>>> drm-rust-next branch will be open for new features at all times.
>>>>
>>>> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
>>>> upcoming merge window, but the next one.
>>>
>>> If that doesn't add any burden to you and Alice, then I think that's a
>>> definitely an improvement to our process.
>> 
>> Actually thinking more about this, this might not be the improvement I
>> expected at first.
>> 
>> Take for instance the current time of the merge window: both `rust-next`
>> and `drm-rust-next` have been merged into `master`, which provides us an
>> ideal base for sending patches that will target `-rc1`.
>> 
>> But if we keep submitting to the pre-merge `drm-rust-next`, then we are
>> in a situation where the extra patches sent to `drm-rust-next` need to
>> be rebased when `-rc1` is released, with a clear potential for
>> conflicts.
>
> Yes, some conflicts, but probably not too bad, due to the much
> newer base, right?

Most of the time, hopefully. But that's still labor shifted from us (as
I would address the conflicts before merging the patches) to the
drm-rust maintainers.

>
>> 
>> So at the end of the day, it would still be cleaner to use `master` in
>> prevision of the `-rc1` tagging and we would be in more or less the same
>> situation as today. `drm-rust-next-staging` is currently based on
>> `master`.
>> 
>> I guess the problem is that my internal process has leaked a bit, when
>> it is really intended to be a temporary convenience (both for me and for
>> NVIDIA contributors) and something drm-rust maintainers can completely
>> ignore.
>
> The only reason that it leaked is because there was an underlying unmet
> need, to begin with, which is: how to continue developing on some
> "appropriate" branch during two weeks (20% of the year) when our main
> branch is locked down and stale?

It's actually 4 weeks (from -rc6 to release, plus 2 weeks until -rc1).

I agree it would be nice to improve the situation - I'm just not sure
that keeping drm-rust-next open is the optimal solution here.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  3:57           ` Alexandre Courbot
@ 2026-04-17  4:15             ` John Hubbard
  0 siblings, 0 replies; 28+ messages in thread
From: John Hubbard @ 2026-04-17  4:15 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Danilo Krummrich, Joel Fernandes, Yury Norov, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	David Airlie, Simona Vetter, Alistair Popple, Timur Tabi,
	Zhi Wang, Eliot Courtney, linux-kernel, rust-for-linux,
	driver-core, dri-devel

On 4/16/26 8:57 PM, Alexandre Courbot wrote:
...
>> Yes, some conflicts, but probably not too bad, due to the much
>> newer base, right?
> 
> Most of the time, hopefully. But that's still labor shifted from us (as
> I would address the conflicts before merging the patches) to the
> drm-rust maintainers.

This point would carry some real weight, were it not for the fact that
one of the drm-rust maintainers is the one who suggested this approach!

Please let's take "yes" for an answer here.

...
> It's actually 4 weeks (from -rc6 to release, plus 2 weeks until -rc1).

I knew it felt longer than 20%. So yes, 40% of the year. This is a real
gap.

> 
> I agree it would be nice to improve the situation - I'm just not sure
> that keeping drm-rust-next open is the optimal solution here.

Me neither, but I'm *very* convinced that it is a solid improvement over
what we have been doing. I really don't see the case against doing this.


thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-16 22:18   ` Danilo Krummrich
  2026-04-16 22:43     ` John Hubbard
  2026-04-17  1:33     ` Alexandre Courbot
@ 2026-04-17  5:55     ` Miguel Ojeda
  2026-04-17 10:59       ` Mark Brown
  2026-04-17 12:00       ` Danilo Krummrich
  2 siblings, 2 replies; 28+ messages in thread
From: Miguel Ojeda @ 2026-04-17  5:55 UTC (permalink / raw)
  To: Danilo Krummrich, Mark Brown
  Cc: John Hubbard, Alexandre Courbot, Joel Fernandes, Yury Norov,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, David Airlie, Simona Vetter, Alistair Popple,
	Timur Tabi, Zhi Wang, Eliot Courtney, linux-kernel,
	rust-for-linux, driver-core, dri-devel

On Fri, Apr 17, 2026 at 12:19 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> But now it seems to develop into some semi-official "shadow infrastructure" for
> when the drm-rust tree is closed after -rc6 and during the merge window, and
> it's not part of the official drm-rust workflow and other maintainers don't have
> oversight of it.
>
> So, in order to not motivate workarounds, starting from the next cycle, the
> drm-rust-next branch will be open for new features at all times.
>
> Consequently, all patches applied to drm-rust-next after -rc6 do not target the
> upcoming merge window, but the next one.

I think that for branches going into linux-next, in general, new
material is not meant to be added until the merge window closes, e.g.
from last -next:

    The merge window is open, so please to not addd any v7.1 material
    to your linux-next included branches until after the merge window closes.

Some things do target future merge windows (e.g. Rust itself was such
a case for a long time), so it may be fine when adding it before the
merge window opens, but I think the idea is mostly to avoid too much
movement during the merge window to avoid interfering with other
maintainers finishing their trees for Linus etc.

But not sure how flexible this is -- Cc'ing Mark.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  5:55     ` Miguel Ojeda
@ 2026-04-17 10:59       ` Mark Brown
  2026-04-17 12:30         ` Danilo Krummrich
  2026-04-17 12:00       ` Danilo Krummrich
  1 sibling, 1 reply; 28+ messages in thread
From: Mark Brown @ 2026-04-17 10:59 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Danilo Krummrich, John Hubbard, Alexandre Courbot, Joel Fernandes,
	Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, David Airlie, Simona Vetter,
	Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

[-- Attachment #1: Type: text/plain, Size: 2041 bytes --]

On Fri, Apr 17, 2026 at 07:55:57AM +0200, Miguel Ojeda wrote:
> On Fri, Apr 17, 2026 at 12:19 AM Danilo Krummrich <dakr@kernel.org> wrote:

> > So, in order to not motivate workarounds, starting from the next cycle, the
> > drm-rust-next branch will be open for new features at all times.

> > Consequently, all patches applied to drm-rust-next after -rc6 do not target the
> > upcoming merge window, but the next one.

> I think that for branches going into linux-next, in general, new
> material is not meant to be added until the merge window closes, e.g.
> from last -next:

>     The merge window is open, so please to not addd any v7.1 material
>     to your linux-next included branches until after the merge window closes.

> Some things do target future merge windows (e.g. Rust itself was such
> a case for a long time), so it may be fine when adding it before the
> merge window opens, but I think the idea is mostly to avoid too much
> movement during the merge window to avoid interfering with other
> maintainers finishing their trees for Linus etc.

> But not sure how flexible this is -- Cc'ing Mark.

Yes, the idea is that at the end of the merge window -next should only
have a few fixes in it since everything should've been sent to Linus.
This also applies to things being added after you've sent your pulls to
the DRM core maintainers, if something isn't going to go in during the
merge window you shouldn't be adding it to -next.  

For the most part nobody's actually checking that other than the reports
I send to Linus highlighting which trees have the most commits in -next
so if you're not disruptive the chances are nobody will notice but you
shouldn't do it.  As Miguel says it's trying to avoid causing issues for
other people, plus the general concept of -next is that it's covering
what's currently scheduled to go into Linus' tree.

Of course, nothing stops you maintaining a branch which isn't in -next
and is open all the time and that won't have any wider impact.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17  5:55     ` Miguel Ojeda
  2026-04-17 10:59       ` Mark Brown
@ 2026-04-17 12:00       ` Danilo Krummrich
  2026-04-17 12:21         ` Miguel Ojeda
  1 sibling, 1 reply; 28+ messages in thread
From: Danilo Krummrich @ 2026-04-17 12:00 UTC (permalink / raw)
  To: Miguel Ojeda, Mark Brown
  Cc: John Hubbard, Alexandre Courbot, Joel Fernandes, Yury Norov,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, David Airlie, Simona Vetter, Alistair Popple,
	Timur Tabi, Zhi Wang, Eliot Courtney, linux-kernel,
	rust-for-linux, driver-core, dri-devel

On Fri Apr 17, 2026 at 7:55 AM CEST, Miguel Ojeda wrote:
> I think that for branches going into linux-next, in general, new
> material is not meant to be added until the merge window closes, e.g.
> from last -next:
>
>     The merge window is open, so please to not addd any v7.1 material
>     to your linux-next included branches until after the merge window closes.
>
> Some things do target future merge windows (e.g. Rust itself was such
> a case for a long time), so it may be fine when adding it before the
> merge window opens, but I think the idea is mostly to avoid too much
> movement during the merge window to avoid interfering with other
> maintainers finishing their trees for Linus etc.
>
> But not sure how flexible this is -- Cc'ing Mark.

This all builds on the assumption that we don't have a process in place that
covers this.

However, all major DRM trees run the above process and handle linux-next in the
following way.

  * -next
        Features; open at all times.

  * -next-fixes
        Fixes for features in -next that have been included before -rc6; active
        between -rc6 and the next -rc1.

  * -fixes
        Fixes targeting the current -rc cycle.

These are mapped to two additional branches that linux-next pulls from:

  * for-linux-next
        Normally points to -next. Between -rc6 and -rc1 it switches to
        -next-fixes instead.

  * for-linux-next-fixes
        Always points to -fixes.

The same thing is going to happen for drm-rust tree, once everything is set up.

- Danilo

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17 12:00       ` Danilo Krummrich
@ 2026-04-17 12:21         ` Miguel Ojeda
  2026-04-17 14:59           ` Danilo Krummrich
  0 siblings, 1 reply; 28+ messages in thread
From: Miguel Ojeda @ 2026-04-17 12:21 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Mark Brown, John Hubbard, Alexandre Courbot, Joel Fernandes,
	Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, David Airlie, Simona Vetter,
	Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On Fri, Apr 17, 2026 at 2:00 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> This all builds on the assumption that we don't have a process in place that
> covers this.

It builds on what happens today. From what I saw, Mark merges
`drm-rust-next`, which is why I mentioned it, i.e. to help prevent
something unexpected around `linux-next`.

If the branches going into `linux-next` change, then great!

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17 10:59       ` Mark Brown
@ 2026-04-17 12:30         ` Danilo Krummrich
  0 siblings, 0 replies; 28+ messages in thread
From: Danilo Krummrich @ 2026-04-17 12:30 UTC (permalink / raw)
  To: Mark Brown
  Cc: Miguel Ojeda, John Hubbard, Alexandre Courbot, Joel Fernandes,
	Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, David Airlie, Simona Vetter,
	Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On Fri Apr 17, 2026 at 12:59 PM CEST, Mark Brown wrote:
> Of course, nothing stops you maintaining a branch which isn't in -next
> and is open all the time and that won't have any wider impact.

This is exactly what's going to happen, please see [1].

Thanks,
Danilo

[1] https://lore.kernel.org/lkml/DHVEWDBHYKQF.XBXZ704CMXCF@kernel.org/

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/3] rust: add `bitfield!` macro
  2026-04-17 12:21         ` Miguel Ojeda
@ 2026-04-17 14:59           ` Danilo Krummrich
  0 siblings, 0 replies; 28+ messages in thread
From: Danilo Krummrich @ 2026-04-17 14:59 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Mark Brown, John Hubbard, Alexandre Courbot, Joel Fernandes,
	Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, David Airlie, Simona Vetter,
	Alistair Popple, Timur Tabi, Zhi Wang, Eliot Courtney,
	linux-kernel, rust-for-linux, driver-core, dri-devel

On Fri Apr 17, 2026 at 2:21 PM CEST, Miguel Ojeda wrote:
> On Fri, Apr 17, 2026 at 2:00 PM Danilo Krummrich <dakr@kernel.org> wrote:
>>
>> This all builds on the assumption that we don't have a process in place that
>> covers this.
>
> It builds on what happens today. From what I saw, Mark merges
> `drm-rust-next`, which is why I mentioned it, i.e. to help prevent
> something unexpected around `linux-next`.

We're not running the new process yet, so the current state isn't relevant. The
for-linux-next handling will be in place before anything changes for Mark.

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-04-17 14:59 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
2026-04-13  2:29   ` Eliot Courtney
2026-04-15 23:18     ` John Hubbard
2026-04-16  1:35   ` Yury Norov
2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
2026-04-13  2:28   ` Eliot Courtney
2026-04-16  2:44   ` Yury Norov
2026-04-16  6:59     ` Alice Ryhl
2026-04-16 12:48       ` Yury Norov
2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
2026-04-13  2:01   ` Eliot Courtney
2026-04-15 23:20   ` John Hubbard
2026-04-15 23:22 ` [PATCH v2 0/3] rust: add `bitfield!` macro John Hubbard
2026-04-16  1:08   ` Eliot Courtney
2026-04-16 22:18   ` Danilo Krummrich
2026-04-16 22:43     ` John Hubbard
2026-04-17  1:33     ` Alexandre Courbot
2026-04-17  3:11       ` Alexandre Courbot
2026-04-17  3:19         ` John Hubbard
2026-04-17  3:57           ` Alexandre Courbot
2026-04-17  4:15             ` John Hubbard
2026-04-17  5:55     ` Miguel Ojeda
2026-04-17 10:59       ` Mark Brown
2026-04-17 12:30         ` Danilo Krummrich
2026-04-17 12:00       ` Danilo Krummrich
2026-04-17 12:21         ` Miguel Ojeda
2026-04-17 14:59           ` Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox