> On 6 Jul 2026, at 09:44, Gary Guo <[email protected]> wrote:
>
> Implement a `CoherentView` type which is a view of `Coherent`. To be able
> to give out DMA handles, the view type contains both CPU and DMA pointers,
> and the projection method projects both at once.
>
> Delegate most of the `Io` implementation to `SysMemBackend`. Provide a
> method to erase the DMA handle and give out a `SysMem` view, if the user
> does not need the `dma_handle`.
>
> Reviewed-by: Alexandre Courbot <[email protected]>
> Signed-off-by: Gary Guo <[email protected]>
> ---
> rust/kernel/dma.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 136 insertions(+), 2 deletions(-)
>
> diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
> index 200def84fb69..1535bc6eec64 100644
> --- a/rust/kernel/dma.rs
> +++ b/rust/kernel/dma.rs
> @@ -14,14 +14,21 @@
> },
> error::to_result,
> fs::file,
> + io::{
> + IoBackend,
> + IoBase,
> + IoCapable,
> + SysMem,
> + SysMemBackend, //
> + },
> prelude::*,
> ptr::KnownSize,
> sync::aref::ARef,
> transmute::{
> AsBytes,
> FromBytes, //
> - }, //
> - uaccess::UserSliceWriter,
> + },
> + uaccess::UserSliceWriter, //
> };
> use core::{
> ops::{
> @@ -1133,6 +1140,133 @@ unsafe impl Send for CoherentHandle {}
> // plain `Copy` values.
> unsafe impl Sync for CoherentHandle {}
>
> +/// View type for `Coherent`.
> +///
> +/// This is same as [`SysMem`] but with additional information that allows
> handing out a DMA handle.
> +pub struct CoherentView<'a, T: ?Sized> {
> + cpu_addr: SysMem<'a, T>,
> + dma_handle: DmaAddress,
> +}
> +
> +impl<T: ?Sized> Copy for CoherentView<'_, T> {}
> +impl<T: ?Sized> Clone for CoherentView<'_, T> {
> + #[inline]
> + fn clone(&self) -> Self {
> + *self
> + }
> +}
> +
> +impl<'a, T: ?Sized> CoherentView<'a, T> {
> + /// Erase the DMA handle information and obtain a [`SysMem`] view of the
> same memory region.
> + #[inline]
> + pub fn as_sys_mem(self) -> SysMem<'a, T> {
> + self.cpu_addr
> + }
> +
> + /// Returns a DMA handle which may be given to the device as the DMA
> address base of the region.
> + #[inline]
> + pub fn dma_handle(self) -> DmaAddress {
> + self.dma_handle
> + }
> +
> + /// Returns a reference to the data in the region.
> + ///
> + /// # Safety
> + ///
> + /// * Callers must ensure that the device does not read/write to/from
> memory while the returned
> + /// reference is live.
> + /// * Callers must ensure that this call does not race with a write
> (including call to `as_mut`)
> + /// to the same region while the returned reference is live.
> + #[inline]
> + pub unsafe fn as_ref(self) -> &'a T {
> + // SAFETY: pointer is aligned and valid per type invariant. Aliasing
> rule is satisfied per
> + // safety requirement.
> + unsafe { &*self.cpu_addr.as_ptr() }
> + }
> +
> + /// Returns a mutable reference to the data in the region.
> + ///
> + /// # Safety
> + ///
> + /// * Callers must ensure that the device does not read/write to/from
> memory while the returned
> + /// reference is live.
> + /// * Callers must ensure that this call does not race with a read
> (including call to `as_ref`)
> + /// or write (including call to `as_mut`) to the same region while the
> returned reference is
> + /// live.
> + #[inline]
> + pub unsafe fn as_mut(self) -> &'a mut T {
> + // SAFETY: pointer is aligned and valid per type invariant. Aliasing
> rule is satisfied per
> + // safety requirement.
> + unsafe { &mut *self.cpu_addr.as_ptr() }
> + }
> +}
> +
> +/// `IoBackend` implementation for `Coherent`.
> +pub struct CoherentIoBackend;
> +
> +impl IoBackend for CoherentIoBackend {
> + type View<'a, T: ?Sized + KnownSize> = CoherentView<'a, T>;
> +
> + #[inline]
> + fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
> + SysMemBackend::as_ptr(view.cpu_addr)
> + }
> +
> + #[inline]
> + unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
> + view: Self::View<'a, T>,
> + ptr: *mut U,
> + ) -> Self::View<'a, U> {
> + let offset = ptr.addr() - view.cpu_addr.as_ptr().addr();
> + // CAST: The offset DMA address can never overflow.
> + let dma_handle = view.dma_handle + offset as DmaAddress;
> + CoherentView {
> + dma_handle,
> + // SAFETY: Per safety requirement.
> + cpu_addr: unsafe { SysMemBackend::project_view(view.cpu_addr,
> ptr) },
> + }
> + }
> +}
> +
> +impl<T> IoCapable<T> for CoherentIoBackend
> +where
> + SysMemBackend: IoCapable<T>,
> +{
> + #[inline]
> + fn io_read<'a>(view: Self::View<'a, T>) -> T {
> + SysMemBackend::io_read(view.cpu_addr)
> + }
> +
> + #[inline]
> + fn io_write<'a>(view: Self::View<'a, T>, value: T) {
> + SysMemBackend::io_write(view.cpu_addr, value)
> + }
> +}
> +
> +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for CoherentView<'a, T> {
> + type Backend = CoherentIoBackend;
> + type Target = T;
> +
> + #[inline]
> + fn as_view(self) -> CoherentView<'a, Self::Target> {
> + self
> + }
> +}
> +
> +impl<'a, T: ?Sized + KnownSize> IoBase<'a> for &'a Coherent<T> {
> + type Backend = CoherentIoBackend;
> + type Target = T;
> +
> + #[inline]
> + fn as_view(self) -> CoherentView<'a, Self::Target> {
> + CoherentView {
> + // SAFETY: `cpu_addr` is valid and aligned kernel accessible
> memory.
> + cpu_addr: unsafe { SysMem::new(self.cpu_addr.as_ptr()) },
> + dma_handle: self.dma_handle,
> + }
> + }
> +}
> +
> /// Reads a field of an item from an allocated region of structs.
> ///
> /// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is
> an expression evaluating
>
> --
> 2.54.0
>
>
Reviewed-by: Daniel Almeida <[email protected]>