public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Add Rust abstractions for nvmem-provider
@ 2026-02-04  4:04 Link Mauve
  2026-02-04  4:04 ` [PATCH v2 1/4] rust: io: Add big-endian read and write functions Link Mauve
                   ` (3 more replies)
  0 siblings, 4 replies; 23+ messages in thread
From: Link Mauve @ 2026-02-04  4:04 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Link Mauve, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

Hi, this is my first foray in Rust in the kernel!  I’m fairly used to
both Rust and the kernel, but not yet to both at the same time.

I wanted to try something simple before jumping to more advanced stuff
like DRM or V4L2 drivers, so I set on rewriting one of my old Wii
drivers in Rust.

I made sure there was no unsafe anywhere in the driver, and tried to
keep it to as few places as possible in the nvmem abstraction.

I’ve tested it on a Wii, using a downstream branch[1], plus the PowerPC
support patch[2], plus a terrible patch to make libcore not use integer
division on u64 or u128[3].  I’ve tested that the data I get out of this
driver result to the same data as the previous C driver.

Thanks for your time!

[1] https://github.com/Wii-Linux/wii-linux-ngx/commits/wii-mainline
[2] https://lore.kernel.org/rust-for-linux/20260204030507.8203-1-linkmauve@linkmauve.fr/T/
[3] https://linkmauve.fr/files/0001-XXX-Unimplement-core-fmt-on-u64-u128-and-Duration.patch

Changes since v1:
- Add Rust helpers to read and write as big endian.
- Set CONFIG_RUST=y in the Wii defconfig.
- Drop the patch to document nvmem-provider.h, this can go in a latter
  series.

In the nvmem abstractions:
- Replace as pointer casts with .cast(), .cast_const() and .cast_mut().
- Replace NvmemConfig::set_*() with NvmemConfig::with_*() to allow the
  builder pattern.
- Expose devm_nvmem_register() on Device instead of in NvmemConfig,
  making it both more correct and more evident coming from C.
- Make it set priv, reg_read and reg_write, as those are managed by the
  abstraction.

In the nintendo-otp driver:
- Add missing RUST depends
- Remove unnecessary reference to pdev in the driver.
- Simplify the loop using while let instead of break.
- Remove unnecessary Drop impl.
- Adapt to the NvmemConfig changes.
- Use c"" instead of c_str!().
- Correctly read and write as big endian.
- Keep a pinned reference to the iomem, otherwise the driver will crash
  trying to access unmapped memory.

Link Mauve (4):
  rust: io: Add big-endian read and write functions
  rust: nvmem: Add an abstraction for nvmem providers
  nvmem: Replace the Wii and Wii U OTP driver with a Rust one
  powerpc: wii_defconfig: Enable Rust

 arch/powerpc/configs/wii_defconfig |   1 +
 drivers/nvmem/Kconfig              |   1 +
 drivers/nvmem/Makefile             |   2 +-
 drivers/nvmem/nintendo-otp.c       | 122 ---------------------
 drivers/nvmem/nintendo_otp.rs      | 127 ++++++++++++++++++++++
 rust/bindings/bindings_helper.h    |   1 +
 rust/helpers/io.c                  |  34 ++++++
 rust/kernel/io.rs                  |  18 ++++
 rust/kernel/lib.rs                 |   2 +
 rust/kernel/nvmem.rs               | 163 +++++++++++++++++++++++++++++
 10 files changed, 348 insertions(+), 123 deletions(-)
 delete mode 100644 drivers/nvmem/nintendo-otp.c
 create mode 100644 drivers/nvmem/nintendo_otp.rs
 create mode 100644 rust/kernel/nvmem.rs

-- 
2.52.0


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

* [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-04  4:04 [PATCH v2 0/4] Add Rust abstractions for nvmem-provider Link Mauve
@ 2026-02-04  4:04 ` Link Mauve
  2026-02-04 15:18   ` Danilo Krummrich
  2026-02-04  4:04 ` [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers Link Mauve
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 23+ messages in thread
From: Link Mauve @ 2026-02-04  4:04 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Link Mauve, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

Another option would be to call u32::swap_bytes() on the data being
read/written, but these helpers make the Rust code as ergonomic as the C
code.

Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
---
 rust/helpers/io.c | 34 ++++++++++++++++++++++++++++++++++
 rust/kernel/io.rs | 18 ++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/rust/helpers/io.c b/rust/helpers/io.c
index c475913c69e6..514ad0377327 100644
--- a/rust/helpers/io.c
+++ b/rust/helpers/io.c
@@ -40,6 +40,23 @@ u64 rust_helper_readq(const void __iomem *addr)
 }
 #endif
 
+u16 rust_helper_ioread16be(const void __iomem *addr)
+{
+	return ioread16be(addr);
+}
+
+u32 rust_helper_ioread32be(const void __iomem *addr)
+{
+	return ioread32be(addr);
+}
+
+#ifdef CONFIG_64BIT
+u64 rust_helper_ioread64be(const void __iomem *addr)
+{
+	return ioread64be(addr);
+}
+#endif
+
 void rust_helper_writeb(u8 value, void __iomem *addr)
 {
 	writeb(value, addr);
@@ -62,6 +79,23 @@ void rust_helper_writeq(u64 value, void __iomem *addr)
 }
 #endif
 
+void rust_helper_iowrite16be(u16 value, void __iomem *addr)
+{
+	iowrite16be(value, addr);
+}
+
+void rust_helper_iowrite32be(u32 value, void __iomem *addr)
+{
+	iowrite32be(value, addr);
+}
+
+#ifdef CONFIG_64BIT
+void rust_helper_iowrite64be(u64 value, void __iomem *addr)
+{
+	iowrite64be(value, addr);
+}
+#endif
+
 u8 rust_helper_readb_relaxed(const void __iomem *addr)
 {
 	return readb_relaxed(addr);
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 98e8b84e68d1..e6912e7ff036 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -256,6 +256,15 @@ fn io_addr_assert<U>(&self, offset: usize) -> usize {
         readq -> u64
     );
 
+    define_read!(read16be, try_read16be, ioread16be -> u16);
+    define_read!(read32be, try_read32be, ioread32be -> u32);
+    define_read!(
+        #[cfg(CONFIG_64BIT)]
+        read64be,
+        try_read64be,
+        ioread64be -> u64
+    );
+
     define_read!(read8_relaxed, try_read8_relaxed, readb_relaxed -> u8);
     define_read!(read16_relaxed, try_read16_relaxed, readw_relaxed -> u16);
     define_read!(read32_relaxed, try_read32_relaxed, readl_relaxed -> u32);
@@ -276,6 +285,15 @@ fn io_addr_assert<U>(&self, offset: usize) -> usize {
         writeq <- u64
     );
 
+    define_write!(write16be, try_write16be, iowrite16be <- u16);
+    define_write!(write32be, try_write32be, iowrite32be <- u32);
+    define_write!(
+        #[cfg(CONFIG_64BIT)]
+        write64be,
+        try_write64be,
+        iowrite64be <- u64
+    );
+
     define_write!(write8_relaxed, try_write8_relaxed, writeb_relaxed <- u8);
     define_write!(write16_relaxed, try_write16_relaxed, writew_relaxed <- u16);
     define_write!(write32_relaxed, try_write32_relaxed, writel_relaxed <- u32);
-- 
2.52.0


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

* [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers
  2026-02-04  4:04 [PATCH v2 0/4] Add Rust abstractions for nvmem-provider Link Mauve
  2026-02-04  4:04 ` [PATCH v2 1/4] rust: io: Add big-endian read and write functions Link Mauve
@ 2026-02-04  4:04 ` Link Mauve
  2026-02-04 15:22   ` Danilo Krummrich
  2026-02-04  4:05 ` [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one Link Mauve
  2026-02-04  4:05 ` [PATCH v2 4/4] powerpc: wii_defconfig: Enable Rust Link Mauve
  3 siblings, 1 reply; 23+ messages in thread
From: Link Mauve @ 2026-02-04  4:04 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Link Mauve, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

This is my very first Rust abstraction in the kernel, I took inspiration
from various other abstractions that had already been written.

I only implemented enough to rewrite a very simple driver I wrote in the
past, in order to test the API and make sure it’s at least as ergonomic
as the C version, without any unsafe at all.

Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/kernel/lib.rs              |   2 +
 rust/kernel/nvmem.rs            | 163 ++++++++++++++++++++++++++++++++
 3 files changed, 166 insertions(+)
 create mode 100644 rust/kernel/nvmem.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index a067038b4b42..522a76b2e294 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -65,6 +65,7 @@
 #include <linux/mdio.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
+#include <linux/nvmem-provider.h>
 #include <linux/of_device.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 696f62f85eb5..97f3fc1e8e12 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -118,6 +118,8 @@
 #[cfg(CONFIG_NET)]
 pub mod net;
 pub mod num;
+#[cfg(CONFIG_NVMEM)]
+pub mod nvmem;
 pub mod of;
 #[cfg(CONFIG_PM_OPP)]
 pub mod opp;
diff --git a/rust/kernel/nvmem.rs b/rust/kernel/nvmem.rs
new file mode 100644
index 000000000000..4b81fd65c9a7
--- /dev/null
+++ b/rust/kernel/nvmem.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! nvmem framework provider.
+//!
+//! Copyright (C) 2026 Link Mauve <linkmauve@linkmauve.fr>
+
+use crate::build_error;
+use crate::device::Device;
+use crate::error::{from_result, VTABLE_DEFAULT_ERROR};
+use crate::prelude::*;
+use core::marker::PhantomData;
+use macros::vtable;
+
+/// The possible types for a nvmem provider.
+#[derive(Default)]
+#[repr(u32)]
+pub enum Type {
+    /// The type of memory is unknown.
+    #[default]
+    Unknown = bindings::nvmem_type_NVMEM_TYPE_UNKNOWN,
+
+    /// Electrically erasable programmable ROM.
+    Eeprom = bindings::nvmem_type_NVMEM_TYPE_EEPROM,
+
+    /// One-time programmable memory.
+    Otp = bindings::nvmem_type_NVMEM_TYPE_OTP,
+
+    /// This memory is backed by a battery.
+    BatteryBacked = bindings::nvmem_type_NVMEM_TYPE_BATTERY_BACKED,
+
+    /// Ferroelectric RAM.
+    Fram = bindings::nvmem_type_NVMEM_TYPE_FRAM,
+}
+
+/// nvmem configuration.
+///
+/// Rust abstraction for the C `struct nvmem_config`.
+#[derive(Default)]
+#[repr(transparent)]
+pub struct NvmemConfig<T: NvmemProvider + Default> {
+    inner: bindings::nvmem_config,
+    _p: PhantomData<T>,
+}
+
+impl<T: NvmemProvider + Default> NvmemConfig<T> {
+    /// NvmemConfig's read callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
+    extern "C" fn reg_read(
+        context: *mut c_void,
+        offset: u32,
+        val: *mut c_void,
+        bytes: usize,
+    ) -> i32 {
+        from_result(|| {
+            let context = context.cast::<T::Priv>();
+            // SAFETY: context is a valid T::Priv as set in Device::nvmem_register().
+            let context = unsafe { &*context };
+            let val = val.cast::<u8>();
+            // SAFETY: val should be non-null, and allocated for bytes bytes.
+            let data = unsafe { core::slice::from_raw_parts_mut(val, bytes) };
+            T::read(context, offset, data).map(|()| 0)
+        })
+    }
+
+    /// NvmemConfig's write callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
+    extern "C" fn reg_write(
+        context: *mut c_void,
+        offset: u32,
+        // TODO: Change val from void* to const void* in the C API!
+        val: *mut c_void,
+        bytes: usize,
+    ) -> i32 {
+        from_result(|| {
+            let context = context.cast::<T::Priv>();
+            // SAFETY: context is a valid T::Priv as set in Device::nvmem_register().
+            let context = unsafe { &*context };
+            let val = val.cast::<u8>().cast_const();
+            // SAFETY: val should be non-null, and allocated for bytes bytes.
+            let data = unsafe { core::slice::from_raw_parts(val, bytes) };
+            T::write(context, offset, data).map(|()| 0)
+        })
+    }
+
+    /// Optional name.
+    pub fn with_name(mut self, name: &CStr) -> Self {
+        self.inner.name = name.as_char_ptr();
+        self
+    }
+
+    /// Type of the nvmem storage
+    pub fn with_type(mut self, type_: Type) -> Self {
+        self.inner.type_ = type_ as u32;
+        self
+    }
+
+    /// Device is read-only.
+    pub fn with_read_only(mut self, read_only: bool) -> Self {
+        self.inner.read_only = read_only;
+        self
+    }
+
+    /// Device is accessibly to root only.
+    pub fn with_root_only(mut self, root_only: bool) -> Self {
+        self.inner.root_only = root_only;
+        self
+    }
+
+    /// Device size.
+    pub fn with_size(mut self, size: i32) -> Self {
+        self.inner.size = size;
+        self
+    }
+
+    /// Minimum read/write access granularity.
+    pub fn with_word_size(mut self, word_size: i32) -> Self {
+        self.inner.word_size = word_size;
+        self
+    }
+
+    /// Minimum read/write access stride.
+    pub fn with_stride(mut self, stride: i32) -> Self {
+        self.inner.stride = stride;
+        self
+    }
+}
+
+impl Device {
+    /// Register a managed nvmem provider on the given device.
+    pub fn nvmem_register<T>(&self, mut config: NvmemConfig<T>, priv_: &T::Priv)
+    where
+        T: NvmemProvider + Default,
+    {
+        // FIXME: The last cast to mut indicates some unsoundness here.
+        config.inner.priv_ = core::ptr::from_ref(priv_).cast::<c_void>().cast_mut();
+        config.inner.dev = self.as_raw();
+        config.inner.reg_read = Some(NvmemConfig::<T>::reg_read);
+        config.inner.reg_write = Some(NvmemConfig::<T>::reg_write);
+        // SAFETY: Both self and config can’t be null here, and should have the correct type.
+        unsafe { bindings::devm_nvmem_register(self.as_raw(), &config.inner) };
+    }
+}
+
+/// Helper trait to define the callbacks of a nvmem provider.
+#[vtable]
+pub trait NvmemProvider {
+    /// The type passed into the context for read and write functions.
+    type Priv;
+
+    /// Callback to read data.
+    #[inline]
+    fn read(_context: &Self::Priv, _offset: u32, _data: &mut [u8]) -> Result {
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Callback to write data.
+    #[inline]
+    fn write(_context: &Self::Priv, _offset: u32, _data: &[u8]) -> Result {
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+}
-- 
2.52.0


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

* [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one
  2026-02-04  4:04 [PATCH v2 0/4] Add Rust abstractions for nvmem-provider Link Mauve
  2026-02-04  4:04 ` [PATCH v2 1/4] rust: io: Add big-endian read and write functions Link Mauve
  2026-02-04  4:04 ` [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers Link Mauve
@ 2026-02-04  4:05 ` Link Mauve
  2026-03-04 18:46   ` Link Mauve
  2026-02-04  4:05 ` [PATCH v2 4/4] powerpc: wii_defconfig: Enable Rust Link Mauve
  3 siblings, 1 reply; 23+ messages in thread
From: Link Mauve @ 2026-02-04  4:05 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Link Mauve, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

I wrote this driver long ago, and wanted to try seeing how hard it would
be to convert it to Rust.

It is a very simple driver, we write the address we want to read in one
memory address, and read the data from a second memory address.  A third
memory address can be used to disable all reads in a range until the
system has been rebooted, but I didn’t find any reason to expose that
feature.

I made sure to use no unsafe in this driver, to make sure the API
exposed in the previous commit is usable.

Ideally we wouldn’t have to impl the write() function in
NintendoOtpProvider, but currently the vtable requires both.

I have tested this driver only on a Wii so far, but I assume it will
work the same on a Wii U, just exposing more memory banks.

Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
---
 drivers/nvmem/Kconfig         |   1 +
 drivers/nvmem/Makefile        |   2 +-
 drivers/nvmem/nintendo-otp.c  | 122 --------------------------------
 drivers/nvmem/nintendo_otp.rs | 127 ++++++++++++++++++++++++++++++++++
 4 files changed, 129 insertions(+), 123 deletions(-)
 delete mode 100644 drivers/nvmem/nintendo-otp.c
 create mode 100644 drivers/nvmem/nintendo_otp.rs

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index bf47a982cf62..c23d338f820a 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -241,6 +241,7 @@ config NVMEM_MXS_OCOTP
 
 config NVMEM_NINTENDO_OTP
 	tristate "Nintendo Wii and Wii U OTP Support"
+	depends on RUST
 	depends on WII || COMPILE_TEST
 	help
 	  This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 7252b8ec88d4..3d40a0a23f76 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -51,7 +51,7 @@ nvmem_mtk-efuse-y			:= mtk-efuse.o
 obj-$(CONFIG_NVMEM_MXS_OCOTP)		+= nvmem-mxs-ocotp.o
 nvmem-mxs-ocotp-y			:= mxs-ocotp.o
 obj-$(CONFIG_NVMEM_NINTENDO_OTP)	+= nvmem-nintendo-otp.o
-nvmem-nintendo-otp-y			:= nintendo-otp.o
+nvmem-nintendo-otp-y			:= nintendo_otp.o
 obj-$(CONFIG_NVMEM_QCOM_QFPROM)		+= nvmem_qfprom.o
 nvmem_qfprom-y				:= qfprom.o
 obj-$(CONFIG_NVMEM_QCOM_SEC_QFPROM)	+= nvmem_sec_qfprom.o
diff --git a/drivers/nvmem/nintendo-otp.c b/drivers/nvmem/nintendo-otp.c
deleted file mode 100644
index 355e7f1fc6d5..000000000000
--- a/drivers/nvmem/nintendo-otp.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Nintendo Wii and Wii U OTP driver
- *
- * This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
- *
- * This memory contains common and per-console keys, signatures and
- * related data required to access peripherals.
- *
- * Based on reversed documentation from https://wiiubrew.org/wiki/Hardware/OTP
- *
- * Copyright (C) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/nvmem-provider.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-
-#define HW_OTPCMD  0
-#define HW_OTPDATA 4
-#define OTP_READ   0x80000000
-#define BANK_SIZE  128
-#define WORD_SIZE  4
-
-struct nintendo_otp_priv {
-	void __iomem *regs;
-};
-
-struct nintendo_otp_devtype_data {
-	const char *name;
-	unsigned int num_banks;
-};
-
-static const struct nintendo_otp_devtype_data hollywood_otp_data = {
-	.name = "wii-otp",
-	.num_banks = 1,
-};
-
-static const struct nintendo_otp_devtype_data latte_otp_data = {
-	.name = "wiiu-otp",
-	.num_banks = 8,
-};
-
-static int nintendo_otp_reg_read(void *context,
-				 unsigned int reg, void *_val, size_t bytes)
-{
-	struct nintendo_otp_priv *priv = context;
-	u32 *val = _val;
-	int words = bytes / WORD_SIZE;
-	u32 bank, addr;
-
-	while (words--) {
-		bank = (reg / BANK_SIZE) << 8;
-		addr = (reg / WORD_SIZE) % (BANK_SIZE / WORD_SIZE);
-		iowrite32be(OTP_READ | bank | addr, priv->regs + HW_OTPCMD);
-		*val++ = ioread32be(priv->regs + HW_OTPDATA);
-		reg += WORD_SIZE;
-	}
-
-	return 0;
-}
-
-static const struct of_device_id nintendo_otp_of_table[] = {
-	{ .compatible = "nintendo,hollywood-otp", .data = &hollywood_otp_data },
-	{ .compatible = "nintendo,latte-otp", .data = &latte_otp_data },
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, nintendo_otp_of_table);
-
-static int nintendo_otp_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	const struct of_device_id *of_id =
-		of_match_device(nintendo_otp_of_table, dev);
-	struct nvmem_device *nvmem;
-	struct nintendo_otp_priv *priv;
-
-	struct nvmem_config config = {
-		.stride = WORD_SIZE,
-		.word_size = WORD_SIZE,
-		.reg_read = nintendo_otp_reg_read,
-		.read_only = true,
-		.root_only = true,
-	};
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->regs = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(priv->regs))
-		return PTR_ERR(priv->regs);
-
-	if (of_id->data) {
-		const struct nintendo_otp_devtype_data *data = of_id->data;
-		config.name = data->name;
-		config.size = data->num_banks * BANK_SIZE;
-	}
-
-	config.dev = dev;
-	config.priv = priv;
-
-	nvmem = devm_nvmem_register(dev, &config);
-
-	return PTR_ERR_OR_ZERO(nvmem);
-}
-
-static struct platform_driver nintendo_otp_driver = {
-	.probe = nintendo_otp_probe,
-	.driver = {
-		.name = "nintendo-otp",
-		.of_match_table = nintendo_otp_of_table,
-	},
-};
-module_platform_driver(nintendo_otp_driver);
-MODULE_AUTHOR("Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>");
-MODULE_DESCRIPTION("Nintendo Wii and Wii U OTP driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/nintendo_otp.rs b/drivers/nvmem/nintendo_otp.rs
new file mode 100644
index 000000000000..04ba3591d674
--- /dev/null
+++ b/drivers/nvmem/nintendo_otp.rs
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+//! Nintendo Wii and Wii U OTP driver
+//!
+//! This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
+//!
+//! This memory contains common and per-console keys, signatures and
+//! related data required to access peripherals.
+//!
+//! Based on reversed documentation from https://wiiubrew.org/wiki/Hardware/OTP
+//!
+//! Copyright (C) 2021 Link Mauve <linkmauve@linkmauve.fr>
+
+use kernel::{
+    device::Core,
+    devres::Devres,
+    io::{mem::ExclusiveIoMem, Io},
+    nvmem::{self, NvmemConfig, NvmemProvider},
+    of::{DeviceId, IdTable},
+    platform,
+    prelude::*,
+};
+
+const HW_OTPCMD: usize = 0;
+const HW_OTPDATA: usize = 4;
+const OTP_READ: u32 = 0x80000000;
+const BANK_SIZE: u32 = 128;
+const WORD_SIZE: u32 = 4;
+
+struct Info {
+    name: &'static CStr,
+    num_banks: u32,
+}
+
+const WII_INFO: Info = Info {
+    name: c"wii-otp",
+    num_banks: 1,
+};
+
+const WIIU_INFO: Info = Info {
+    name: c"wiiu-otp",
+    num_banks: 8,
+};
+
+struct NintendoOtpDriver {
+    #[expect(dead_code)]
+    iomem: Pin<KBox<Devres<ExclusiveIoMem<8>>>>,
+}
+
+kernel::of_device_table!(
+    OF_TABLE,
+    MODULE_OF_TABLE,
+    <NintendoOtpDriver as platform::Driver>::IdInfo,
+    [
+        (DeviceId::new(c"nintendo,hollywood-otp"), WII_INFO),
+        (DeviceId::new(c"nintendo,latte-otp"), WIIU_INFO),
+    ]
+);
+
+#[derive(Default)]
+struct NintendoOtpProvider;
+
+#[vtable]
+impl NvmemProvider for NintendoOtpProvider {
+    type Priv = Io<8>;
+
+    fn read(io: &Self::Priv, mut reg: u32, mut data: &mut [u8]) -> Result {
+        while let Some(bytes) = data.split_off_mut(..4) {
+            let bank = (reg / BANK_SIZE) << 8;
+            let addr = (reg / WORD_SIZE) % (BANK_SIZE / WORD_SIZE);
+            io.write32be(OTP_READ | bank | addr, HW_OTPCMD);
+            let elem = io.read32be(HW_OTPDATA);
+            bytes.copy_from_slice(&elem.to_be_bytes());
+            reg += WORD_SIZE;
+        }
+
+        Ok(())
+    }
+
+    fn write(_context: &Self::Priv, _offset: u32, _data: &[u8]) -> Result {
+        Err(ENODEV)
+    }
+}
+
+impl platform::Driver for NintendoOtpDriver {
+    type IdInfo = Info;
+    const OF_ID_TABLE: Option<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();
+
+        let Some(Info { name, num_banks }) = info else {
+            return Err(EINVAL);
+        };
+
+        dev_info!(dev, "got '{name}', num_banks = {num_banks}\n");
+
+        let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
+        let iomem = request.iomap_exclusive_sized::<8>();
+        let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
+        let io = iomem.access(dev)?;
+
+        let config = NvmemConfig::<NintendoOtpProvider>::default()
+            .with_name(name)
+            .with_type(nvmem::Type::Otp)
+            .with_size((num_banks * BANK_SIZE) as i32)
+            .with_word_size(WORD_SIZE as i32)
+            .with_stride(WORD_SIZE as i32)
+            .with_read_only(true)
+            .with_root_only(true);
+
+        dev.nvmem_register(config, io);
+
+        Ok(Self { iomem })
+    }
+}
+
+kernel::module_platform_driver! {
+    type: NintendoOtpDriver,
+    name: "nintendo-otp",
+    authors: ["Link Mauve <linkmauve@linkmauve.fr>"],
+    description: "Nintendo Wii and Wii U OTP driver",
+    license: "GPL v2",
+}
-- 
2.52.0


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

* [PATCH v2 4/4] powerpc: wii_defconfig: Enable Rust
  2026-02-04  4:04 [PATCH v2 0/4] Add Rust abstractions for nvmem-provider Link Mauve
                   ` (2 preceding siblings ...)
  2026-02-04  4:05 ` [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one Link Mauve
@ 2026-02-04  4:05 ` Link Mauve
  3 siblings, 0 replies; 23+ messages in thread
From: Link Mauve @ 2026-02-04  4:05 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Link Mauve, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

The nintendo-otp driver now depends on Rust, so let’s enable it on this
platform.

Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
---
 arch/powerpc/configs/wii_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig
index 7c714a19221e..b1172249e783 100644
--- a/arch/powerpc/configs/wii_defconfig
+++ b/arch/powerpc/configs/wii_defconfig
@@ -18,6 +18,7 @@ CONFIG_WII=y
 # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 CONFIG_PREEMPT=y
 CONFIG_BINFMT_MISC=m
+CONFIG_RUST=y
 CONFIG_KEXEC=y
 # CONFIG_SECCOMP is not set
 CONFIG_ADVANCED_OPTIONS=y
-- 
2.52.0


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-04  4:04 ` [PATCH v2 1/4] rust: io: Add big-endian read and write functions Link Mauve
@ 2026-02-04 15:18   ` Danilo Krummrich
  2026-02-04 15:20     ` Danilo Krummrich
  2026-02-05 14:28     ` Daniel Almeida
  0 siblings, 2 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-04 15:18 UTC (permalink / raw)
  To: Link Mauve
  Cc: rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
> Another option would be to call u32::swap_bytes() on the data being
> read/written, but these helpers make the Rust code as ergonomic as the C
> code.
>
> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>

The I/O stuff recently changed quite significantly, please have a look at the
driver-core-next branch [1] in the driver-core tree.

Also, instead of providing additional *be() methods, we should just create a new
type io::Endianness and use it to indicate the device endianness when requesting
the I/O resource.

For instance, for your driver we could have

	request.iomap_exclusive_sized::<8>(Endianness::Big)?

and then let the I/O backend choose the correct accessors based on this.

I.e. the device is either big or little endian, hence we don't need to provide
both accessors at the same time.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git/log/?h=driver-core-next

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-04 15:18   ` Danilo Krummrich
@ 2026-02-04 15:20     ` Danilo Krummrich
  2026-02-05 14:28     ` Daniel Almeida
  1 sibling, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-04 15:20 UTC (permalink / raw)
  To: Link Mauve
  Cc: rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Wed Feb 4, 2026 at 4:18 PM CET, Danilo Krummrich wrote:
> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>> Another option would be to call u32::swap_bytes() on the data being
>> read/written, but these helpers make the Rust code as ergonomic as the C
>> code.
>>
>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>
> The I/O stuff recently changed quite significantly, please have a look at the
> driver-core-next branch [1] in the driver-core tree.
>
> Also, instead of providing additional *be() methods, we should just create a new
> type io::Endianness and use it to indicate the device endianness when requesting
> the I/O resource.
>
> For instance, for your driver we could have
>
> 	request.iomap_exclusive_sized::<8>(Endianness::Big)?
>
> and then let the I/O backend choose the correct accessors based on this.
>
> I.e. the device is either big or little endian, hence we don't need to provide
> both accessors at the same time.
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git/log/?h=driver-core-next

Forgot to mention, please also consider this patch series [2] for your work.

[2] https://lore.kernel.org/all/20260202-io-v1-0-9bb2177d23be@nvidia.com/

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

* Re: [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers
  2026-02-04  4:04 ` [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers Link Mauve
@ 2026-02-04 15:22   ` Danilo Krummrich
  2026-02-05 12:48     ` Link Mauve
  0 siblings, 1 reply; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-04 15:22 UTC (permalink / raw)
  To: Link Mauve
  Cc: rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
> +impl Device {
> +    /// Register a managed nvmem provider on the given device.
> +    pub fn nvmem_register<T>(&self, mut config: NvmemConfig<T>, priv_: &T::Priv)
> +    where
> +        T: NvmemProvider + Default,
> +    {
> +        // FIXME: The last cast to mut indicates some unsoundness here.
> +        config.inner.priv_ = core::ptr::from_ref(priv_).cast::<c_void>().cast_mut();
> +        config.inner.dev = self.as_raw();
> +        config.inner.reg_read = Some(NvmemConfig::<T>::reg_read);
> +        config.inner.reg_write = Some(NvmemConfig::<T>::reg_write);
> +        // SAFETY: Both self and config can’t be null here, and should have the correct type.
> +        unsafe { bindings::devm_nvmem_register(self.as_raw(), &config.inner) };
> +    }
> +}

This should not be a method on the generic device type. Typically we use a
Registration struct for this, i.e. this would become
nvmem::Registration::register().

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

* Re: [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers
  2026-02-04 15:22   ` Danilo Krummrich
@ 2026-02-05 12:48     ` Link Mauve
  2026-02-05 12:57       ` Danilo Krummrich
  0 siblings, 1 reply; 23+ messages in thread
From: Link Mauve @ 2026-02-05 12:48 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Link Mauve, rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Wed, Feb 04, 2026 at 04:22:16PM +0100, Danilo Krummrich wrote:
> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
> > +impl Device {
> > +    /// Register a managed nvmem provider on the given device.
> > +    pub fn nvmem_register<T>(&self, mut config: NvmemConfig<T>, priv_: &T::Priv)
> > +    where
> > +        T: NvmemProvider + Default,
> > +    {
> > +        // FIXME: The last cast to mut indicates some unsoundness here.
> > +        config.inner.priv_ = core::ptr::from_ref(priv_).cast::<c_void>().cast_mut();
> > +        config.inner.dev = self.as_raw();
> > +        config.inner.reg_read = Some(NvmemConfig::<T>::reg_read);
> > +        config.inner.reg_write = Some(NvmemConfig::<T>::reg_write);
> > +        // SAFETY: Both self and config can’t be null here, and should have the correct type.
> > +        unsafe { bindings::devm_nvmem_register(self.as_raw(), &config.inner) };
> > +    }
> > +}
> 
> This should not be a method on the generic device type. Typically we use a
> Registration struct for this, i.e. this would become
> nvmem::Registration::register().

Should I also switch to the nvmem_register()/nvmem_unregister() API
instead of the devm_nvmem_register() API, so that the unregister can
happen in the Drop impl instead of being managed by the kernel?

-- 
Link Mauve

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

* Re: [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers
  2026-02-05 12:48     ` Link Mauve
@ 2026-02-05 12:57       ` Danilo Krummrich
  0 siblings, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 12:57 UTC (permalink / raw)
  To: Link Mauve
  Cc: rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 1:48 PM CET, Link Mauve wrote:
> On Wed, Feb 04, 2026 at 04:22:16PM +0100, Danilo Krummrich wrote:
>> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>> > +impl Device {
>> > +    /// Register a managed nvmem provider on the given device.
>> > +    pub fn nvmem_register<T>(&self, mut config: NvmemConfig<T>, priv_: &T::Priv)
>> > +    where
>> > +        T: NvmemProvider + Default,
>> > +    {
>> > +        // FIXME: The last cast to mut indicates some unsoundness here.
>> > +        config.inner.priv_ = core::ptr::from_ref(priv_).cast::<c_void>().cast_mut();
>> > +        config.inner.dev = self.as_raw();
>> > +        config.inner.reg_read = Some(NvmemConfig::<T>::reg_read);
>> > +        config.inner.reg_write = Some(NvmemConfig::<T>::reg_write);
>> > +        // SAFETY: Both self and config can’t be null here, and should have the correct type.
>> > +        unsafe { bindings::devm_nvmem_register(self.as_raw(), &config.inner) };
>> > +    }
>> > +}
>> 
>> This should not be a method on the generic device type. Typically we use a
>> Registration struct for this, i.e. this would become
>> nvmem::Registration::register().
>
> Should I also switch to the nvmem_register()/nvmem_unregister() API
> instead of the devm_nvmem_register() API, so that the unregister can
> happen in the Drop impl instead of being managed by the kernel?

No, ensuring unregistration when the bus device is unbound is the correct thing
to do.

We typically support two patterns:

	impl Registration {
		fn new(dev: &Device<Bound>) -> Result<Devres<Registration>>;
		fn register(dev: &Device<Bound>) -> Result;
	}

Registration::new() still ensures unregistration when the bus device is unbound,
but also allows you to unregister before that happens.

Registration::register() is eqivalent to devm_nvmem_register().

You don't have to implement both, you can just pick the one you need for your
driver. I think in the case of nvmem you probably only every need register().

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-04 15:18   ` Danilo Krummrich
  2026-02-04 15:20     ` Danilo Krummrich
@ 2026-02-05 14:28     ` Daniel Almeida
  2026-02-05 14:56       ` Danilo Krummrich
  2026-02-05 15:16       ` Gary Guo
  1 sibling, 2 replies; 23+ messages in thread
From: Daniel Almeida @ 2026-02-05 14:28 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Link Mauve, rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer



> On 4 Feb 2026, at 12:18, Danilo Krummrich <dakr@kernel.org> wrote:
> 
> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>> Another option would be to call u32::swap_bytes() on the data being
>> read/written, but these helpers make the Rust code as ergonomic as the C
>> code.
>> 
>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
> 
> The I/O stuff recently changed quite significantly, please have a look at the
> driver-core-next branch [1] in the driver-core tree.
> 
> Also, instead of providing additional *be() methods, we should just create a new
> type io::Endianness and use it to indicate the device endianness when requesting
> the I/O resource.
> 
> For instance, for your driver we could have
> 
> request.iomap_exclusive_sized::<8>(Endianness::Big)?

Can we please structure this in a way that LittleEndian is the default?
Perhaps using a const generic that is defaulted, or something along these lines.

> 
> and then let the I/O backend choose the correct accessors based on this.
> 
> I.e. the device is either big or little endian, hence we don't need to provide
> both accessors at the same time.
> 
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git/log/?h=driver-core-next
> 


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 14:28     ` Daniel Almeida
@ 2026-02-05 14:56       ` Danilo Krummrich
  2026-02-05 15:16       ` Gary Guo
  1 sibling, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 14:56 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Link Mauve, rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 3:28 PM CET, Daniel Almeida wrote:
>
>
>> On 4 Feb 2026, at 12:18, Danilo Krummrich <dakr@kernel.org> wrote:
>> 
>> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>>> Another option would be to call u32::swap_bytes() on the data being
>>> read/written, but these helpers make the Rust code as ergonomic as the C
>>> code.
>>> 
>>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>> 
>> The I/O stuff recently changed quite significantly, please have a look at the
>> driver-core-next branch [1] in the driver-core tree.
>> 
>> Also, instead of providing additional *be() methods, we should just create a new
>> type io::Endianness and use it to indicate the device endianness when requesting
>> the I/O resource.
>> 
>> For instance, for your driver we could have
>> 
>> request.iomap_exclusive_sized::<8>(Endianness::Big)?
>
> Can we please structure this in a way that LittleEndian is the default?
> Perhaps using a const generic that is defaulted, or something along these lines.

Yes, little-endian should absolutely be the default. Please don't take the above
as specific suggestion. :)

>> 
>> and then let the I/O backend choose the correct accessors based on this.
>> 
>> I.e. the device is either big or little endian, hence we don't need to provide
>> both accessors at the same time.
>> 
>> [1] https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git/log/?h=driver-core-next
>> 


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 14:28     ` Daniel Almeida
  2026-02-05 14:56       ` Danilo Krummrich
@ 2026-02-05 15:16       ` Gary Guo
  2026-02-05 17:28         ` Daniel Almeida
  1 sibling, 1 reply; 23+ messages in thread
From: Gary Guo @ 2026-02-05 15:16 UTC (permalink / raw)
  To: Daniel Almeida, Danilo Krummrich
  Cc: Link Mauve, rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 2:28 PM GMT, Daniel Almeida wrote:
>
>
>> On 4 Feb 2026, at 12:18, Danilo Krummrich <dakr@kernel.org> wrote:
>> 
>> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>>> Another option would be to call u32::swap_bytes() on the data being
>>> read/written, but these helpers make the Rust code as ergonomic as the C
>>> code.
>>> 
>>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>> 
>> The I/O stuff recently changed quite significantly, please have a look at the
>> driver-core-next branch [1] in the driver-core tree.
>> 
>> Also, instead of providing additional *be() methods, we should just create a new
>> type io::Endianness and use it to indicate the device endianness when requesting
>> the I/O resource.
>> 
>> For instance, for your driver we could have
>> 
>> request.iomap_exclusive_sized::<8>(Endianness::Big)?
>
> Can we please structure this in a way that LittleEndian is the default?
> Perhaps using a const generic that is defaulted, or something along these lines.

I think we should have everything default to little endian, and have wrapper
types that do big endian which require expicit construction, similar to
RelaxedMmio in Alex's series.

Best,
Gary

>
>> 
>> and then let the I/O backend choose the correct accessors based on this.
>> 
>> I.e. the device is either big or little endian, hence we don't need to provide
>> both accessors at the same time.
>> 
>> [1] https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git/log/?h=driver-core-next
>> 


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 15:16       ` Gary Guo
@ 2026-02-05 17:28         ` Daniel Almeida
  2026-02-05 19:05           ` Danilo Krummrich
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Almeida @ 2026-02-05 17:28 UTC (permalink / raw)
  To: Gary Guo
  Cc: Danilo Krummrich, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer



> On 5 Feb 2026, at 12:16, Gary Guo <gary@garyguo.net> wrote:
> 
> On Thu Feb 5, 2026 at 2:28 PM GMT, Daniel Almeida wrote:
>> 
>> 
>>> On 4 Feb 2026, at 12:18, Danilo Krummrich <dakr@kernel.org> wrote:
>>> 
>>> On Wed Feb 4, 2026 at 5:04 AM CET, Link Mauve wrote:
>>>> Another option would be to call u32::swap_bytes() on the data being
>>>> read/written, but these helpers make the Rust code as ergonomic as the C
>>>> code.
>>>> 
>>>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>>> 
>>> The I/O stuff recently changed quite significantly, please have a look at the
>>> driver-core-next branch [1] in the driver-core tree.
>>> 
>>> Also, instead of providing additional *be() methods, we should just create a new
>>> type io::Endianness and use it to indicate the device endianness when requesting
>>> the I/O resource.
>>> 
>>> For instance, for your driver we could have
>>> 
>>> request.iomap_exclusive_sized::<8>(Endianness::Big)?
>> 
>> Can we please structure this in a way that LittleEndian is the default?
>> Perhaps using a const generic that is defaulted, or something along these lines.
> 
> I think we should have everything default to little endian, and have wrapper
> types that do big endian which require expicit construction, similar to
> RelaxedMmio in Alex's series.
> 
> Best,
> Gary
> 

Ah yes, the RelaxedMmio pattern is definitely a good one. I agree that we should head in this direction.

— Daniel


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 17:28         ` Daniel Almeida
@ 2026-02-05 19:05           ` Danilo Krummrich
  2026-02-05 21:20             ` Link Mauve
  2026-02-05 22:31             ` Gary Guo
  0 siblings, 2 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 19:05 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Gary Guo, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 6:28 PM CET, Daniel Almeida wrote:
>> On 5 Feb 2026, at 12:16, Gary Guo <gary@garyguo.net> wrote:
>> I think we should have everything default to little endian, and have wrapper
>> types that do big endian which require expicit construction, similar to
>> RelaxedMmio in Alex's series.
>
> Ah yes, the RelaxedMmio pattern is definitely a good one. I agree that we
> should head in this direction.

I strongly disagree.

This is a great pattern for relaxed ordering because:

  (1) We need both strict and relaxed ordering.

  (2) Relaxed ordering is rare, hence it doesn't hurt to write e.g.

	io.relaxed().write()

  (3) If you by accident just write

	io.write()

      i.e. forget to call relaxed() it s not a bug, nothing bad happens.

Whereas for endianness it is a bad pattern because:

  (1) Devices are either little-endian or big-endian. Hence, having to write

	io.big_endian().write()

      is excessive, we always want big-endian for a big-endian device.

  (2) It is error prone, if you forget to call big_endian() first, it is a bug.

  (3) It is unergonomic in combination with relaxed ordering.

	io.big_endian().relaxed().write()

      (Does the other way around work as well? :)

It makes much more sense to define once when we request the I/O memory whether
the device is litte-endian or big-endian.

This could be done with different request functions, a const generic or a
function argument, but it should be done at request time.

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 19:05           ` Danilo Krummrich
@ 2026-02-05 21:20             ` Link Mauve
  2026-02-05 22:11               ` Danilo Krummrich
  2026-02-05 22:31             ` Gary Guo
  1 sibling, 1 reply; 23+ messages in thread
From: Link Mauve @ 2026-02-05 21:20 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Daniel Almeida, Gary Guo, Link Mauve, rust-for-linux,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Srinivas Kandagatla, Miguel Ojeda,
	Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Ard Biesheuvel, Martin K. Petersen,
	Eric Biggers, Greg Kroah-Hartman, Lyude Paul, Asahi Lina,
	Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori,
	linuxppc-dev, linux-kernel, officialTechflashYT, Ash Logan,
	Roberto Van Eeden, Jonathan Neuschäfer

On Thu, Feb 05, 2026 at 08:05:08PM +0100, Danilo Krummrich wrote:
> On Thu Feb 5, 2026 at 6:28 PM CET, Daniel Almeida wrote:
> >> On 5 Feb 2026, at 12:16, Gary Guo <gary@garyguo.net> wrote:
> >> I think we should have everything default to little endian, and have wrapper
> >> types that do big endian which require expicit construction, similar to
> >> RelaxedMmio in Alex's series.
> >
> > Ah yes, the RelaxedMmio pattern is definitely a good one. I agree that we
> > should head in this direction.
> 
> I strongly disagree.
> 
> This is a great pattern for relaxed ordering because:
> 
>   (1) We need both strict and relaxed ordering.
> 
>   (2) Relaxed ordering is rare, hence it doesn't hurt to write e.g.
> 
> 	io.relaxed().write()
> 
>   (3) If you by accident just write
> 
> 	io.write()
> 
>       i.e. forget to call relaxed() it s not a bug, nothing bad happens.
> 
> Whereas for endianness it is a bad pattern because:
> 
>   (1) Devices are either little-endian or big-endian. Hence, having to write
> 
> 	io.big_endian().write()
> 
>       is excessive, we always want big-endian for a big-endian device.
> 
>   (2) It is error prone, if you forget to call big_endian() first, it is a bug.
> 
>   (3) It is unergonomic in combination with relaxed ordering.
> 
> 	io.big_endian().relaxed().write()
> 
>       (Does the other way around work as well? :)
> 
> It makes much more sense to define once when we request the I/O memory whether
> the device is litte-endian or big-endian.
> 
> This could be done with different request functions, a const generic or a
> function argument, but it should be done at request time.

Could this ever be done in the device tree?  I understand this would
mean having to change all drivers and all device trees that do big
endian, but it seems to be the natural location for this information.  I
have no idea how to structure that though.

-- 
Link Mauve

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 21:20             ` Link Mauve
@ 2026-02-05 22:11               ` Danilo Krummrich
  0 siblings, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:11 UTC (permalink / raw)
  To: Link Mauve
  Cc: Daniel Almeida, Gary Guo, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

(Cc: Rob, Saravana)

On Thu Feb 5, 2026 at 10:20 PM CET, Link Mauve wrote:
> On Thu, Feb 05, 2026 at 08:05:08PM +0100, Danilo Krummrich wrote:
>> On Thu Feb 5, 2026 at 6:28 PM CET, Daniel Almeida wrote:
>> >> On 5 Feb 2026, at 12:16, Gary Guo <gary@garyguo.net> wrote:
>> >> I think we should have everything default to little endian, and have wrapper
>> >> types that do big endian which require expicit construction, similar to
>> >> RelaxedMmio in Alex's series.
>> >
>> > Ah yes, the RelaxedMmio pattern is definitely a good one. I agree that we
>> > should head in this direction.
>> 
>> I strongly disagree.
>> 
>> This is a great pattern for relaxed ordering because:
>> 
>>   (1) We need both strict and relaxed ordering.
>> 
>>   (2) Relaxed ordering is rare, hence it doesn't hurt to write e.g.
>> 
>> 	io.relaxed().write()
>> 
>>   (3) If you by accident just write
>> 
>> 	io.write()
>> 
>>       i.e. forget to call relaxed() it s not a bug, nothing bad happens.
>> 
>> Whereas for endianness it is a bad pattern because:
>> 
>>   (1) Devices are either little-endian or big-endian. Hence, having to write
>> 
>> 	io.big_endian().write()
>> 
>>       is excessive, we always want big-endian for a big-endian device.
>> 
>>   (2) It is error prone, if you forget to call big_endian() first, it is a bug.
>> 
>>   (3) It is unergonomic in combination with relaxed ordering.
>> 
>> 	io.big_endian().relaxed().write()
>> 
>>       (Does the other way around work as well? :)
>> 
>> It makes much more sense to define once when we request the I/O memory whether
>> the device is litte-endian or big-endian.
>> 
>> This could be done with different request functions, a const generic or a
>> function argument, but it should be done at request time.
>
> Could this ever be done in the device tree?  I understand this would
> mean having to change all drivers and all device trees that do big
> endian, but it seems to be the natural location for this information.  I
> have no idea how to structure that though.

I think that's a good idea, for newly supported devices we could probably do
that. For existing ones that might not work. IIRC, there is an expectation that
driver should still work with older device trees.

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 19:05           ` Danilo Krummrich
  2026-02-05 21:20             ` Link Mauve
@ 2026-02-05 22:31             ` Gary Guo
  2026-02-05 22:43               ` Danilo Krummrich
  2026-02-05 22:46               ` Danilo Krummrich
  1 sibling, 2 replies; 23+ messages in thread
From: Gary Guo @ 2026-02-05 22:31 UTC (permalink / raw)
  To: Danilo Krummrich, Daniel Almeida
  Cc: Gary Guo, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 7:05 PM GMT, Danilo Krummrich wrote:
> On Thu Feb 5, 2026 at 6:28 PM CET, Daniel Almeida wrote:
>>> On 5 Feb 2026, at 12:16, Gary Guo <gary@garyguo.net> wrote:
>>> I think we should have everything default to little endian, and have wrapper
>>> types that do big endian which require expicit construction, similar to
>>> RelaxedMmio in Alex's series.
>>
>> Ah yes, the RelaxedMmio pattern is definitely a good one. I agree that we
>> should head in this direction.
>
> I strongly disagree.
>
> This is a great pattern for relaxed ordering because:
>
>   (1) We need both strict and relaxed ordering.
>
>   (2) Relaxed ordering is rare, hence it doesn't hurt to write e.g.
>
> 	io.relaxed().write()
>
>   (3) If you by accident just write
>
> 	io.write()
>
>       i.e. forget to call relaxed() it s not a bug, nothing bad happens.
>
> Whereas for endianness it is a bad pattern because:
>
>   (1) Devices are either little-endian or big-endian. Hence, having to write
>
> 	io.big_endian().write()
>
>       is excessive, we always want big-endian for a big-endian device.

You don't need to always write this. You just need to do `big_endian()` once
when you obtain the io, and then keep using `BigEndian<Mmio>` instead of just
`Mmio`, and the rest of code is still `.write()`.

I proposed the wrapper type because majority of devices won't need BE support,
so adding complexity to Mmio itself is not ideal. It is also generic, so it can
work with any IO backends, so for example, you can have `BigEndian<Pio>` and
`BigEndian<Mmio>` and you don't need to duplicate your endianness support for
both backends.

>
>   (2) It is error prone, if you forget to call big_endian() first, it is a bug.

Moot point when `big_endian()` is only done once.

>
>   (3) It is unergonomic in combination with relaxed ordering.
>
> 	io.big_endian().relaxed().write()

This might be an issue, as `RelaxedMmio`, unless `BigEndian`, cannot be
implemented as wrapper that just reverse byteorder. Although I am not sure that
we even need that support, given that there's no be_relaxed functions on C side
anyway.

Best,
Gary

>
>       (Does the other way around work as well? :)
>
> It makes much more sense to define once when we request the I/O memory whether
> the device is litte-endian or big-endian.
>
> This could be done with different request functions, a const generic or a
> function argument, but it should be done at request time.


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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 22:31             ` Gary Guo
@ 2026-02-05 22:43               ` Danilo Krummrich
  2026-02-08 17:17                 ` Daniel Almeida
  2026-02-05 22:46               ` Danilo Krummrich
  1 sibling, 1 reply; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:43 UTC (permalink / raw)
  To: Gary Guo
  Cc: Daniel Almeida, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 11:31 PM CET, Gary Guo wrote:
> On Thu Feb 5, 2026 at 7:05 PM GMT, Danilo Krummrich wrote:
>>   (1) Devices are either little-endian or big-endian. Hence, having to write
>>
>> 	io.big_endian().write()
>>
>>       is excessive, we always want big-endian for a big-endian device.
>
> You don't need to always write this. You just need to do `big_endian()` once
> when you obtain the io, and then keep using `BigEndian<Mmio>` instead of just
> `Mmio`, and the rest of code is still `.write()`.

<snip>

>>   (2) It is error prone, if you forget to call big_endian() first, it is a bug.
>
> Moot point when `big_endian()` is only done once.

Well, you need to do it at least once per driver entry point. For DRM IOCTLs for
instance you also have to consider that it is always Devres<Mmio>.

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 22:31             ` Gary Guo
  2026-02-05 22:43               ` Danilo Krummrich
@ 2026-02-05 22:46               ` Danilo Krummrich
  1 sibling, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:46 UTC (permalink / raw)
  To: Gary Guo
  Cc: Daniel Almeida, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Thu Feb 5, 2026 at 11:31 PM CET, Gary Guo wrote:
> I proposed the wrapper type because majority of devices won't need BE support,
> so adding complexity to Mmio itself is not ideal. It is also generic, so it can
> work with any IO backends, so for example, you can have `BigEndian<Pio>` and
> `BigEndian<Mmio>` and you don't need to duplicate your endianness support for
> both backends.

That implies that we swap bytes manually? That would be a waste if the CPU and
device are big-endian.

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-05 22:43               ` Danilo Krummrich
@ 2026-02-08 17:17                 ` Daniel Almeida
  2026-02-08 17:52                   ` Danilo Krummrich
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Almeida @ 2026-02-08 17:17 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Gary Guo, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer



> On 5 Feb 2026, at 19:43, Danilo Krummrich <dakr@kernel.org> wrote:
> 
> On Thu Feb 5, 2026 at 11:31 PM CET, Gary Guo wrote:
>> On Thu Feb 5, 2026 at 7:05 PM GMT, Danilo Krummrich wrote:
>>>  (1) Devices are either little-endian or big-endian. Hence, having to write
>>> 
>>> io.big_endian().write()
>>> 
>>>      is excessive, we always want big-endian for a big-endian device.
>> 
>> You don't need to always write this. You just need to do `big_endian()` once
>> when you obtain the io, and then keep using `BigEndian<Mmio>` instead of just
>> `Mmio`, and the rest of code is still `.write()`.
> 
> <snip>
> 
>>>  (2) It is error prone, if you forget to call big_endian() first, it is a bug.
>> 
>> Moot point when `big_endian()` is only done once.
> 
> Well, you need to do it at least once per driver entry point. For DRM IOCTLs for
> instance you also have to consider that it is always Devres<Mmio>.
> 

Well, this is also the case for relaxed(). I basically made peace with the fact that

let mmio = mmio.relaxed();
< use mmio >

is going to be a reality per driver entrypoint, unless I misunderstood?

— Daniel

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

* Re: [PATCH v2 1/4] rust: io: Add big-endian read and write functions
  2026-02-08 17:17                 ` Daniel Almeida
@ 2026-02-08 17:52                   ` Danilo Krummrich
  0 siblings, 0 replies; 23+ messages in thread
From: Danilo Krummrich @ 2026-02-08 17:52 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Gary Guo, Link Mauve, rust-for-linux, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Srinivas Kandagatla, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Ard Biesheuvel, Martin K. Petersen, Eric Biggers,
	Greg Kroah-Hartman, Lyude Paul, Asahi Lina, Viresh Kumar,
	Lorenzo Stoakes, Tamir Duberstein, FUJITA Tomonori, linuxppc-dev,
	linux-kernel, officialTechflashYT, Ash Logan, Roberto Van Eeden,
	Jonathan Neuschäfer

On Sun Feb 8, 2026 at 6:17 PM CET, Daniel Almeida wrote:
>
>
>> On 5 Feb 2026, at 19:43, Danilo Krummrich <dakr@kernel.org> wrote:
>> 
>> On Thu Feb 5, 2026 at 11:31 PM CET, Gary Guo wrote:
>>> On Thu Feb 5, 2026 at 7:05 PM GMT, Danilo Krummrich wrote:
>>>>  (1) Devices are either little-endian or big-endian. Hence, having to write
>>>> 
>>>> io.big_endian().write()
>>>> 
>>>>      is excessive, we always want big-endian for a big-endian device.
>>> 
>>> You don't need to always write this. You just need to do `big_endian()` once
>>> when you obtain the io, and then keep using `BigEndian<Mmio>` instead of just
>>> `Mmio`, and the rest of code is still `.write()`.
>> 
>> <snip>
>> 
>>>>  (2) It is error prone, if you forget to call big_endian() first, it is a bug.
>>> 
>>> Moot point when `big_endian()` is only done once.
>> 
>> Well, you need to do it at least once per driver entry point. For DRM IOCTLs for
>> instance you also have to consider that it is always Devres<Mmio>.
>> 
>
> Well, this is also the case for relaxed(). I basically made peace with the fact that
>
> let mmio = mmio.relaxed();
> < use mmio >
>
> is going to be a reality per driver entrypoint, unless I misunderstood?

Well, there are two differences: Firstly, relaxed ordering should only be
possible in certain situations, but not always and not for every driver entry
point. Secondly, if you mistakenly forget it, you may suffer from a pretty
slight performance hit, but it is not going to be a bug.

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

* Re: [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one
  2026-02-04  4:05 ` [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one Link Mauve
@ 2026-03-04 18:46   ` Link Mauve
  0 siblings, 0 replies; 23+ messages in thread
From: Link Mauve @ 2026-03-04 18:46 UTC (permalink / raw)
  To: Link Mauve
  Cc: rust-for-linux, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Srinivas Kandagatla,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Ard Biesheuvel,
	Martin K. Petersen, Eric Biggers, Greg Kroah-Hartman, Lyude Paul,
	Asahi Lina, Viresh Kumar, Lorenzo Stoakes, Tamir Duberstein,
	FUJITA Tomonori, linuxppc-dev, linux-kernel, officialTechflashYT,
	Ash Logan, Roberto Van Eeden, Jonathan Neuschäfer

Hi,

I’m working on a v3 of this series atm.

On Wed, Feb 04, 2026 at 05:05:00AM +0100, Link Mauve wrote:
> I wrote this driver long ago, and wanted to try seeing how hard it would
> be to convert it to Rust.
> 
> It is a very simple driver, we write the address we want to read in one
> memory address, and read the data from a second memory address.  A third
> memory address can be used to disable all reads in a range until the
> system has been rebooted, but I didn’t find any reason to expose that
> feature.
> 
> I made sure to use no unsafe in this driver, to make sure the API
> exposed in the previous commit is usable.
> 
> Ideally we wouldn’t have to impl the write() function in
> NintendoOtpProvider, but currently the vtable requires both.
> 
> I have tested this driver only on a Wii so far, but I assume it will
> work the same on a Wii U, just exposing more memory banks.
> 
> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
> ---
>  drivers/nvmem/Kconfig         |   1 +
>  drivers/nvmem/Makefile        |   2 +-
>  drivers/nvmem/nintendo-otp.c  | 122 --------------------------------
>  drivers/nvmem/nintendo_otp.rs | 127 ++++++++++++++++++++++++++++++++++
>  4 files changed, 129 insertions(+), 123 deletions(-)
>  delete mode 100644 drivers/nvmem/nintendo-otp.c
>  create mode 100644 drivers/nvmem/nintendo_otp.rs

Should I make it a Rust reference driver[1] and keep the C version, or
is replacing the C driver like I’m doing here okay?  Ideally I would
only maintain the Rust version in the end, but I’m fine with maintaining
both for the time being, until we have everything sorted out.

[1] https://rust-for-linux.com/rust-reference-drivers

-- 
Link Mauve

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

end of thread, other threads:[~2026-03-04 18:54 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-04  4:04 [PATCH v2 0/4] Add Rust abstractions for nvmem-provider Link Mauve
2026-02-04  4:04 ` [PATCH v2 1/4] rust: io: Add big-endian read and write functions Link Mauve
2026-02-04 15:18   ` Danilo Krummrich
2026-02-04 15:20     ` Danilo Krummrich
2026-02-05 14:28     ` Daniel Almeida
2026-02-05 14:56       ` Danilo Krummrich
2026-02-05 15:16       ` Gary Guo
2026-02-05 17:28         ` Daniel Almeida
2026-02-05 19:05           ` Danilo Krummrich
2026-02-05 21:20             ` Link Mauve
2026-02-05 22:11               ` Danilo Krummrich
2026-02-05 22:31             ` Gary Guo
2026-02-05 22:43               ` Danilo Krummrich
2026-02-08 17:17                 ` Daniel Almeida
2026-02-08 17:52                   ` Danilo Krummrich
2026-02-05 22:46               ` Danilo Krummrich
2026-02-04  4:04 ` [PATCH v2 2/4] rust: nvmem: Add an abstraction for nvmem providers Link Mauve
2026-02-04 15:22   ` Danilo Krummrich
2026-02-05 12:48     ` Link Mauve
2026-02-05 12:57       ` Danilo Krummrich
2026-02-04  4:05 ` [PATCH v2 3/4] nvmem: Replace the Wii and Wii U OTP driver with a Rust one Link Mauve
2026-03-04 18:46   ` Link Mauve
2026-02-04  4:05 ` [PATCH v2 4/4] powerpc: wii_defconfig: Enable Rust Link Mauve

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