summaryrefslogtreecommitdiff
path: root/rust/kernel
diff options
context:
space:
mode:
authorGary Guo <gary@garyguo.net>2026-07-06 13:44:33 +0100
committerDanilo Krummrich <dakr@kernel.org>2026-07-11 18:09:04 +0200
commit11a4784f902ebf3e674dbaf07dbec9a37aabb5e4 (patch)
treecb80d3d4a2dc330adab6bb432bb097aa12ebe651 /rust/kernel
parente7219e53c525db87b43f4a9064d0e6331d7dc710 (diff)
rust: io: implement `IoSysMap`
Add an enum as sum type for `Mmio` and `SysMem`. This serves similar purpose of `iosys_map`. Thanks to Rust's type system, all of projection and struct read/write can be handled by the generic I/O projection mechanism (i.e. `io_project!`, `io_read!, `io_write!`) for free, and there is no need to provide things like `iosys_map_rd_field` or `iosys_map_wr_field`. An enum type also makes it very easy to construct or destruct. This could be made more generic by implementing on a general purpose sum type like `Either`; however this is kept specific unless a need arises that warrants this to be generic over other I/O backends. Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260706-io_projection-v6-20-72cd5d055d54@garyguo.net Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'rust/kernel')
-rw-r--r--rust/kernel/io.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index dbaa88898c3b..95f46bb75f9e 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -1468,6 +1468,143 @@ impl<'a, T: ?Sized + KnownSize> IoBase<'a> for SysMem<'a, T> {
}
}
+/// I/O Backend for [`IoSysMap`].
+pub struct IoSysMapBackend;
+
+/// Either [`Mmio`] or [`SysMem`].
+///
+/// This can be used when a piece of logic may wish to handle both MMIO or system memory but does
+/// not want or cannot be generic over I/O backends. This serves a similar purpose to
+/// [`include/linux/iosys-map.h`] in C.
+///
+/// This type can be used like any other types that implements [`Io`]; this also include
+/// [`io_project!`], [`io_read!`], [`io_write!`].
+///
+/// [`include/linux/iosys-map.h`]: srctree/include/linux/iosys-map.h
+pub enum IoSysMap<'a, T: ?Sized> {
+ /// The view is I/O memory.
+ Io(Mmio<'a, T>),
+ /// The view is system memory.
+ Sys(SysMem<'a, T>),
+}
+
+impl<T: ?Sized> Copy for IoSysMap<'_, T> {}
+impl<T: ?Sized> Clone for IoSysMap<'_, T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'a, T: ?Sized> From<Mmio<'a, T>> for IoSysMap<'a, T> {
+ #[inline]
+ fn from(value: Mmio<'a, T>) -> Self {
+ IoSysMap::Io(value)
+ }
+}
+
+impl<'a, T: ?Sized> From<SysMem<'a, T>> for IoSysMap<'a, T> {
+ #[inline]
+ fn from(value: SysMem<'a, T>) -> Self {
+ IoSysMap::Sys(value)
+ }
+}
+
+impl IoBackend for IoSysMapBackend {
+ type View<'a, T: ?Sized + KnownSize> = IoSysMap<'a, T>;
+
+ #[inline]
+ fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
+ match view {
+ IoSysMap::Io(l) => MmioBackend::as_ptr(l),
+ IoSysMap::Sys(r) => SysMemBackend::as_ptr(r),
+ }
+ }
+
+ #[inline]
+ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
+ view: Self::View<'a, T>,
+ ptr: *mut U,
+ ) -> Self::View<'a, U> {
+ match view {
+ // SAFETY: Per safety requirement.
+ IoSysMap::Io(l) => IoSysMap::Io(unsafe { MmioBackend::project_view(l, ptr) }),
+ // SAFETY: Per safety requirement.
+ IoSysMap::Sys(r) => IoSysMap::Sys(unsafe { SysMemBackend::project_view(r, ptr) }),
+ }
+ }
+}
+
+impl<T> IoCapable<T> for IoSysMapBackend
+where
+ MmioBackend: IoCapable<T>,
+ SysMemBackend: IoCapable<T>,
+{
+ #[inline]
+ fn io_read(view: Self::View<'_, T>) -> T {
+ match view {
+ IoSysMap::Io(l) => MmioBackend::io_read(l),
+ IoSysMap::Sys(r) => SysMemBackend::io_read(r),
+ }
+ }
+
+ #[inline]
+ fn io_write<'a>(view: Self::View<'a, T>, value: T) {
+ match view {
+ IoSysMap::Io(l) => MmioBackend::io_write(l, value),
+ IoSysMap::Sys(r) => SysMemBackend::io_write(r, value),
+ }
+ }
+}
+
+impl IoCopyable for IoSysMapBackend {
+ #[inline]
+ unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {
+ match view {
+ // SAFETY: Per safety requirement.
+ IoSysMap::Io(l) => unsafe { MmioBackend::copy_from_io(l, buffer) },
+ // SAFETY: Per safety requirement.
+ IoSysMap::Sys(r) => unsafe { SysMemBackend::copy_from_io(r, buffer) },
+ }
+ }
+
+ #[inline]
+ unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {
+ match view {
+ // SAFETY: Per safety requirement.
+ IoSysMap::Io(l) => unsafe { MmioBackend::copy_to_io(l, buffer) },
+ // SAFETY: Per safety requirement.
+ IoSysMap::Sys(r) => unsafe { SysMemBackend::copy_to_io(r, buffer) },
+ }
+ }
+
+ #[inline]
+ fn copy_read<T: FromBytes>(view: Self::View<'_, T>) -> T {
+ match view {
+ IoSysMap::Io(l) => MmioBackend::copy_read(l),
+ IoSysMap::Sys(r) => SysMemBackend::copy_read(r),
+ }
+ }
+
+ #[inline]
+ fn copy_write<T: IntoBytes>(view: Self::View<'_, T>, value: T) {
+ match view {
+ IoSysMap::Io(l) => MmioBackend::copy_write(l, value),
+ IoSysMap::Sys(r) => SysMemBackend::copy_write(r, value),
+ }
+ }
+}
+
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for IoSysMap<'a, T> {
+ type Backend = IoSysMapBackend;
+ type Target = T;
+
+ #[inline]
+ fn as_view(self) -> IoSysMap<'a, T> {
+ self
+ }
+}
+
// This helper turns associated functions to methods so it can be invoked in macro.
// Used by `io_project!()` only.
#[doc(hidden)]