[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250824135954.2243774-1-joelagnelf@nvidia.com>
Date: Sun, 24 Aug 2025 09:59:52 -0400
From: Joel Fernandes <joelagnelf@...dia.com>
To: linux-kernel@...r.kernel.org,
Danilo Krummrich <dakr@...nel.org>,
Alexandre Courbot <acourbot@...dia.com>,
David Airlie <airlied@...il.com>,
Simona Vetter <simona@...ll.ch>,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>
Cc: John Hubbard <jhubbard@...dia.com>,
Alistair Popple <apopple@...dia.com>,
Joel Fernandes <joelagnelf@...dia.com>,
nouveau@...ts.freedesktop.org,
dri-devel@...ts.freedesktop.org,
rust-for-linux@...r.kernel.org
Subject: [PATCH 1/2] nova-core: Add a library for bitfields in Rust structs
Add a minimal bitfield library for defining in Rust structures (called
bitstruct), similar in concept to bit fields in C structs. This will be used
for defining page table entries and other structures in nova-core.
Signed-off-by: Joel Fernandes <joelagnelf@...dia.com>
---
drivers/gpu/nova-core/bitstruct.rs | 149 +++++++++++++++++++++++++++++
drivers/gpu/nova-core/nova_core.rs | 1 +
2 files changed, 150 insertions(+)
create mode 100644 drivers/gpu/nova-core/bitstruct.rs
diff --git a/drivers/gpu/nova-core/bitstruct.rs b/drivers/gpu/nova-core/bitstruct.rs
new file mode 100644
index 000000000000..661a75da0a9c
--- /dev/null
+++ b/drivers/gpu/nova-core/bitstruct.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// bitstruct.rs — C-style library for bitfield-packed Rust structures
+//
+// A library that provides support for defining bit fields in Rust
+// structures to circumvent lack of native language support for this.
+//
+// Similar usage syntax to the register! macro.
+
+use kernel::prelude::*;
+
+/// Macro for defining bitfield-packed structures in Rust.
+/// The size of the underlying storage type is specified with #[repr(TYPE)].
+///
+/// # Example (just for illustration)
+/// ```rust
+/// bitstruct! {
+/// #[repr(u64)]
+/// pub struct PageTableEntry {
+/// 0:0 present as bool,
+/// 1:1 writable as bool,
+/// 11:9 available as u8,
+/// 51:12 pfn as u64,
+/// 62:52 available2 as u16,
+/// 63:63 nx as bool,
+/// }
+/// }
+/// ```
+///
+/// This generates a struct with methods:
+/// - Constructor: `default()` sets all bits to zero.
+/// - Field accessors: `present()`, `pfn()`, etc.
+/// - Field setters: `set_present()`, `set_pfn()`, etc.
+/// - Builder methods: `with_present()`, `with_pfn()`, etc.
+/// - Raw conversion: `from_raw()`, `into_raw()`
+#[allow(unused_macros)]
+macro_rules! bitstruct {
+ (
+ #[repr($storage:ty)]
+ $vis:vis struct $name:ident {
+ $(
+ $hi:literal : $lo:literal $field:ident as $field_type:tt
+ ),* $(,)?
+ }
+ ) => {
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Default)]
+ $vis struct $name($storage);
+
+ impl $name {
+ /// Create from raw value
+ #[inline(always)]
+ $vis const fn from_raw(val: $storage) -> Self {
+ Self(val)
+ }
+
+ /// Get raw value
+ #[inline(always)]
+ $vis const fn into_raw(self) -> $storage {
+ self.0
+ }
+ }
+
+ impl core::fmt::Debug for $name {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{}({:#x})", stringify!($name), self.0)
+ }
+ }
+
+ // Generate all field methods
+ $(
+ bitstruct_field_impl!($vis, $name, $storage, $hi, $lo, $field as $field_type);
+ )*
+ };
+}
+
+/// Helper to calculate mask for bit fields
+#[allow(unused_macros)]
+macro_rules! bitstruct_mask {
+ ($hi:literal, $lo:literal, $storage:ty) => {{
+ let width = ($hi - $lo + 1) as usize;
+ let storage_bits = 8 * core::mem::size_of::<$storage>();
+ if width >= storage_bits {
+ <$storage>::MAX
+ } else {
+ ((1 as $storage) << width) - 1
+ }
+ }};
+}
+
+#[allow(unused_macros)]
+macro_rules! bitstruct_field_impl {
+ ($vis:vis, $struct_name:ident, $storage:ty, $hi:literal, $lo:literal, $field:ident as $field_type:tt) => {
+ impl $struct_name {
+ #[inline(always)]
+ $vis const fn $field(&self) -> $field_type {
+ let field_val = (self.0 >> $lo) & bitstruct_mask!($hi, $lo, $storage);
+ bitstruct_cast_value!(field_val, $field_type)
+ }
+ }
+ bitstruct_make_setters!($vis, $struct_name, $storage, $hi, $lo, $field, $field_type);
+ };
+}
+
+/// Helper macro to convert extracted value to target type
+///
+/// Special handling for bool types is required because the `as` keyword
+/// cannot be used to convert to bool in Rust. For bool fields, we check
+/// if the extracted value is non-zero. For all other types, we use the
+/// standard `as` conversion.
+#[allow(unused_macros)]
+macro_rules! bitstruct_cast_value {
+ ($field_val:expr, bool) => {
+ $field_val != 0
+ };
+ ($field_val:expr, $field_type:tt) => {
+ $field_val as $field_type
+ };
+}
+
+#[allow(unused_macros)]
+macro_rules! bitstruct_write_bits {
+ ($raw:expr, $hi:literal, $lo:literal, $val:expr, $storage:ty) => {{
+ let mask = bitstruct_mask!($hi, $lo, $storage);
+ ($raw & !(mask << $lo)) | ((($val as $storage) & mask) << $lo)
+ }};
+}
+
+#[allow(unused_macros)]
+macro_rules! bitstruct_make_setters {
+ ($vis:vis, $struct_name:ident, $storage:ty, $hi:literal, $lo:literal, $field:ident, $field_type:tt) => {
+ ::kernel::macros::paste! {
+ impl $struct_name {
+ #[inline(always)]
+ #[allow(dead_code)]
+ $vis fn [<set_ $field>](&mut self, val: $field_type) {
+ self.0 = bitstruct_write_bits!(self.0, $hi, $lo, val, $storage);
+ }
+
+ #[inline(always)]
+ #[allow(dead_code)]
+ $vis const fn [<with_ $field>](mut self, val: $field_type) -> Self {
+ self.0 = bitstruct_write_bits!(self.0, $hi, $lo, val, $storage);
+ self
+ }
+ }
+ }
+ };
+}
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index cb2bbb30cba1..54505cad4a73 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -2,6 +2,7 @@
//! Nova Core GPU Driver
+mod bitstruct;
mod dma;
mod driver;
mod falcon;
--
2.34.1
Powered by blists - more mailing lists