[PATCH v8 00/10] rust: add `register!` macro

Alexandre Courbot posted 10 patches 1 month ago
There is a newer version of this series
drivers/gpu/nova-core/falcon.rs                    |  330 +++---
drivers/gpu/nova-core/falcon/gsp.rs                |   25 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs          |   70 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs          |   12 +-
drivers/gpu/nova-core/falcon/sec2.rs               |   17 +-
drivers/gpu/nova-core/fb.rs                        |    6 +-
drivers/gpu/nova-core/fb/hal/ga100.rs              |   37 +-
drivers/gpu/nova-core/fb/hal/ga102.rs              |    7 +-
drivers/gpu/nova-core/fb/hal/tu102.rs              |   17 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   16 +-
drivers/gpu/nova-core/gfw.rs                       |   11 +-
drivers/gpu/nova-core/gpu.rs                       |   36 +-
drivers/gpu/nova-core/gsp/boot.rs                  |   11 +-
drivers/gpu/nova-core/gsp/cmdq.rs                  |    9 +-
drivers/gpu/nova-core/regs.rs                      |  612 +++++-----
drivers/gpu/nova-core/regs/macros.rs               |  739 ------------
rust/kernel/io.rs                                  |  391 +++++--
rust/kernel/io/register.rs                         | 1190 ++++++++++++++++++++
rust/kernel/lib.rs                                 |    3 +
rust/kernel/num/bounded.rs                         |   70 +-
samples/rust/rust_driver_pci.rs                    |   84 +-
scripts/Makefile.build                             |    3 +-
22 files changed, 2319 insertions(+), 1377 deletions(-)
[PATCH v8 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 1 month ago
Another revision, another redesign.

This one eschews closures completely for write operations, and defaults
to a two-argument `write` method backed by a single-argument `write_val`
one to avoid register name repetition. The two-argument version can now
be used in most cases thanks to a clever use of traits (thanks Gary!).

We went from this syntax:

  bar.write_with(regs::NV_PFALCON_FALCON_DMATRFFBOFFS::of::<E>(), |r| {
      r.with_offs(src_start + pos)
  });

to this one:

  bar.write(
      WithBase::of::<E>(),
      regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
  );

While slightly more verbose, it is also much easier to read, as the
location and value are properly formatted into their own line, and the
confusing closure syntax is gone. Getting rid of closures also allows
any register value constructor to be used, not just a set of fixed ones.
The supporting code in the register module also doesn't spill on `io` at
all.

This design also trims more generated code from the register macro:
almost everything is provided through traits and generic code, and the
macro only implements the traits relevant to the register type (while
also embedding the bitfield feature which will eventually move to its
own macro).

The `register` macro documentation and top patch should give a good idea
of how this is used.

This revision is based on `driver-core-next` as of 2026-03-09. The top
patch also depends on `drm-rust-next`, but it is only here to illustrate
how client code looks like.

A tree with this series and its dependencies is available at [1].

[1] https://github.com/Gnurou/linux/tree/b4/register

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>

---
Changes in v8:
- Use two-arguments `Io::write` with a convenience single-argument
  `Io::write_val`.
- Remove the `IoWrite` type, all helper methods of `IoLoc`, and stop
  relying on closures to write values.
- Add traits for specifying relative and array register locations.
- Improved documentation and examples.
- Link to v7: https://patch.msgid.link/20260224-register-v7-0-aad44f760f33@nvidia.com

Changes in v7:
- Use `RES + SHIFT >= N` instead of `RES >= N - SHIFT` in
  `Bounded::shr`.
- Rename `IoRef` to `IoLoc` and all related types
  accordingly.
- Use `Into` trait bounds in both directions on `IoLoc`.
- Add RFC patch allowing fixed register values to be used directly with
  `write`.
- Link to v6: https://patch.msgid.link/20260216-register-v6-0-eec9a4de9e9e@nvidia.com

Changes in v6:
- Remove Tested-by tags as the code has considerably changed.
- Make `Bounded::get` const so it can be used with registers.
- Use the `pin_init::zeroed()` const function instead of defining our
  own method.
- Generalize all `Io` around the new `IoRef` and `IoWrite` types, and
  make registers use these as well.
- Use the more natural pattern of having the `Io` type perform the I/O
  access instead of the register type.
- Convert the whole PCI driver example, and not only the PCI
  configuration space.
- Rename `Bounded::as_bool` to `Bounded::into_bool`.
- Drop `Bounded::into_inner` in favor of making `Bounded::get` const.
- Link to v5: https://patch.msgid.link/20260129-register-v5-0-c4587c902514@nvidia.com

Changes in v5:
- Rename all setters to `with_*` and `with_const_*`.
- Use `, stride = ` to specify the stride of register arrays.
- Remove `Deref` requirement on the `RegisterIo` trait and make it
  `#[doc(hidden)`.
- Simplify the top dispatch rule a bit.
- Link to v4: https://patch.msgid.link/20260128-register-v4-0-aee3a33d9649@nvidia.com

Changes in v4:
- Add `with_` const field setter methods (removing the need to call
  `Bounded::new` for constant field values).
- Add `into_inner` const method for `Bounded`.
- Add `from_raw` and const `zeroed` method to create initial register
  values.
- More documentation improvements.
- Link to v3: https://patch.msgid.link/20260126-register-v3-0-2328a59d7312@nvidia.com

Changes in v3:
- Sort the Rust features list alphabetically.
- Rebase on top of latest `driver-core-next` including the new Io trait.
- Allow several registers to be defined from the same macro invocation.
- Remove references to `bitfield!` macro.
- Fix doccomment of `shr` and `shl`.
- Use `+` syntax for relative register offsets.
- Move register arrays size and stride to after the backing type declaration.
- Use regular doccomments to document registers and fields (thanks Gary!).
- Remove `Default` implementation and implement the more predictable
  `Zeroable` instead.
- Improve doccomments a bit.
- Link to v2: https://patch.msgid.link/20260121-register-v2-0-79d9b8d5e36a@nvidia.com

Changes in v2:
- Remove `bitfield!` and put its rules into `register!` to give it more
  time to get reviewed.
- Allow output type larger than strictly required for `shr` and `shl` on
  `Bounded`.
- Enable the `generic_arg_infer` feature, required for rustc < 1.89.
- Link to v1: https://patch.msgid.link/20260120-register-v1-0-723a1743b557@nvidia.com

---
Alexandre Courbot (10):
      rust: enable the `generic_arg_infer` feature
      rust: num: add `shr` and `shl` methods to `Bounded`
      rust: num: add `into_bool` method to `Bounded`
      rust: num: make Bounded::get const
      rust: io: add IoLoc type and generic I/O accessors
      rust: io: use generic read/write accessors for primitive accesses
      rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
      rust: io: add `register!` macro
      sample: rust: pci: use `register!` macro
      [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro

 drivers/gpu/nova-core/falcon.rs                    |  330 +++---
 drivers/gpu/nova-core/falcon/gsp.rs                |   25 +-
 drivers/gpu/nova-core/falcon/hal/ga102.rs          |   70 +-
 drivers/gpu/nova-core/falcon/hal/tu102.rs          |   12 +-
 drivers/gpu/nova-core/falcon/sec2.rs               |   17 +-
 drivers/gpu/nova-core/fb.rs                        |    6 +-
 drivers/gpu/nova-core/fb/hal/ga100.rs              |   37 +-
 drivers/gpu/nova-core/fb/hal/ga102.rs              |    7 +-
 drivers/gpu/nova-core/fb/hal/tu102.rs              |   17 +-
 drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   16 +-
 drivers/gpu/nova-core/gfw.rs                       |   11 +-
 drivers/gpu/nova-core/gpu.rs                       |   36 +-
 drivers/gpu/nova-core/gsp/boot.rs                  |   11 +-
 drivers/gpu/nova-core/gsp/cmdq.rs                  |    9 +-
 drivers/gpu/nova-core/regs.rs                      |  612 +++++-----
 drivers/gpu/nova-core/regs/macros.rs               |  739 ------------
 rust/kernel/io.rs                                  |  391 +++++--
 rust/kernel/io/register.rs                         | 1190 ++++++++++++++++++++
 rust/kernel/lib.rs                                 |    3 +
 rust/kernel/num/bounded.rs                         |   70 +-
 samples/rust/rust_driver_pci.rs                    |   84 +-
 scripts/Makefile.build                             |    3 +-
 22 files changed, 2319 insertions(+), 1377 deletions(-)
---
base-commit: a985880eb0f73b0d497d30dcce73e537f787b6c0
change-id: 20260117-register-ccaba1d21713

Best regards,
-- 
Alexandre Courbot <acourbot@nvidia.com>
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Danilo Krummrich 4 weeks, 1 day ago
On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
> Alexandre Courbot (10):
>       rust: enable the `generic_arg_infer` feature
>       rust: num: add `shr` and `shl` methods to `Bounded`
>       rust: num: add `into_bool` method to `Bounded`
>       rust: num: make Bounded::get const
>       rust: io: add IoLoc type and generic I/O accessors
>       rust: io: use generic read/write accessors for primitive accesses
>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>       rust: io: add `register!` macro
>       sample: rust: pci: use `register!` macro
>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro

I did not look into the root cause, but fetching this patch series my build
fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
enabled?
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 4 weeks ago
On Wed Mar 11, 2026 at 2:20 AM JST, Danilo Krummrich wrote:
> On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
>> Alexandre Courbot (10):
>>       rust: enable the `generic_arg_infer` feature
>>       rust: num: add `shr` and `shl` methods to `Bounded`
>>       rust: num: add `into_bool` method to `Bounded`
>>       rust: num: make Bounded::get const
>>       rust: io: add IoLoc type and generic I/O accessors
>>       rust: io: use generic read/write accessors for primitive accesses
>>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>>       rust: io: add `register!` macro
>>       sample: rust: pci: use `register!` macro
>>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>
> I did not look into the root cause, but fetching this patch series my build
> fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
> enabled?

Nope, it is disabled and I build with Clippy so I am surprised you are
getting this. Do you know which module is failing?
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Danilo Krummrich 4 weeks ago
On Wed Mar 11, 2026 at 2:01 PM CET, Alexandre Courbot wrote:
> On Wed Mar 11, 2026 at 2:20 AM JST, Danilo Krummrich wrote:
>> On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
>>> Alexandre Courbot (10):
>>>       rust: enable the `generic_arg_infer` feature
>>>       rust: num: add `shr` and `shl` methods to `Bounded`
>>>       rust: num: add `into_bool` method to `Bounded`
>>>       rust: num: make Bounded::get const
>>>       rust: io: add IoLoc type and generic I/O accessors
>>>       rust: io: use generic read/write accessors for primitive accesses
>>>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>>>       rust: io: add `register!` macro
>>>       sample: rust: pci: use `register!` macro
>>>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>
>> I did not look into the root cause, but fetching this patch series my build
>> fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
>> enabled?
>
> Nope, it is disabled and I build with Clippy so I am surprised you are
> getting this. Do you know which module is failing?

ERROR: modpost: "rust_build_error" [drivers/gpu/nova-core/nova_core.ko] undefined!
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 4 weeks ago
On Wed Mar 11, 2026 at 10:07 PM JST, Danilo Krummrich wrote:
> On Wed Mar 11, 2026 at 2:01 PM CET, Alexandre Courbot wrote:
>> On Wed Mar 11, 2026 at 2:20 AM JST, Danilo Krummrich wrote:
>>> On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
>>>> Alexandre Courbot (10):
>>>>       rust: enable the `generic_arg_infer` feature
>>>>       rust: num: add `shr` and `shl` methods to `Bounded`
>>>>       rust: num: add `into_bool` method to `Bounded`
>>>>       rust: num: make Bounded::get const
>>>>       rust: io: add IoLoc type and generic I/O accessors
>>>>       rust: io: use generic read/write accessors for primitive accesses
>>>>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>>>>       rust: io: add `register!` macro
>>>>       sample: rust: pci: use `register!` macro
>>>>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>>
>>> I did not look into the root cause, but fetching this patch series my build
>>> fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
>>> enabled?
>>
>> Nope, it is disabled and I build with Clippy so I am surprised you are
>> getting this. Do you know which module is failing?
>
> ERROR: modpost: "rust_build_error" [drivers/gpu/nova-core/nova_core.ko] undefined!

Does it happen with the exact branch I posted?

https://github.com/Gnurou/linux/tree/b4/register

This one builds fine for me.

Gary also pointed out a few missing `inlines` that could potentially
trigger that kind of error. But I'd be curious to try and reproduce
myself if you can post your tree somewhere.
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Danilo Krummrich 4 weeks ago
On Wed Mar 11, 2026 at 2:35 PM CET, Alexandre Courbot wrote:
> On Wed Mar 11, 2026 at 10:07 PM JST, Danilo Krummrich wrote:
>> On Wed Mar 11, 2026 at 2:01 PM CET, Alexandre Courbot wrote:
>>> On Wed Mar 11, 2026 at 2:20 AM JST, Danilo Krummrich wrote:
>>>> On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
>>>>> Alexandre Courbot (10):
>>>>>       rust: enable the `generic_arg_infer` feature
>>>>>       rust: num: add `shr` and `shl` methods to `Bounded`
>>>>>       rust: num: add `into_bool` method to `Bounded`
>>>>>       rust: num: make Bounded::get const
>>>>>       rust: io: add IoLoc type and generic I/O accessors
>>>>>       rust: io: use generic read/write accessors for primitive accesses
>>>>>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>>>>>       rust: io: add `register!` macro
>>>>>       sample: rust: pci: use `register!` macro
>>>>>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>>>
>>>> I did not look into the root cause, but fetching this patch series my build
>>>> fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
>>>> enabled?
>>>
>>> Nope, it is disabled and I build with Clippy so I am surprised you are
>>> getting this. Do you know which module is failing?
>>
>> ERROR: modpost: "rust_build_error" [drivers/gpu/nova-core/nova_core.ko] undefined!
>
> Does it happen with the exact branch I posted?

Yup, my HEAD is at commit 5c558172827e ("[FOR REFERENCE] gpu: nova-core: use the
kernel `register!` macro").
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 4 weeks ago
On Wed Mar 11, 2026 at 10:38 PM JST, Danilo Krummrich wrote:
> On Wed Mar 11, 2026 at 2:35 PM CET, Alexandre Courbot wrote:
>> On Wed Mar 11, 2026 at 10:07 PM JST, Danilo Krummrich wrote:
>>> On Wed Mar 11, 2026 at 2:01 PM CET, Alexandre Courbot wrote:
>>>> On Wed Mar 11, 2026 at 2:20 AM JST, Danilo Krummrich wrote:
>>>>> On Mon Mar 9, 2026 at 4:13 PM CET, Alexandre Courbot wrote:
>>>>>> Alexandre Courbot (10):
>>>>>>       rust: enable the `generic_arg_infer` feature
>>>>>>       rust: num: add `shr` and `shl` methods to `Bounded`
>>>>>>       rust: num: add `into_bool` method to `Bounded`
>>>>>>       rust: num: make Bounded::get const
>>>>>>       rust: io: add IoLoc type and generic I/O accessors
>>>>>>       rust: io: use generic read/write accessors for primitive accesses
>>>>>>       rust: io: introduce `IntoIoVal` trait and single-argument `write_val`
>>>>>>       rust: io: add `register!` macro
>>>>>>       sample: rust: pci: use `register!` macro
>>>>>>       [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>>>>
>>>>> I did not look into the root cause, but fetching this patch series my build
>>>>> fails due to a build_assert!(). Maybe you have CONFIG_RUST_BUILD_ASSERT_ALLOW
>>>>> enabled?
>>>>
>>>> Nope, it is disabled and I build with Clippy so I am surprised you are
>>>> getting this. Do you know which module is failing?
>>>
>>> ERROR: modpost: "rust_build_error" [drivers/gpu/nova-core/nova_core.ko] undefined!
>>
>> Does it happen with the exact branch I posted?
>
> Yup, my HEAD is at commit 5c558172827e ("[FOR REFERENCE] gpu: nova-core: use the
> kernel `register!` macro").

I did a mistake when updating the nova-core code - changed a
dynamically-checked index into a static one, and since it could not be
proven at build-time it failed. Working as intended, apart from the too
cryptic error message.

For the record, here is the fix:

--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -291,14 +291,15 @@ pub(crate) fn run(
             .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;

         // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory.
-        bar.try_update(
+        bar.update(
             regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
-                .at(usize::from_safe_cast(self.dmem_desc.ctx_dma)),
+                .try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma))
+                .ok_or(EINVAL)?,
             |v| {
                 v.with_target(FalconFbifTarget::CoherentSysmem)
                     .with_mem_type(FalconFbifMemType::Physical)
             },
-        )?;
+        );

         let (mbox0, _) = falcon
             .boot(bar, Some(0), None)
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by Daniel Almeida 1 month ago
Hi Alex,

We will test that on Tyr shortly. There’s a patch on the list that targeted
an earlier version of the macro. We will rebase it on the current one.

At least you get one more user from the get-go.

— Daniel
Re: [PATCH v8 00/10] rust: add `register!` macro
Posted by John Hubbard 1 month ago
On 3/9/26 8:13 AM, Alexandre Courbot wrote:
> Another revision, another redesign.
> 
> This one eschews closures completely for write operations, and defaults
> to a two-argument `write` method backed by a single-argument `write_val`
> one to avoid register name repetition. The two-argument version can now
> be used in most cases thanks to a clever use of traits (thanks Gary!).
> 
> We went from this syntax:
> 
>   bar.write_with(regs::NV_PFALCON_FALCON_DMATRFFBOFFS::of::<E>(), |r| {
>       r.with_offs(src_start + pos)
>   });
> 
> to this one:
> 
>   bar.write(
>       WithBase::of::<E>(),
>       regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
>   );
> 
> While slightly more verbose, it is also much easier to read, as the

Yes, it is! Let's acknowledge the progress in readability here, even
though we are still working on minor details in the other thread. :)


thanks,
-- 
John Hubbard