From nobody Fri Oct 2 01:56:25 2026 Received: from linkmauve.fr (linkmauve.fr [82.65.109.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 729443DB310; Thu, 6 Aug 2026 06:22:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.65.109.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785997333; cv=none; b=Lgt4o/7TYgi5+jOJX/BvTG+PpAhdbJZlu0QtowIGfOT+psLDh9X/WoJc13/7RBXoCIYKOQqc6EpTo8+KTrb8yUhF60GRVjFCWGlW7Z1WqcOJMn/n4WFn4Sv65PjI2Lqwq3f9frghCImPmn+uR7RYozRReUYG+89xabIqnnBjuuM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785997333; c=relaxed/simple; bh=/4VEb4lu7jJv1J2369j6uGurfX24GvQlqc0cDhlc6pI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=LT3RpczF24rS2IsAO446YrzLWFa2EfE+B6IJwg6x2d4MiVinGpBUinOpuXTI0ytzjuYczNVO5lMsVP4DxGPJlAQ8VunA93PWm0uOoOGA6Igjx/dNy8uKHa+jOwUjCVWBhonISG9tRR8LH9sH+Yj2e4Zt3I+PQAoKh5ffLjU9zUI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linkmauve.fr; spf=pass smtp.mailfrom=linkmauve.fr; arc=none smtp.client-ip=82.65.109.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linkmauve.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linkmauve.fr Received: by linkmauve.fr (Postfix, from userid 1000) id BF80270A28AC; Thu, 06 Aug 2026 08:22:08 +0200 (CEST) From: Link Mauve To: rust-for-linux@vger.kernel.org Cc: Link Mauve , Ethan Plant , Michael Garofalo , Ash Logan , =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= , Sasha Finkelstein , Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?UTF-8?q?Onur=20=C3=96zkan?= , linux-kernel@vger.kernel.org, driver-core@lists.linux.dev Subject: [PATCH v2] rust: io: Add a BigEndianMmio wrapper Date: Thu, 6 Aug 2026 08:22:04 +0200 Message-ID: <20260806062207.3024012-1-linkmauve@linkmauve.fr> X-Mailer: git-send-email 2.55.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Link Mauve --- 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.2443151507074= 972963.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 valu= e, void __iomem *addr) } #endif =20 +__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 *r= es) { 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>) -> $t= y { // SAFETY: `$backend::as_ptr(view)` is a valid pointer for= MMIO operations for both - // `MmioBackend` and `RelaxedMmioBackend`. + // `MmioBackend`, `RelaxedMmioBackend` and `BigEndianMmioB= ackend`. unsafe { bindings::$read_fn($backend::as_ptr(view).cast_co= nst().cast()) } } =20 #[inline] fn io_write(view: <$backend as IoBackend>::View<'_, $ty>, valu= e: $ty) { // SAFETY: `$backend::as_ptr(view)` is a valid pointer for= MMIO operations for both - // `MmioBackend` and `RelaxedMmioBackend`. + // `MmioBackend`, `RelaxedMmioBackend` and `BigEndianMmioB= ackend`. 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 Copy for BigEndianMmio<'_, T> {} +impl 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> =3D 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 + KnownSiz= e>( + 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 =3D BigEndianMmioBackend; + type Target =3D 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 o= rder. + /// + /// # 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 `read= l`. + /// let v =3D 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 --=20 2.55.0