> On 6 Jul 2026, at 09:44, Gary Guo <[email protected]> wrote:
> 
> Provide `read_val` and `write_val` that allow I/O views to be accessed when
> they're narrowed down to just views of primitives.
> 
> This is used to provide `io_read!` and `io_write!` macros, which are
> generalized version of current `dma_read!` and `dma_write!` macro that work
> for all types that implement `Io`.
> 
> Note though `io_read!` and `io_write!` only works if backend implements
> `IoCapable` for the type; which is typically only implemented for
> atomically accessible primitives. `dma_read!` and `dma_write!` currently
> supports them via `read_volatile` and `write_volatile`; this can be
> undesirable for aggregates as LLVM may turn them to multiple instructions
> to access parts and re-assemble, even if they could be combined to a single
> instruction. Thus, `io_read!()` and `io_write!()` does not fully replace
> `dma_read!()` and `dma_write!()` in this scenario. The ability to
> read/write aggregates (when atomicity is of no concern) is better served
> with copying primitives (e.g. memcpy_{from,to}io).
> 
> Reviewed-by: Alexandre Courbot <[email protected]>
> Signed-off-by: Gary Guo <[email protected]>
> ---
> rust/kernel/io.rs | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 106 insertions(+)
> 
> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
> index 78c6ae2a0db8..c423125870b7 100644
> --- a/rust/kernel/io.rs
> +++ b/rust/kernel/io.rs
> @@ -398,6 +398,50 @@ fn try_cast<U>(self) -> Result<<Self::Backend as 
> IoBackend>::View<'a, U>>
>         Ok(unsafe { Self::Backend::project_view(view, ptr.cast()) })
>     }
> 
> +    /// Read a value from I/O.
> +    ///
> +    /// This only works for primitives supported by the I/O backend.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```no_run
> +    /// # use kernel::io::*;
> +    /// # fn test_read_val(mmio: Mmio<'_, u32>) {
> +    /// // let mmio: Mmio<'_, u32>;
> +    /// let val: u32 = mmio.read_val();
> +    /// # }
> +    /// ```
> +    #[inline]
> +    fn read_val(self) -> Self::Target
> +    where
> +        Self::Backend: IoCapable<Self::Target>,
> +        Self::Target: Sized,
> +    {
> +        Self::Backend::io_read(self.as_view())
> +    }
> +
> +    /// Write a value to I/O.
> +    ///
> +    /// This only works for primitives supported by the I/O backend.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```no_run
> +    /// # use kernel::io::*;
> +    /// # fn test_write_val(mmio: Mmio<'_, u32>) {
> +    /// // let mmio: Mmio<'_, u32>;
> +    /// mmio.write_val(1u32);
> +    /// # }
> +    /// ```
> +    #[inline]
> +    fn write_val(self, value: Self::Target)
> +    where
> +        Self::Backend: IoCapable<Self::Target>,
> +        Self::Target: Sized,
> +    {
> +        Self::Backend::io_write(self.as_view(), value)
> +    }
> +
>     /// Fallible 8-bit read with runtime bounds check.
>     #[inline(always)]
>     fn try_read8(self, offset: usize) -> Result<u8>
> @@ -1229,3 +1273,65 @@ macro_rules! io_project {
> }
> #[doc(inline)]
> pub use crate::io_project;
> +
> +/// Read from I/O memory.
> +///
> +/// The syntax is of form `io_read!(io, proj)` where `io` is an expression 
> to a type that
> +/// implements [`Io`] and `proj` is a [projection 
> specification](kernel::ptr::project!).
> +///
> +/// # Examples
> +///
> +/// ```
> +/// #[repr(C)]
> +/// struct MyStruct { field: u32, }
> +///
> +/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result {
> +/// // let mmio: Mmio<'_, [MyStruct]>;
> +/// let field: u32 = kernel::io::io_read!(mmio, [try: 2].field);
> +/// # Ok::<(), Error>(()) }
> +/// ```
> +#[macro_export]
> +#[doc(hidden)]
> +macro_rules! io_read {
> +    ($io:expr, $($proj:tt)*) => {
> +        $crate::io::Io::read_val($crate::io_project!($io, $($proj)*))
> +    };
> +}
> +#[doc(inline)]
> +pub use crate::io_read;
> +
> +/// Writes to I/O memory.
> +///
> +/// The syntax is of form `io_write!(io, proj, val)` where `io` is an 
> expression to a type that
> +/// implements [`Io`] and `proj` is a [projection 
> specification](kernel::ptr::project!),
> +/// and `val` is the value to be written to the projected location.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// #[repr(C)]
> +/// struct MyStruct { field: u32, }
> +///
> +/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result {
> +/// // let mmio: Mmio<'_, [MyStruct]>;
> +/// kernel::io::io_write!(mmio, [try: 2].field, 10);
> +/// # Ok::<(), Error>(()) }
> +/// ```
> +#[macro_export]
> +#[doc(hidden)]
> +macro_rules! io_write {
> +    (@parse [$io:expr] [$($proj:tt)*] [, $val:expr]) => {
> +        $crate::io::Io::write_val($crate::io_project!($io, $($proj)*), $val)
> +    };
> +    (@parse [$io:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => {
> +        $crate::io_write!(@parse [$io] [$($proj)* .$field] [$($rest)*])
> +    };
> +    (@parse [$io:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] 
> $($rest:tt)*]) => {
> +        $crate::io_write!(@parse [$io] [$($proj)* [$flavor: $index]] 
> [$($rest)*])
> +    };
> +    ($io:expr, $($rest:tt)*) => {
> +        $crate::io_write!(@parse [$io] [] [$($rest)*])
> +    };
> +}
> +#[doc(inline)]
> +pub use crate::io_write;
> 
> -- 
> 2.54.0
> 
> 

Reviewed-by: Daniel Almeida <[email protected]>

Reply via email to