[PATCH v5 12/20] rust: io: move `Io` methods to extension trait
From: Gary Guo
Date: Fri Jun 26 2026 - 10:50:45 EST
`Io` trait now has a single required methods with many more provided
methods. Provided methods may want to rely on their implementations to not
be arbitrarily overridden by implementers for correctness or soundness.
Thus, extract these methods to a new trait and provide a blanket
implementation. This pattern is used extensively in userspace Rust
libraries e.g. `tokio` where `AsyncRead` has minimum methods and
`AsyncReadExt` is what users mostly interact with.
To avoid changing all user imports, the base trait is renamed to `IoBase`
and the newly added trait takes the existing `Io` name.
A `size` method is added as an example of methods that users should not
override.
Suggested-by: Danilo Krummrich <dakr@xxxxxxxxxx>
Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/kernel/devres.rs | 3 ++-
rust/kernel/io.rs | 34 ++++++++++++++++++++++++----------
rust/kernel/io/mem.rs | 6 +++---
rust/kernel/pci/io.rs | 6 +++---
4 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 3545ffc5345d..6e0b845b229b 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -68,6 +68,7 @@ struct Inner<T> {
/// devres::Devres,
/// io::{
/// Io,
+/// IoBase,
/// Mmio,
/// MmioRaw,
/// MmioBackend,
@@ -105,7 +106,7 @@ struct Inner<T> {
/// }
/// }
///
-/// impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<SIZE> {
+/// impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<SIZE> {
/// type Backend = MmioBackend;
/// type Target = Region<SIZE>;
///
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index adafd273920f..0746b0d209ef 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -223,7 +223,7 @@ fn io_view<'a, IO: Io<'a>, U>(
/// operation.
pub trait IoBackend {
/// View type for this I/O backend.
- type View<'a, T: ?Sized + KnownSize>: Io<'a, Backend = Self, Target = T>;
+ type View<'a, T: ?Sized + KnownSize>: IoBase<'a, Backend = Self, Target = T>;
/// Convert a `view` to a raw pointer for projection.
///
@@ -309,15 +309,12 @@ fn offset(self) -> usize {
/// Types implementing this trait (e.g. MMIO BARs or PCI config regions)
/// can perform I/O operations on regions of memory.
///
-/// The [`Io`] trait provides:
-/// - Method to convert into [`IoBackend::View`].
-/// - Helper methods for offset validation and address calculation
-/// - Fallible (runtime checked) accessors for different data widths
-///
-/// Which I/O methods are available depends on the associated [`IoBackend`] implementation.
+/// This trait defines which backend shall be used for I/O operations and provides a method to
+/// convert into [`IoBackend::View`]. Users should use the [`Io`] trait which provides the actual
+/// methods to perform I/O operations.
///
/// This should be implemented on cheaply copyable handles, such as references or view types.
-pub trait Io<'a>: Copy {
+pub trait IoBase<'a>: Copy {
/// Type that defines all I/O operations.
type Backend: IoBackend;
@@ -326,6 +323,21 @@ pub trait Io<'a>: Copy {
/// Return a view that covers the full region.
fn as_view(self) -> <Self::Backend as IoBackend>::View<'a, Self::Target>;
+}
+
+/// Extension trait to provide I/O operation methods to types that implement [`IoBase`].
+///
+/// This trait provides:
+/// - Helper methods for offset validation and address calculation
+/// - Fallible (runtime checked) accessors for different data widths
+///
+/// Which I/O methods are available depends on the associated [`IoBackend`] implementation.
+pub trait Io<'a>: IoBase<'a> {
+ /// Returns the size of this I/O region.
+ #[inline]
+ fn size(self) -> usize {
+ KnownSize::size(Self::Backend::as_ptr(self.as_view()))
+ }
/// Fallible 8-bit read with runtime bounds check.
#[inline(always)]
@@ -779,6 +791,8 @@ fn update<T, L, F>(self, location: L, f: F)
}
}
+impl<'a, T: IoBase<'a>> Io<'a> for T {}
+
/// A view of memory-mapped I/O region.
///
/// # Invariant
@@ -819,7 +833,7 @@ unsafe impl<T: ?Sized + Sync> Send for Mmio<'_, T> {}
// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory.
unsafe impl<T: ?Sized + Sync> Sync for Mmio<'_, T> {}
-impl<'a, T: ?Sized + KnownSize> Io<'a> for Mmio<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for Mmio<'a, T> {
type Backend = MmioBackend;
type Target = T;
@@ -920,7 +934,7 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
}
}
-impl<'a, T: ?Sized + KnownSize> Io<'a> for RelaxedMmio<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for RelaxedMmio<'a, T> {
type Backend = RelaxedMmioBackend;
type Target = T;
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index d9b3189d09b4..e95b769ebe47 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -14,7 +14,7 @@
Region,
Resource, //
},
- Io,
+ IoBase,
Mmio,
MmioBackend,
MmioRaw, //
@@ -210,7 +210,7 @@ pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a ExclusiveIoMem<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a ExclusiveIoMem<'_, SIZE> {
type Backend = MmioBackend;
type Target = super::Region<SIZE>;
@@ -292,7 +292,7 @@ fn drop(&mut self) {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<'_, SIZE> {
type Backend = MmioBackend;
type Target = super::Region<SIZE>;
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index 4be33ecb4192..4d1d0afdc491 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -8,8 +8,8 @@
device,
devres::Devres,
io::{
- Io,
IoBackend,
+ IoBase,
IoCapable,
Mmio,
MmioBackend,
@@ -144,7 +144,7 @@ fn io_write(view: ConfigSpace<'_, $ty>, value: $ty) {
impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_word);
impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config_dword);
-impl<'a, T: ?Sized + KnownSize> Io<'a> for ConfigSpace<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for ConfigSpace<'a, T> {
type Backend = ConfigSpaceBackend;
type Target = T;
@@ -267,7 +267,7 @@ fn drop(&mut self) {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a Bar<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a Bar<'_, SIZE> {
type Backend = MmioBackend;
type Target = crate::io::Region<SIZE>;
--
2.54.0