Re: [PATCH v6 16/20] rust: io: add `read_val` and `write_val` functions on `Io`
Daniel Almeida <[email protected]> Fri, 10 Jul 2026 22:56:59 -0300
| Newsgroups | dev.linux.lists.nova-gpu,dev.linux.lists.driver-core,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.linux-pwm,org.kernel.vger.rust-for-linux |
|---|---|
| Message-ID | <[email protected]> |
> 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]>