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

Alexandre Courbot posted 10 patches 1 month, 3 weeks ago
There is a newer version of this series
drivers/gpu/nova-core/falcon.rs           |  249 +++----
drivers/gpu/nova-core/falcon/gsp.rs       |   23 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs |   65 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs |   11 +-
drivers/gpu/nova-core/falcon/sec2.rs      |   17 +-
drivers/gpu/nova-core/fb.rs               |    6 +-
drivers/gpu/nova-core/fb/hal/ga100.rs     |   40 +-
drivers/gpu/nova-core/fb/hal/ga102.rs     |    7 +-
drivers/gpu/nova-core/fb/hal/tu102.rs     |   22 +-
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         |   10 +-
drivers/gpu/nova-core/regs.rs             |  544 ++++++++------
drivers/gpu/nova-core/regs/macros.rs      |  739 -------------------
rust/kernel/io.rs                         |  347 +++++++--
rust/kernel/io/register.rs                | 1135 +++++++++++++++++++++++++++++
rust/kernel/lib.rs                        |    3 +
rust/kernel/num/bounded.rs                |   70 +-
samples/rust/rust_driver_pci.rs           |   84 ++-
scripts/Makefile.build                    |    3 +-
21 files changed, 2118 insertions(+), 1315 deletions(-)
[PATCH v7 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 1 month, 3 weeks ago
New revision addressing the v6 feedback - the use of "location" instead
of "reference" in particular reads well both in the code and the
comments.

As a reminder, since the previous revision we use the I/O type to
perform the actual I/O instead of the register type, which moves us from
this access pattern:

    let boot0 = regs::NV_PMC_BOOT_0::read(bar);

to this arguably more natural one:

    let boot0 = bar.read(regs::NV_PMC_BOOT_0);

This revision is based on `driver-core-testing` as of 2026-02-24 with
[1] applied. A tree with this series and its dependencies is available
at [2].

[1] https://lore.kernel.org/all/20260206-io-v2-0-71dea20a06e6@nvidia.com/
[2] https://github.com/Gnurou/linux/tree/b4/register

The first patch enables the `generic_arg_infer` feature, which is
required for generic type inference and used in subsequent patches. This
feature is stable since rustc 1.89.

The second patch adds `shr` and `shl` methods to `Bounded`. These were
suggested by Alice during LPC as a way to avoid the use of the
controversial `Bounded::from_expr` in both the bitfield macro and the
Nova code. The third patch adds another convenience method to obtain a
`bool` from single-bit `Bounded`s, while the fourth patch turns
`Bounded::get` into a const method in order to make register setter
methods const.

Patches 5 and 6 introduce the `IoLoc` and `IoWrite` types around which
I/O accesses are centered. This allows registers to be accessed using
the same `read` and `write` methods as primitive types.

Patch 7 adds the `register!` macro and the types it requires.

Patch 8 updates the Rust PCI sample driver to use `register!`, as per
its TODO item.

Patch 9 illustrates more extensively how this macro is used by
converting nova-core to use it, and removing the local implementation.
This patch is to be merged one cycle after the other patches.

Patch 10 is an RFC allowing a shorter write syntax to be used in the
case of fixed or relative registers. It doesn't need to be merged
immediately, but I think it is a good time to discuss it.

I have also removed Gary's signoff on patches 5 and 7 to make sure it
doesn't get merged before he gives it explicitly.

Signed-off-by: Alexandre Courbot <acourbot@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 and IoWrite types
      rust: io: use generic read/write accessors for primitive accesses
      rust: io: add `register!` macro
      sample: rust: pci: use `register!` macro
      [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
      RFC: rust: io: allow fixed register values directly in `write`

 drivers/gpu/nova-core/falcon.rs           |  249 +++----
 drivers/gpu/nova-core/falcon/gsp.rs       |   23 +-
 drivers/gpu/nova-core/falcon/hal/ga102.rs |   65 +-
 drivers/gpu/nova-core/falcon/hal/tu102.rs |   11 +-
 drivers/gpu/nova-core/falcon/sec2.rs      |   17 +-
 drivers/gpu/nova-core/fb.rs               |    6 +-
 drivers/gpu/nova-core/fb/hal/ga100.rs     |   40 +-
 drivers/gpu/nova-core/fb/hal/ga102.rs     |    7 +-
 drivers/gpu/nova-core/fb/hal/tu102.rs     |   22 +-
 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         |   10 +-
 drivers/gpu/nova-core/regs.rs             |  544 ++++++++------
 drivers/gpu/nova-core/regs/macros.rs      |  739 -------------------
 rust/kernel/io.rs                         |  347 +++++++--
 rust/kernel/io/register.rs                | 1135 +++++++++++++++++++++++++++++
 rust/kernel/lib.rs                        |    3 +
 rust/kernel/num/bounded.rs                |   70 +-
 samples/rust/rust_driver_pci.rs           |   84 ++-
 scripts/Makefile.build                    |    3 +-
 21 files changed, 2118 insertions(+), 1315 deletions(-)
---
base-commit: 545225ee0b0b6998c7b6ff888f8497681b8b35c4
change-id: 20260117-register-ccaba1d21713

Best regards,
-- 
Alexandre Courbot <acourbot@nvidia.com>
Re: [PATCH v7 00/10] rust: add `register!` macro
Posted by Dirk Behme 1 month, 2 weeks ago
On 24.02.2026 15:21, Alexandre Courbot wrote:
> New revision addressing the v6 feedback - the use of "location" instead
> of "reference" in particular reads well both in the code and the
> comments.
> 
> As a reminder, since the previous revision we use the I/O type to
> perform the actual I/O instead of the register type, which moves us from
> this access pattern:
> 
>      let boot0 = regs::NV_PMC_BOOT_0::read(bar);
> 
> to this arguably more natural one:
> 
>      let boot0 = bar.read(regs::NV_PMC_BOOT_0);
> 
> This revision is based on `driver-core-testing` as of 2026-02-24 with
> [1] applied. A tree with this series and its dependencies is available
> at [2].
> 
> [1] https://lore.kernel.org/all/20260206-io-v2-0-71dea20a06e6@nvidia.com/
> [2] https://github.com/Gnurou/linux/tree/b4/register
> 
> The first patch enables the `generic_arg_infer` feature, which is
> required for generic type inference and used in subsequent patches. This
> feature is stable since rustc 1.89.
> 
> The second patch adds `shr` and `shl` methods to `Bounded`. These were
> suggested by Alice during LPC as a way to avoid the use of the
> controversial `Bounded::from_expr` in both the bitfield macro and the
> Nova code. The third patch adds another convenience method to obtain a
> `bool` from single-bit `Bounded`s, while the fourth patch turns
> `Bounded::get` into a const method in order to make register setter
> methods const.
> 
> Patches 5 and 6 introduce the `IoLoc` and `IoWrite` types around which
> I/O accesses are centered. This allows registers to be accessed using
> the same `read` and `write` methods as primitive types.
> 
> Patch 7 adds the `register!` macro and the types it requires.
> 
> Patch 8 updates the Rust PCI sample driver to use `register!`, as per
> its TODO item.
> 
> Patch 9 illustrates more extensively how this macro is used by
> converting nova-core to use it, and removing the local implementation.
> This patch is to be merged one cycle after the other patches.
> 
> Patch 10 is an RFC allowing a shorter write syntax to be used in the
> case of fixed or relative registers. It doesn't need to be merged
> immediately, but I think it is a good time to discuss it.
> 
> I have also removed Gary's signoff on patches 5 and 7 to make sure it
> doesn't get merged before he gives it explicitly.
> 
> Signed-off-by: Alexandre Courbot <acourbot@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 and IoWrite types
>        rust: io: use generic read/write accessors for primitive accesses
>        rust: io: add `register!` macro
>        sample: rust: pci: use `register!` macro
>        [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>        RFC: rust: io: allow fixed register values directly in `write`
> 
>   drivers/gpu/nova-core/falcon.rs           |  249 +++----
>   drivers/gpu/nova-core/falcon/gsp.rs       |   23 +-
>   drivers/gpu/nova-core/falcon/hal/ga102.rs |   65 +-
>   drivers/gpu/nova-core/falcon/hal/tu102.rs |   11 +-
>   drivers/gpu/nova-core/falcon/sec2.rs      |   17 +-
>   drivers/gpu/nova-core/fb.rs               |    6 +-
>   drivers/gpu/nova-core/fb/hal/ga100.rs     |   40 +-
>   drivers/gpu/nova-core/fb/hal/ga102.rs     |    7 +-
>   drivers/gpu/nova-core/fb/hal/tu102.rs     |   22 +-
>   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         |   10 +-
>   drivers/gpu/nova-core/regs.rs             |  544 ++++++++------
>   drivers/gpu/nova-core/regs/macros.rs      |  739 -------------------
>   rust/kernel/io.rs                         |  347 +++++++--
>   rust/kernel/io/register.rs                | 1135 +++++++++++++++++++++++++++++
>   rust/kernel/lib.rs                        |    3 +
>   rust/kernel/num/bounded.rs                |   70 +-
>   samples/rust/rust_driver_pci.rs           |   84 ++-
>   scripts/Makefile.build                    |    3 +-
>   21 files changed, 2118 insertions(+), 1315 deletions(-)
> ---
> base-commit: 545225ee0b0b6998c7b6ff888f8497681b8b35c4
> change-id: 20260117-register-ccaba1d21713


I converted my simple aarch64 TMU timer example [1] over to v7 (many 
thanks helping with that!) and gave it a try: It works like with v2. 
With that:

Tested-by: Dirk Behme <dirk.behme@de.bosch.com>

Thanks

Dirk

[1]

// SPDX-License-Identifier: GPL-2.0

//! Rust Renesas TMU driver.

use kernel::{
     c_str,
     device::{Core, Device, Bound},
     devres::Devres,
     io::{Io, IoCapable, IoKnownSize, mem::IoMem},
     irq::{self, Flags, IrqReturn, Registration},
     of, platform,
     prelude::*,
     register,
     sync::Arc,
     types::ARef,
};

use core::ops::Deref;
use core::sync::atomic::{AtomicU32, Ordering};

struct RenesasTMUDriver {
     pdev: ARef<platform::Device>,
     _registration: Arc<Registration<Data>>,
     _iomem: Arc<Devres<IoMem<TMU_MMIO_SIZE>>>,
}

struct Info;

kernel::of_device_table!(
     OF_TABLE,
     MODULE_OF_TABLE,
     <RenesasTMUDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c_str!("renesas,tmu")), Info)]
);

register! {

TSTR(u8) @ 0x04 {
     2:2    str2;
     1:1    str1;
     0:0    str0;
}

TSTRRAW(u8) => TSTR {
     7:0   value;
}

TCOR(u32) @ 0x08 {
     31:0    tcor;
}

TCNT(u32) @ 0x0C {
     31:0    tcnt;
}

TCR(u16) @ 0x10 {
     9:9    icpf;
     8:8    unf;
     7:6    icpe;
     5:5    unie;
     4:3    ckeg;
     2:0    tpsc;
}

TCRRAW(u16) => TCR {
	    15:0   value;
}
}

impl TCR {
     fn handle_underflow<T>(io: &T)
     where
         T: Io + IoKnownSize + IoCapable<u16>,
	{
	    let tcr: TCR = io.read(TCR);
	    if tcr.unf().into_bool() {
	        io.write(tcr.with_unf(false));
	    }
	}
}

const TMU_MMIO_SIZE: usize = 0x14;

// Data shared between process and IRQ context.
#[pin_data]
struct Data {
     #[pin]
     iomem: Arc<Devres<IoMem<TMU_MMIO_SIZE>>>,
     #[pin]
     irq_count: AtomicU32,
}

impl irq::Handler for Data {
     // Executed in IRQ context.
     fn handle(&self, dev: &Device<Bound>) -> IrqReturn {
         let count = self.irq_count.fetch_add(1, Ordering::Relaxed);
         dev_info!(dev, "Renesas TMU IRQ handler called {} time(s).\n", 
count);

         // Reset the underflow flag
         let io = self.iomem.access(dev).unwrap();
         TCR::handle_underflow(io.deref());

         IrqReturn::Handled
     }
}

impl platform::Driver for RenesasTMUDriver {
     type IdInfo = Info;
     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);

     fn probe(
         pdev: &platform::Device<Core>,
         _info: Option<&Self::IdInfo>,
     ) -> impl PinInit<Self, Error> {
         let dev = pdev.as_ref();

         dev_dbg!(dev, "Probe Rust Renesas TMU driver.\n");

         let request = pdev.io_request_by_index(0).ok_or(EINVAL)?;
         let iomem = 
Arc::pin_init(request.iomap_sized::<TMU_MMIO_SIZE>(), GFP_KERNEL)?;
         let io = iomem.access(dev)?;

         // Set count to 1 minute. Clock is 16.66MHz / 4 = 4.165MHz
         let timeout: u32 = 4165000 * 60; // 1 minute in clock ticks
         io.update(TCOR, |r| r.with_tcor(timeout));
         io.update(TCNT, |r| r.with_tcnt(timeout));

         // Enable underflow interrupt (UNIE, Underflow Interrupt Control)
         io.update(TCR, |r| r.with_unie(true));

         let request = pdev.irq_by_index(0)?;
         dev_info!(dev, "IRQ:  {}\n", request.irq());
         let clone = iomem.clone();
         let handler = try_pin_init!(Data{iomem: clone, irq_count: 
AtomicU32::new(1)});
         let registration = irq::Registration::new(request, 
Flags::SHARED, c_str!("tmu"), handler);
         let registration = Arc::pin_init(registration, GFP_KERNEL)?;

         // Enable TMU
         io.update(TSTR, |r| r.with_str0(true));
         // Read back registers to verify
         dev_info!(dev, "TSTR: 0x{:x}\n", io.read(TSTRRAW).value());
         dev_info!(dev, "TCOR: 0x{:x}\n", io.read(TCOR).tcor());
         dev_info!(dev, "TCNT: 0x{:x}\n", io.read(TCNT).tcnt());
         dev_info!(dev, "TCR:  0x{:x}\n", io.read(TCRRAW).value());

         dev_info!(dev, "probe done\n");

         Ok(Self {
             pdev: pdev.into(),
             _registration: registration,
             _iomem: iomem.clone(),
         })
     }
}

impl Drop for RenesasTMUDriver {
     fn drop(&mut self) {
         dev_dbg!(self.pdev.as_ref(), "Remove Rust Renesas TMU driver.\n");
     }
}

kernel::module_platform_driver! {
     type: RenesasTMUDriver,
     name: "rust_tmu",
     authors: ["Dirk Behme"],
     description: "Rust Renesas TMU driver",
     license: "GPL v2",
}
Re: [PATCH v7 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 1 month, 2 weeks ago
On Wed Feb 25, 2026 at 8:58 PM JST, Dirk Behme wrote:
> On 24.02.2026 15:21, Alexandre Courbot wrote:
>> New revision addressing the v6 feedback - the use of "location" instead
>> of "reference" in particular reads well both in the code and the
>> comments.
>> 
>> As a reminder, since the previous revision we use the I/O type to
>> perform the actual I/O instead of the register type, which moves us from
>> this access pattern:
>> 
>>      let boot0 = regs::NV_PMC_BOOT_0::read(bar);
>> 
>> to this arguably more natural one:
>> 
>>      let boot0 = bar.read(regs::NV_PMC_BOOT_0);
>> 
>> This revision is based on `driver-core-testing` as of 2026-02-24 with
>> [1] applied. A tree with this series and its dependencies is available
>> at [2].
>> 
>> [1] https://lore.kernel.org/all/20260206-io-v2-0-71dea20a06e6@nvidia.com/
>> [2] https://github.com/Gnurou/linux/tree/b4/register
>> 
>> The first patch enables the `generic_arg_infer` feature, which is
>> required for generic type inference and used in subsequent patches. This
>> feature is stable since rustc 1.89.
>> 
>> The second patch adds `shr` and `shl` methods to `Bounded`. These were
>> suggested by Alice during LPC as a way to avoid the use of the
>> controversial `Bounded::from_expr` in both the bitfield macro and the
>> Nova code. The third patch adds another convenience method to obtain a
>> `bool` from single-bit `Bounded`s, while the fourth patch turns
>> `Bounded::get` into a const method in order to make register setter
>> methods const.
>> 
>> Patches 5 and 6 introduce the `IoLoc` and `IoWrite` types around which
>> I/O accesses are centered. This allows registers to be accessed using
>> the same `read` and `write` methods as primitive types.
>> 
>> Patch 7 adds the `register!` macro and the types it requires.
>> 
>> Patch 8 updates the Rust PCI sample driver to use `register!`, as per
>> its TODO item.
>> 
>> Patch 9 illustrates more extensively how this macro is used by
>> converting nova-core to use it, and removing the local implementation.
>> This patch is to be merged one cycle after the other patches.
>> 
>> Patch 10 is an RFC allowing a shorter write syntax to be used in the
>> case of fixed or relative registers. It doesn't need to be merged
>> immediately, but I think it is a good time to discuss it.
>> 
>> I have also removed Gary's signoff on patches 5 and 7 to make sure it
>> doesn't get merged before he gives it explicitly.
>> 
>> Signed-off-by: Alexandre Courbot <acourbot@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 and IoWrite types
>>        rust: io: use generic read/write accessors for primitive accesses
>>        rust: io: add `register!` macro
>>        sample: rust: pci: use `register!` macro
>>        [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>        RFC: rust: io: allow fixed register values directly in `write`
>> 
>>   drivers/gpu/nova-core/falcon.rs           |  249 +++----
>>   drivers/gpu/nova-core/falcon/gsp.rs       |   23 +-
>>   drivers/gpu/nova-core/falcon/hal/ga102.rs |   65 +-
>>   drivers/gpu/nova-core/falcon/hal/tu102.rs |   11 +-
>>   drivers/gpu/nova-core/falcon/sec2.rs      |   17 +-
>>   drivers/gpu/nova-core/fb.rs               |    6 +-
>>   drivers/gpu/nova-core/fb/hal/ga100.rs     |   40 +-
>>   drivers/gpu/nova-core/fb/hal/ga102.rs     |    7 +-
>>   drivers/gpu/nova-core/fb/hal/tu102.rs     |   22 +-
>>   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         |   10 +-
>>   drivers/gpu/nova-core/regs.rs             |  544 ++++++++------
>>   drivers/gpu/nova-core/regs/macros.rs      |  739 -------------------
>>   rust/kernel/io.rs                         |  347 +++++++--
>>   rust/kernel/io/register.rs                | 1135 +++++++++++++++++++++++++++++
>>   rust/kernel/lib.rs                        |    3 +
>>   rust/kernel/num/bounded.rs                |   70 +-
>>   samples/rust/rust_driver_pci.rs           |   84 ++-
>>   scripts/Makefile.build                    |    3 +-
>>   21 files changed, 2118 insertions(+), 1315 deletions(-)
>> ---
>> base-commit: 545225ee0b0b6998c7b6ff888f8497681b8b35c4
>> change-id: 20260117-register-ccaba1d21713
>
>
> I converted my simple aarch64 TMU timer example [1] over to v7 (many 
> thanks helping with that!) and gave it a try: It works like with v2. 
> With that:
>
> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>

Really appreciated! And I think we are finally converging, so hopefully
no more big refactoring ahead. :) Still, please let me know if you saw
anything that looked off during the conversion.
Re: [PATCH v7 00/10] rust: add `register!` macro
Posted by Dirk Behme 1 month, 2 weeks ago
On 25.02.2026 14:50, Alexandre Courbot wrote:
> On Wed Feb 25, 2026 at 8:58 PM JST, Dirk Behme wrote:
>> On 24.02.2026 15:21, Alexandre Courbot wrote:
>>> New revision addressing the v6 feedback - the use of "location" instead
>>> of "reference" in particular reads well both in the code and the
>>> comments.
>>>
>>> As a reminder, since the previous revision we use the I/O type to
>>> perform the actual I/O instead of the register type, which moves us from
>>> this access pattern:
>>>
>>>       let boot0 = regs::NV_PMC_BOOT_0::read(bar);
>>>
>>> to this arguably more natural one:
>>>
>>>       let boot0 = bar.read(regs::NV_PMC_BOOT_0);
>>>
>>> This revision is based on `driver-core-testing` as of 2026-02-24 with
>>> [1] applied. A tree with this series and its dependencies is available
>>> at [2].
>>>
>>> [1] https://lore.kernel.org/all/20260206-io-v2-0-71dea20a06e6@nvidia.com/
>>> [2] https://github.com/Gnurou/linux/tree/b4/register
>>>
>>> The first patch enables the `generic_arg_infer` feature, which is
>>> required for generic type inference and used in subsequent patches. This
>>> feature is stable since rustc 1.89.
>>>
>>> The second patch adds `shr` and `shl` methods to `Bounded`. These were
>>> suggested by Alice during LPC as a way to avoid the use of the
>>> controversial `Bounded::from_expr` in both the bitfield macro and the
>>> Nova code. The third patch adds another convenience method to obtain a
>>> `bool` from single-bit `Bounded`s, while the fourth patch turns
>>> `Bounded::get` into a const method in order to make register setter
>>> methods const.
>>>
>>> Patches 5 and 6 introduce the `IoLoc` and `IoWrite` types around which
>>> I/O accesses are centered. This allows registers to be accessed using
>>> the same `read` and `write` methods as primitive types.
>>>
>>> Patch 7 adds the `register!` macro and the types it requires.
>>>
>>> Patch 8 updates the Rust PCI sample driver to use `register!`, as per
>>> its TODO item.
>>>
>>> Patch 9 illustrates more extensively how this macro is used by
>>> converting nova-core to use it, and removing the local implementation.
>>> This patch is to be merged one cycle after the other patches.
>>>
>>> Patch 10 is an RFC allowing a shorter write syntax to be used in the
>>> case of fixed or relative registers. It doesn't need to be merged
>>> immediately, but I think it is a good time to discuss it.
>>>
>>> I have also removed Gary's signoff on patches 5 and 7 to make sure it
>>> doesn't get merged before he gives it explicitly.
>>>
>>> Signed-off-by: Alexandre Courbot <acourbot@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 and IoWrite types
>>>         rust: io: use generic read/write accessors for primitive accesses
>>>         rust: io: add `register!` macro
>>>         sample: rust: pci: use `register!` macro
>>>         [FOR REFERENCE] gpu: nova-core: use the kernel `register!` macro
>>>         RFC: rust: io: allow fixed register values directly in `write`
>>>
>>>    drivers/gpu/nova-core/falcon.rs           |  249 +++----
>>>    drivers/gpu/nova-core/falcon/gsp.rs       |   23 +-
>>>    drivers/gpu/nova-core/falcon/hal/ga102.rs |   65 +-
>>>    drivers/gpu/nova-core/falcon/hal/tu102.rs |   11 +-
>>>    drivers/gpu/nova-core/falcon/sec2.rs      |   17 +-
>>>    drivers/gpu/nova-core/fb.rs               |    6 +-
>>>    drivers/gpu/nova-core/fb/hal/ga100.rs     |   40 +-
>>>    drivers/gpu/nova-core/fb/hal/ga102.rs     |    7 +-
>>>    drivers/gpu/nova-core/fb/hal/tu102.rs     |   22 +-
>>>    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         |   10 +-
>>>    drivers/gpu/nova-core/regs.rs             |  544 ++++++++------
>>>    drivers/gpu/nova-core/regs/macros.rs      |  739 -------------------
>>>    rust/kernel/io.rs                         |  347 +++++++--
>>>    rust/kernel/io/register.rs                | 1135 +++++++++++++++++++++++++++++
>>>    rust/kernel/lib.rs                        |    3 +
>>>    rust/kernel/num/bounded.rs                |   70 +-
>>>    samples/rust/rust_driver_pci.rs           |   84 ++-
>>>    scripts/Makefile.build                    |    3 +-
>>>    21 files changed, 2118 insertions(+), 1315 deletions(-)
>>> ---
>>> base-commit: 545225ee0b0b6998c7b6ff888f8497681b8b35c4
>>> change-id: 20260117-register-ccaba1d21713
>>
>>
>> I converted my simple aarch64 TMU timer example [1] over to v7 (many
>> thanks helping with that!) and gave it a try: It works like with v2.
>> With that:
>>
>> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
> 
> Really appreciated! And I think we are finally converging, so hopefully
> no more big refactoring ahead. :) Still, please let me know if you saw
> anything that looked off during the conversion.


I was slightly surprised about the `set_` to `with_` change. But 
thinking about it I think it heavily depends on the point of view:

If you look at it from a physical register point of view I'm used to 
"set" a register / bit. So looking from physical register point of view 
I find using `set_` natural.

On the other hand, if we look at the Rust "syntax" you create here like

foo.with_a(4).with_b(9).write(io);

we write to register foo with bits a being 4 and bits b being 9. So we 
are doing a write *with* some bits set. From this point of view `with_` 
fits as well.

I think you mentioned that this is discussable. And I think it heavily 
depends on the point of view you take. So I'm fine either.

Thanks

Dirk
Re: [PATCH v7 00/10] rust: add `register!` macro
Posted by Alexandre Courbot 1 month, 2 weeks ago
On Thu Feb 26, 2026 at 9:01 PM JST, Dirk Behme wrote:
<snip>
>>> I converted my simple aarch64 TMU timer example [1] over to v7 (many
>>> thanks helping with that!) and gave it a try: It works like with v2.
>>> With that:
>>>
>>> Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
>> 
>> Really appreciated! And I think we are finally converging, so hopefully
>> no more big refactoring ahead. :) Still, please let me know if you saw
>> anything that looked off during the conversion.
>
>
> I was slightly surprised about the `set_` to `with_` change. But 
> thinking about it I think it heavily depends on the point of view:
>
> If you look at it from a physical register point of view I'm used to 
> "set" a register / bit. So looking from physical register point of view 
> I find using `set_` natural.
>
> On the other hand, if we look at the Rust "syntax" you create here like
>
> foo.with_a(4).with_b(9).write(io);
>
> we write to register foo with bits a being 4 and bits b being 9. So we 
> are doing a write *with* some bits set. From this point of view `with_` 
> fits as well.
>
> I think you mentioned that this is discussable. And I think it heavily 
> depends on the point of view you take. So I'm fine either.

This has to do with Rust conventions: we are using a builder pattern,
where fields are set by taking the register by value, and returning the
updated value. Such methods tend to be prefixed with `with_`, whereas
`set_` is typically used for in-plane modification using `&mut self`.

Now AFAICT this is not a *codified* convention, just a rather strong
unwritten one. But it seems adequate to follow it, so users are not
mistaken into thinking the setters do something different than they do.

As to why the builder pattern, this is because it is shorter to write

  io.write(reg.with_foo(true));

than

  mut foo = ...;
  reg.set_foo(true);
  io.write(reg);

and also cleaner as it removes the need for the register variable to be
mutable.