> 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]>

Reply via email to