Re: [PATCH v2] rust: io: Add a BigEndianMmio wrapper
"Gary Guo" <[email protected]> Thu, 06 Aug 2026 12:44:31 +0100
| Newsgroups | org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Thu Aug 6, 2026 at 7:22 AM BST, Link Mauve wrote: > This allows the user to read from and write to big-endian MMIO devices, > such as those found on PowerPC systems. > > The implementation is pretty much a copy-paste of the RelaxedMmio type, > with the business logic changed. > > This has been tested with various WIP drivers on the Nintendo Wii, and I > thought it would be nicer to upstream it before those are completely > ready, to get some review. An alternative approach would be to have a generic wrapper `BigEndian<IO>` where it performs byte-swapping in its `IoCapable` implementation. This is more composable as it works for all I/O. Of course, this means that it won't be using the specialized BE I/O impl, but then the only architectures that have specialized ioread16be are PPC32 and SPARC, so maybe it's a reasonable trade-off to make? Best, Gary > > Signed-off-by: Link Mauve <[email protected]> > --- > rust/helpers/io.c | 34 ++++++++++++++++++ > rust/kernel/io.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 120 insertions(+), 2 deletions(-) > > Changes since v1: > - Link to v1: > https://lore.kernel.org/rust-for-linux/178598049138.1212746.2443151507074972963.b4-review@b4/T/ > - Fix copy/paste mistake in backend docstring (thank you Ethan Plant!) > - Fix safety comment in macro documentation. > > diff --git a/rust/helpers/io.c b/rust/helpers/io.c > index 7ed9a4f77f1b..3bbb86a00d67 100644 > --- a/rust/helpers/io.c > +++ b/rust/helpers/io.c > @@ -120,6 +120,40 @@ __rust_helper void rust_helper_writeq_relaxed(u64 value, void __iomem *addr) > } > #endif > > +__rust_helper u16 rust_helper_ioread16be(const void __iomem *addr) > +{ > + return ioread16be(addr); > +} > + > +__rust_helper u32 rust_helper_ioread32be(const void __iomem *addr) > +{ > + return ioread32be(addr); > +} > + > +#ifdef CONFIG_64BIT > +__rust_helper u64 rust_helper_ioread64be(const void __iomem *addr) > +{ > + return ioread64be(addr); > +} > +#endif > + > +__rust_helper void rust_helper_iowrite16be(u16 value, void __iomem *addr) > +{ > + iowrite16be(value, addr); > +} > + > +__rust_helper void rust_helper_iowrite32be(u32 value, void __iomem *addr) > +{ > + iowrite32be(value, addr); > +} > + > +#ifdef CONFIG_64BIT > +__rust_helper void rust_helper_iowrite64be(u64 value, void __iomem *addr) > +{ > + iowrite64be(value, addr); > +} > +#endif > + > __rust_helper resource_size_t rust_helper_resource_size(struct resource *res) > { > return resource_size(res); > diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs > index a38c20ba3d23..ab8b7864298a 100644 > --- a/rust/kernel/io.rs > +++ b/rust/kernel/io.rs > @@ -1194,14 +1194,14 @@ impl IoCapable<$ty> for $backend { > #[inline] > fn io_read(view: <$backend as IoBackend>::View<'_, $ty>) -> $ty { > // SAFETY: `$backend::as_ptr(view)` is a valid pointer for MMIO operations for both > - // `MmioBackend` and `RelaxedMmioBackend`. > + // `MmioBackend`, `RelaxedMmioBackend` and `BigEndianMmioBackend`. > unsafe { bindings::$read_fn($backend::as_ptr(view).cast_const().cast()) } > } > > #[inline] > fn io_write(view: <$backend as IoBackend>::View<'_, $ty>, value: $ty) { > // SAFETY: `$backend::as_ptr(view)` is a valid pointer for MMIO operations for both > - // `MmioBackend` and `RelaxedMmioBackend`. > + // `MmioBackend`, `RelaxedMmioBackend` and `BigEndianMmioBackend`. > unsafe { bindings::$write_fn(value, $backend::as_ptr(view).cast()) } > } > } > @@ -1751,3 +1751,87 @@ macro_rules! io_write { > } > #[doc(inline)] > pub use crate::io_write; > + > +/// [`Mmio`] wrapper using big-endian accessors. > +/// > +/// This type provides an implementation of [`Io`] that uses big-endian I/O MMIO operands instead of > +/// the regular little-endian ones. > +/// > +/// See [`Mmio::big_endian`] for a usage example. > +#[repr(transparent)] > +pub struct BigEndianMmio<'a, T: ?Sized>(Mmio<'a, T>); > + > +impl<T: ?Sized> Copy for BigEndianMmio<'_, T> {} > +impl<T: ?Sized> Clone for BigEndianMmio<'_, T> { > + #[inline] > + fn clone(&self) -> Self { > + *self > + } > +} > + > +/// I/O Backend for memory-mapped I/O using big-endian accessors. > +pub struct BigEndianMmioBackend; > + > +impl IoBackend for BigEndianMmioBackend { > + type View<'a, T: ?Sized + KnownSize> = BigEndianMmio<'a, T>; > + > + #[inline] > + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T { > + MmioBackend::as_ptr(view.0) > + } > + > + #[inline] > + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>( > + view: Self::View<'a, T>, > + ptr: *mut U, > + ) -> Self::View<'a, U> { > + // SAFETY: Per safety requirement. > + BigEndianMmio(unsafe { MmioBackend::project_view(view.0, ptr) }) > + } > +} > + > +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for BigEndianMmio<'a, T> { > + type Backend = BigEndianMmioBackend; > + type Target = T; > + > + #[inline] > + fn as_view(self) -> BigEndianMmio<'a, T> { > + self > + } > +} > + > +impl<'a, T: ?Sized> Mmio<'a, T> { > + /// Returns a [`BigEndianMmio`] reference that performs big-endian I/O operations. > + /// > + /// Big-endian makes no change to 8-bit accesses, but will invert the bytes of 16-, 32- and > + /// 64-bit accesses, to ensure numbers will be read in their correct order. > + /// > + /// # Examples > + /// > + /// ```no_run > + /// use kernel::io::{ > + /// Io, > + /// Mmio, > + /// Region, > + /// BigEndianMmio, > + /// }; > + /// > + /// fn do_io(io: Mmio<'_, Region<0x100>>) { > + /// // The access is performed using `ioread32be` instead of `readl`. > + /// let v = io.big_endian().read32(0x10); > + /// } > + /// > + /// ``` > + #[inline] > + pub fn big_endian(self) -> BigEndianMmio<'a, T> { > + BigEndianMmio(self) > + } > +} > + > +// MMIO regions support 8, 16, and 32-bit accesses. > +impl_mmio_io_capable!(BigEndianMmioBackend, u8, readb, writeb); > +impl_mmio_io_capable!(BigEndianMmioBackend, u16, ioread16be, iowrite16be); > +impl_mmio_io_capable!(BigEndianMmioBackend, u32, ioread32be, iowrite32be); > +// MMIO regions on 64-bit systems also support 64-bit accesses. > +#[cfg(CONFIG_64BIT)] > +impl_mmio_io_capable!(BigEndianMmioBackend, u64, ioread64be, iowrite64be); > > base-commit: 1701fda2f58e345c050f4309971bdc07cd6146ba