Re: [PATCH v7 05/10] rust: io: add IoLoc and IoWrite types
From: Gary Guo
Date: Wed Mar 04 2026 - 17:23:57 EST
On Tue Feb 24, 2026 at 2:21 PM GMT, Alexandre Courbot wrote:
> I/O accesses are defined by the following properties:
>
> - For reads, a start address, a width, and a type to interpret the read
> value as,
> - For writes, the same as above, and a value to write.
>
> Introduce the `IoLoc` trait, which allows implementing types to specify
> the address a type expects to be accessed at, as well as the width of
> the access, and the user-facing type used to perform the access.
>
> This allows read operations to be made generic with the `read` method
> over an `IoLoc` argument.
>
> Write operations need a value to write on top of the `IoLoc`: fulfill
> that purpose with the `IoWrite` type, which is the combination of an
> `IoLoc` and a value of the type it expects. This allows write operations
> to be made generic with the `write` method over a single `IoWrite`
> argument.
>
> The main purpose of these new entities is to allow register types to be
> written using these generic `read` and `write` methods of `Io`.
>
> Co-developed-by: Gary Guo <gary@xxxxxxxxxxx>
> Signed-off-by: Alexandre Courbot <acourbot@xxxxxxxxxx>
> ---
> rust/kernel/io.rs | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 241 insertions(+)
>
> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
> index b150743ffa4f..fdd2549d8e13 100644
> --- a/rust/kernel/io.rs
> +++ b/rust/kernel/io.rs
> @@ -173,6 +173,158 @@ pub trait IoCapable<T> {
> unsafe fn io_write(&self, value: T, address: usize);
> }
>
> +/// Describes a given I/O location: its offset, width, and return type.
> +///
> +/// This trait is the key abstraction allowing [`Io::read`], [`Io::write`], and [`Io::update`]
> +/// 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 data is returned or provided.
> +///
> +/// `T` and `IoType` may differ: for instance, a typed register has `T` = the register type with
> +/// its bitfields, and `IoType` = its backing primitive (e.g. `u32`), with `Into` conversions
> +/// between them.
> +///
> +/// An `IoLoc` can be passed directly to [`Io::read`] or [`Io::try_read`] to obtain a value, or
> +/// turned into an [`IoWrite`] via [`IoLoc::set`] to be passed to [`Io::write`] or
> +/// [`Io::try_write`].
> +pub trait IoLoc<T>: Copy
> +where
> + T: Into<Self::IoType>,
> + Self::IoType: Into<T>,
> +{
> + /// Size (`u8`, `u16`, etc) of the I/O performed on the returned [`offset`](IoLoc::offset).
> + type IoType;
You should move the where bound on the trait type to here.
A where bound on the trait is something that needs to be proved when referencing
the trait, rather than something that can be assumed (which is the case for
bounds in assoc types), which is why you need the extra `Into` bounds on `Io`
functions.
If you use
type IoType: Into<T> + From<T>;
then you can remove the `Into` bound from all `Io` methods.
(You would need to update the impl side though, with something like
impl<T> IoLoc<T> for FixedRegisterLoc<T>
where
- T: FixedRegister + From<T::Storage> + Into<T::Storage>,
+ T: FixedRegister + From<T::Storage>,
+ T::Storage: From<T>,
{
type IoType = T::Storage;
Best,
Gary