[PATCH] rust: io: macro_export io_define_read!() and io_define_write!()
From: Danilo Krummrich
Date: Mon Feb 16 2026 - 08:16:14 EST
Currently, the define_read!() and define_write!() I/O macros are crate
public. The only user outside of the I/O module is PCI (for the
configurations space I/O backend). Consequently, when CONFIG_PCI=n this
causes a compile time warning [1].
In order to fix this, rename the macros to io_define_read!() and
io_define_write!() and use #[macro_export] to export them.
This is better than making the crate public visibility conditional, as
eventually subsystems will have their own crate.
Also, I/O backends are valid to be implemented by drivers as well. For
instance, there are devices (such as GPUs) that run firmware which
allows to program other devices only accessible through the primary
device through indirect I/O.
Since the macros are now public, also add the corresponding
documentation.
Fixes: 121d87b28e1d ("rust: io: separate generic I/O helpers from MMIO implementation")
Reported-by: Miguel Ojeda <miguel.ojeda.sandonis@xxxxxxxxx>
Closes: https://lore.kernel.org/driver-core/CANiq72khOYkt6t5zwMvSiyZvWWHMZuNCMERXu=7K=_5tT-8Pgg@xxxxxxxxxxxxxx/ [1]
Signed-off-by: Danilo Krummrich <dakr@xxxxxxxxxx>
---
rust/kernel/io.rs | 129 ++++++++++++++++++++++++++++--------------
rust/kernel/pci/io.rs | 24 ++++----
2 files changed, 99 insertions(+), 54 deletions(-)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index c1cca7b438c3..58f464cf5efd 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -139,9 +139,9 @@ pub fn maxsize(&self) -> usize {
/// Internal helper macros used to invoke C MMIO read functions.
///
-/// This macro is intended to be used by higher-level MMIO access macros (define_read) and provides
-/// a unified expansion for infallible vs. fallible read semantics. It emits a direct call into the
-/// corresponding C helper and performs the required cast to the Rust return type.
+/// This macro is intended to be used by higher-level MMIO access macros (io_define_read) and
+/// provides a unified expansion for infallible vs. fallible read semantics. It emits a direct call
+/// into the corresponding C helper and performs the required cast to the Rust return type.
///
/// # Parameters
///
@@ -166,9 +166,9 @@ macro_rules! call_mmio_read {
/// Internal helper macros used to invoke C MMIO write functions.
///
-/// This macro is intended to be used by higher-level MMIO access macros (define_write) and provides
-/// a unified expansion for infallible vs. fallible write semantics. It emits a direct call into the
-/// corresponding C helper and performs the required cast to the Rust return type.
+/// This macro is intended to be used by higher-level MMIO access macros (io_define_write) and
+/// provides a unified expansion for infallible vs. fallible write semantics. It emits a direct call
+/// into the corresponding C helper and performs the required cast to the Rust return type.
///
/// # Parameters
///
@@ -193,7 +193,30 @@ macro_rules! call_mmio_write {
}};
}
-macro_rules! define_read {
+/// Generates an accessor method for reading from an I/O backend.
+///
+/// This macro reduces boilerplate by automatically generating either compile-time bounds-checked
+/// (infallible) or runtime bounds-checked (fallible) read methods. It abstracts the address
+/// calculation and bounds checking, and delegates the actual I/O read operation to a specified
+/// helper macro, making it generic over different I/O backends.
+///
+/// # Parameters
+///
+/// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on
+/// `IoKnownSize` for compile-time checks and returns the value directly. `fallible` performs
+/// runtime checks against `maxsize()` and returns a `Result<T>`.
+/// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g.,
+/// `#[cfg(CONFIG_64BIT)]` or inline directives).
+/// * `$vis:vis` - The visibility of the generated method (e.g., `pub`).
+/// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `read32`,
+/// `try_read8`).
+/// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call
+/// (e.g., `call_mmio_read`).
+/// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the
+/// `$call_macro`.
+/// * `$type_name:ty` - The Rust type of the value being read (e.g., `u8`, `u32`).
+#[macro_export]
+macro_rules! io_define_read {
(infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) ->
$type_name:ty) => {
/// Read IO data from a given offset known at compile time.
@@ -226,9 +249,32 @@ macro_rules! define_read {
}
};
}
-pub(crate) use define_read;
-macro_rules! define_write {
+/// Generates an accessor method for writing to an I/O backend.
+///
+/// This macro reduces boilerplate by automatically generating either compile-time bounds-checked
+/// (infallible) or runtime bounds-checked (fallible) write methods. It abstracts the address
+/// calculation and bounds checking, and delegates the actual I/O write operation to a specified
+/// helper macro, making it generic over different I/O backends.
+///
+/// # Parameters
+///
+/// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on
+/// `IoKnownSize` for compile-time checks and returns `()`. `fallible` performs runtime checks
+/// against `maxsize()` and returns a `Result`.
+/// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g.,
+/// `#[cfg(CONFIG_64BIT)]` or inline directives).
+/// * `$vis:vis` - The visibility of the generated method (e.g., `pub`).
+/// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `write32`,
+/// `try_write8`).
+/// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call
+/// (e.g., `call_mmio_write`).
+/// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the
+/// `$call_macro`.
+/// * `$type_name:ty` - The Rust type of the value being written (e.g., `u8`, `u32`). Note the use
+/// of `<-` before the type to denote a write operation.
+#[macro_export]
+macro_rules! io_define_write {
(infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) <-
$type_name:ty) => {
/// Write IO data from a given offset known at compile time.
@@ -259,7 +305,6 @@ macro_rules! define_write {
}
};
}
-pub(crate) use define_write;
/// Checks whether an access of type `U` at the given `offset`
/// is valid within this region.
@@ -509,40 +554,40 @@ fn maxsize(&self) -> usize {
self.0.maxsize()
}
- define_read!(fallible, try_read8, call_mmio_read(readb) -> u8);
- define_read!(fallible, try_read16, call_mmio_read(readw) -> u16);
- define_read!(fallible, try_read32, call_mmio_read(readl) -> u32);
- define_read!(
+ io_define_read!(fallible, try_read8, call_mmio_read(readb) -> u8);
+ io_define_read!(fallible, try_read16, call_mmio_read(readw) -> u16);
+ io_define_read!(fallible, try_read32, call_mmio_read(readl) -> u32);
+ io_define_read!(
fallible,
#[cfg(CONFIG_64BIT)]
try_read64,
call_mmio_read(readq) -> u64
);
- define_write!(fallible, try_write8, call_mmio_write(writeb) <- u8);
- define_write!(fallible, try_write16, call_mmio_write(writew) <- u16);
- define_write!(fallible, try_write32, call_mmio_write(writel) <- u32);
- define_write!(
+ io_define_write!(fallible, try_write8, call_mmio_write(writeb) <- u8);
+ io_define_write!(fallible, try_write16, call_mmio_write(writew) <- u16);
+ io_define_write!(fallible, try_write32, call_mmio_write(writel) <- u32);
+ io_define_write!(
fallible,
#[cfg(CONFIG_64BIT)]
try_write64,
call_mmio_write(writeq) <- u64
);
- define_read!(infallible, read8, call_mmio_read(readb) -> u8);
- define_read!(infallible, read16, call_mmio_read(readw) -> u16);
- define_read!(infallible, read32, call_mmio_read(readl) -> u32);
- define_read!(
+ io_define_read!(infallible, read8, call_mmio_read(readb) -> u8);
+ io_define_read!(infallible, read16, call_mmio_read(readw) -> u16);
+ io_define_read!(infallible, read32, call_mmio_read(readl) -> u32);
+ io_define_read!(
infallible,
#[cfg(CONFIG_64BIT)]
read64,
call_mmio_read(readq) -> u64
);
- define_write!(infallible, write8, call_mmio_write(writeb) <- u8);
- define_write!(infallible, write16, call_mmio_write(writew) <- u16);
- define_write!(infallible, write32, call_mmio_write(writel) <- u32);
- define_write!(
+ io_define_write!(infallible, write8, call_mmio_write(writeb) <- u8);
+ io_define_write!(infallible, write16, call_mmio_write(writew) <- u16);
+ io_define_write!(infallible, write32, call_mmio_write(writel) <- u32);
+ io_define_write!(
infallible,
#[cfg(CONFIG_64BIT)]
write64,
@@ -566,40 +611,40 @@ pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self {
unsafe { &*core::ptr::from_ref(raw).cast() }
}
- define_read!(infallible, pub read8_relaxed, call_mmio_read(readb_relaxed) -> u8);
- define_read!(infallible, pub read16_relaxed, call_mmio_read(readw_relaxed) -> u16);
- define_read!(infallible, pub read32_relaxed, call_mmio_read(readl_relaxed) -> u32);
- define_read!(
+ io_define_read!(infallible, pub read8_relaxed, call_mmio_read(readb_relaxed) -> u8);
+ io_define_read!(infallible, pub read16_relaxed, call_mmio_read(readw_relaxed) -> u16);
+ io_define_read!(infallible, pub read32_relaxed, call_mmio_read(readl_relaxed) -> u32);
+ io_define_read!(
infallible,
#[cfg(CONFIG_64BIT)]
pub read64_relaxed,
call_mmio_read(readq_relaxed) -> u64
);
- define_read!(fallible, pub try_read8_relaxed, call_mmio_read(readb_relaxed) -> u8);
- define_read!(fallible, pub try_read16_relaxed, call_mmio_read(readw_relaxed) -> u16);
- define_read!(fallible, pub try_read32_relaxed, call_mmio_read(readl_relaxed) -> u32);
- define_read!(
+ io_define_read!(fallible, pub try_read8_relaxed, call_mmio_read(readb_relaxed) -> u8);
+ io_define_read!(fallible, pub try_read16_relaxed, call_mmio_read(readw_relaxed) -> u16);
+ io_define_read!(fallible, pub try_read32_relaxed, call_mmio_read(readl_relaxed) -> u32);
+ io_define_read!(
fallible,
#[cfg(CONFIG_64BIT)]
pub try_read64_relaxed,
call_mmio_read(readq_relaxed) -> u64
);
- define_write!(infallible, pub write8_relaxed, call_mmio_write(writeb_relaxed) <- u8);
- define_write!(infallible, pub write16_relaxed, call_mmio_write(writew_relaxed) <- u16);
- define_write!(infallible, pub write32_relaxed, call_mmio_write(writel_relaxed) <- u32);
- define_write!(
+ io_define_write!(infallible, pub write8_relaxed, call_mmio_write(writeb_relaxed) <- u8);
+ io_define_write!(infallible, pub write16_relaxed, call_mmio_write(writew_relaxed) <- u16);
+ io_define_write!(infallible, pub write32_relaxed, call_mmio_write(writel_relaxed) <- u32);
+ io_define_write!(
infallible,
#[cfg(CONFIG_64BIT)]
pub write64_relaxed,
call_mmio_write(writeq_relaxed) <- u64
);
- define_write!(fallible, pub try_write8_relaxed, call_mmio_write(writeb_relaxed) <- u8);
- define_write!(fallible, pub try_write16_relaxed, call_mmio_write(writew_relaxed) <- u16);
- define_write!(fallible, pub try_write32_relaxed, call_mmio_write(writel_relaxed) <- u32);
- define_write!(
+ io_define_write!(fallible, pub try_write8_relaxed, call_mmio_write(writeb_relaxed) <- u8);
+ io_define_write!(fallible, pub try_write16_relaxed, call_mmio_write(writew_relaxed) <- u16);
+ io_define_write!(fallible, pub try_write32_relaxed, call_mmio_write(writel_relaxed) <- u32);
+ io_define_write!(
fallible,
#[cfg(CONFIG_64BIT)]
pub try_write64_relaxed,
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index 6ca4cf75594c..2c8d7d00e54d 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -8,14 +8,14 @@
device,
devres::Devres,
io::{
- define_read,
- define_write,
Io,
IoCapable,
IoKnownSize,
Mmio,
MmioRaw, //
},
+ io_define_read,
+ io_define_write,
prelude::*,
sync::aref::ARef, //
};
@@ -88,7 +88,7 @@ pub struct ConfigSpace<'a, S: ConfigSpaceKind = Extended> {
/// Internal helper macros used to invoke C PCI configuration space read functions.
///
/// This macro is intended to be used by higher-level PCI configuration space access macros
-/// (define_read) and provides a unified expansion for infallible vs. fallible read semantics. It
+/// (io_define_read) and provides a unified expansion for infallible vs. fallible read semantics. It
/// emits a direct call into the corresponding C helper and performs the required cast to the Rust
/// return type.
///
@@ -117,9 +117,9 @@ macro_rules! call_config_read {
/// Internal helper macros used to invoke C PCI configuration space write functions.
///
/// This macro is intended to be used by higher-level PCI configuration space access macros
-/// (define_write) and provides a unified expansion for infallible vs. fallible read semantics. It
-/// emits a direct call into the corresponding C helper and performs the required cast to the Rust
-/// return type.
+/// (io_define_write) and provides a unified expansion for infallible vs. fallible read semantics.
+/// It emits a direct call into the corresponding C helper and performs the required cast to the
+/// Rust return type.
///
/// # Parameters
///
@@ -163,13 +163,13 @@ fn maxsize(&self) -> usize {
// PCI configuration space does not support fallible operations.
// The default implementations from the Io trait are not used.
- define_read!(infallible, read8, call_config_read(pci_read_config_byte) -> u8);
- define_read!(infallible, read16, call_config_read(pci_read_config_word) -> u16);
- define_read!(infallible, read32, call_config_read(pci_read_config_dword) -> u32);
+ io_define_read!(infallible, read8, call_config_read(pci_read_config_byte) -> u8);
+ io_define_read!(infallible, read16, call_config_read(pci_read_config_word) -> u16);
+ io_define_read!(infallible, read32, call_config_read(pci_read_config_dword) -> u32);
- define_write!(infallible, write8, call_config_write(pci_write_config_byte) <- u8);
- define_write!(infallible, write16, call_config_write(pci_write_config_word) <- u16);
- define_write!(infallible, write32, call_config_write(pci_write_config_dword) <- u32);
+ io_define_write!(infallible, write8, call_config_write(pci_write_config_byte) <- u8);
+ io_define_write!(infallible, write16, call_config_write(pci_write_config_word) <- u16);
+ io_define_write!(infallible, write32, call_config_write(pci_write_config_dword) <- u32);
}
impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> {
base-commit: 0f2acd3148e0ef42bdacbd477f90e8533f96b2ac
--
2.53.0