From: Alexandre Courbot <acourbot@nvidia.com>
To: "Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Miguel Ojeda" <ojeda@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Boqun Feng" <boqun@kernel.org>
Cc: Yury Norov <yury.norov@gmail.com>,
John Hubbard <jhubbard@nvidia.com>,
Alistair Popple <apopple@nvidia.com>,
Joel Fernandes <joelagnelf@nvidia.com>,
Timur Tabi <ttabi@nvidia.com>, Edwin Peer <epeer@nvidia.com>,
Eliot Courtney <ecourtney@nvidia.com>,
Dirk Behme <dirk.behme@de.bosch.com>,
Steven Price <steven.price@arm.com>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [PATCH v8 05/10] rust: io: add IoLoc type and generic I/O accessors
Date: Tue, 10 Mar 2026 00:14:02 +0900 [thread overview]
Message-ID: <20260310-register-v8-5-424f80dd43bc@nvidia.com> (raw)
In-Reply-To: <20260310-register-v8-0-424f80dd43bc@nvidia.com>
I/O accesses are defined by the following properties:
- An I/O location, which consists of a start address, a width, and a
type to interpret the read value as,
- A value, which is returned for reads or provided for writes.
Introduce the `IoLoc` trait, which allows implementing types to fully
specify an I/O location.
This allows I/O operations to be made generic through the new `read` and
`write` methods.
This design will allow us to factorize the I/O code working with
primitives, and to introduce ways to perform I/O with a higher degree of
control through register types.
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
rust/kernel/io.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index b150743ffa4f..1db6572f4a42 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -173,6 +173,30 @@ pub trait IoCapable<T> {
unsafe fn io_write(&self, value: T, address: usize);
}
+/// Describes a given I/O location: its offset, width, and type to convert the raw value from and
+/// into.
+///
+/// This trait is the key abstraction allowing [`Io::read`], [`Io::write`], and [`Io::update`] (and
+/// their fallible [`try_read`](Io::try_read), [`try_write`](Io::try_write) and
+/// [`try_update`](Io::try_update) counterparts) to work uniformly with both raw [`usize`] offsets
+/// (for primitive types like [`u32`]) and typed ones.
+///
+/// An `IoLoc<T>` carries three pieces of information:
+///
+/// - The offset to access (returned by [`IoLoc::offset`]),
+/// - The width of the access (determined by [`IoLoc::IoType`]),
+/// - The type `T` in which the raw data is returned or provided.
+///
+/// `T` and `IoLoc::IoType` may differ: for instance, a typed register has `T` = the register type
+/// with its bitfields, and `IoType` = its backing primitive (e.g. `u32`).
+pub trait IoLoc<T> {
+ /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [`offset`](IoLoc::offset).
+ type IoType: Into<T> + From<T>;
+
+ /// Returns the offset of this location.
+ 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.
///
@@ -406,6 +430,106 @@ fn write64(&self, value: u64, offset: usize)
// SAFETY: `address` has been validated by `io_addr_assert`.
unsafe { self.io_write(value, address) }
}
+
+ /// Generic fallible read with runtime bounds check.
+ #[inline(always)]
+ fn try_read<T, L>(&self, location: L) -> Result<T>
+ where
+ L: IoLoc<T>,
+ Self: IoCapable<L::IoType>,
+ {
+ let address = self.io_addr::<L::IoType>(location.offset())?;
+
+ // SAFETY: `address` has been validated by `io_addr`.
+ Ok(unsafe { self.io_read(address) }.into())
+ }
+
+ /// Generic fallible write with runtime bounds check.
+ #[inline(always)]
+ fn try_write<T, L>(&self, location: L, value: T) -> Result
+ where
+ L: IoLoc<T>,
+ Self: IoCapable<L::IoType>,
+ {
+ let address = self.io_addr::<L::IoType>(location.offset())?;
+ let io_value = value.into();
+
+ // SAFETY: `address` has been validated by `io_addr`.
+ unsafe { self.io_write(io_value, address) }
+
+ Ok(())
+ }
+
+ /// Generic fallible update with runtime bounds check.
+ ///
+ /// Caution: this does not perform any synchronization. Race conditions can occur in case of
+ /// concurrent access.
+ #[inline(always)]
+ fn try_update<T, L, F>(&self, location: L, f: F) -> Result
+ where
+ L: IoLoc<T>,
+ Self: IoCapable<L::IoType>,
+ F: FnOnce(T) -> T,
+ {
+ let address = self.io_addr::<L::IoType>(location.offset())?;
+
+ // SAFETY: `address` has been validated by `io_addr`.
+ let value: T = unsafe { self.io_read(address) }.into();
+ let io_value = f(value).into();
+
+ // SAFETY: `address` has been validated by `io_addr_assert`.
+ unsafe { self.io_write(io_value, address) }
+
+ Ok(())
+ }
+
+ /// Generic infallible read with compile-time bounds check.
+ #[inline(always)]
+ fn read<T, L>(&self, location: L) -> T
+ where
+ L: IoLoc<T>,
+ Self: IoKnownSize + IoCapable<L::IoType>,
+ {
+ let address = self.io_addr_assert::<L::IoType>(location.offset());
+
+ // SAFETY: `address` has been validated by `io_addr_assert`.
+ unsafe { self.io_read(address) }.into()
+ }
+
+ /// Generic infallible write with compile-time bounds check.
+ #[inline(always)]
+ fn write<T, L>(&self, location: L, value: T)
+ where
+ L: IoLoc<T>,
+ Self: IoKnownSize + IoCapable<L::IoType>,
+ {
+ let address = self.io_addr_assert::<L::IoType>(location.offset());
+ let io_value = value.into();
+
+ // SAFETY: `address` has been validated by `io_addr_assert`.
+ unsafe { self.io_write(io_value, address) }
+ }
+
+ /// Generic infallible update with compile-time bounds check.
+ ///
+ /// Caution: this does not perform any synchronization. Race conditions can occur in case of
+ /// concurrent access.
+ #[inline(always)]
+ fn update<T, L, F>(&self, location: L, f: F)
+ where
+ L: IoLoc<T>,
+ Self: IoKnownSize + IoCapable<L::IoType> + Sized,
+ F: FnOnce(T) -> T,
+ {
+ let address = self.io_addr_assert::<L::IoType>(location.offset());
+
+ // SAFETY: `address` has been validated by `io_addr_assert`.
+ let value: T = unsafe { self.io_read(address) }.into();
+ let io_value = f(value).into();
+
+ // SAFETY: `address` has been validated by `io_addr_assert`.
+ unsafe { self.io_write(io_value, address) }
+ }
}
/// Trait for types with a known size at compile time.
--
2.53.0
next prev parent reply other threads:[~2026-03-09 15:14 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-09 15:13 [PATCH v8 00/10] rust: add `register!` macro Alexandre Courbot
2026-03-09 15:13 ` [PATCH v8 01/10] rust: enable the `generic_arg_infer` feature Alexandre Courbot
2026-03-11 0:13 ` Yury Norov
2026-03-11 6:16 ` Miguel Ojeda
2026-03-09 15:13 ` [PATCH v8 02/10] rust: num: add `shr` and `shl` methods to `Bounded` Alexandre Courbot
2026-03-11 0:26 ` Yury Norov
2026-03-09 15:14 ` [PATCH v8 03/10] rust: num: add `into_bool` method " Alexandre Courbot
2026-03-11 0:29 ` Yury Norov
2026-03-09 15:14 ` [PATCH v8 04/10] rust: num: make Bounded::get const Alexandre Courbot
2026-03-09 15:14 ` Alexandre Courbot [this message]
2026-03-10 15:15 ` [PATCH v8 05/10] rust: io: add IoLoc type and generic I/O accessors Danilo Krummrich
2026-03-09 15:14 ` [PATCH v8 06/10] rust: io: use generic read/write accessors for primitive accesses Alexandre Courbot
2026-03-09 15:29 ` Gary Guo
2026-03-10 1:57 ` Alexandre Courbot
2026-03-10 1:59 ` Alexandre Courbot
2026-03-10 2:04 ` Gary Guo
2026-03-10 15:17 ` Danilo Krummrich
2026-03-09 15:14 ` [PATCH v8 07/10] rust: io: introduce `IntoIoVal` trait and single-argument `write_val` Alexandre Courbot
2026-03-09 15:30 ` Gary Guo
2026-03-10 2:05 ` Alexandre Courbot
2026-03-10 16:34 ` Danilo Krummrich
2026-03-10 22:33 ` Gary Guo
2026-03-11 13:25 ` Danilo Krummrich
2026-03-11 13:42 ` Alexandre Courbot
2026-03-11 13:28 ` Alexandre Courbot
2026-03-11 14:56 ` Danilo Krummrich
2026-03-11 15:42 ` Gary Guo
2026-03-11 16:22 ` Danilo Krummrich
2026-03-11 17:16 ` Gary Guo
2026-03-12 13:53 ` Alexandre Courbot
2026-03-12 15:54 ` Danilo Krummrich
2026-03-14 1:19 ` Alexandre Courbot
2026-03-09 15:14 ` [PATCH v8 08/10] rust: io: add `register!` macro Alexandre Courbot
2026-03-10 16:39 ` Danilo Krummrich
2026-03-09 15:14 ` [PATCH v8 09/10] sample: rust: pci: use " Alexandre Courbot
2026-03-09 15:14 ` [PATCH FOR REFERENCE v8 10/10] gpu: nova-core: use the kernel " Alexandre Courbot
2026-03-09 15:43 ` Joel Fernandes
2026-03-09 17:34 ` John Hubbard
2026-03-09 17:51 ` Joel Fernandes
2026-03-09 18:01 ` John Hubbard
2026-03-09 18:28 ` Gary Guo
2026-03-09 18:34 ` John Hubbard
2026-03-09 18:42 ` Danilo Krummrich
2026-03-09 18:47 ` John Hubbard
2026-03-09 18:42 ` Gary Guo
2026-03-09 18:50 ` John Hubbard
2026-03-09 18:04 ` Danilo Krummrich
2026-03-09 18:06 ` John Hubbard
2026-03-10 2:18 ` Alexandre Courbot
2026-03-09 18:05 ` [PATCH v8 00/10] rust: add " John Hubbard
2026-03-09 21:08 ` Daniel Almeida
2026-03-10 17:20 ` Danilo Krummrich
2026-03-11 13:01 ` Alexandre Courbot
2026-03-11 13:07 ` Danilo Krummrich
2026-03-11 13:35 ` Alexandre Courbot
2026-03-11 13:38 ` Danilo Krummrich
2026-03-12 2:23 ` Alexandre Courbot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260310-register-v8-5-424f80dd43bc@nvidia.com \
--to=acourbot@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dirk.behme@de.bosch.com \
--cc=ecourtney@nvidia.com \
--cc=epeer@nvidia.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=joelagnelf@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=steven.price@arm.com \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
--cc=yury.norov@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.