Re: [PATCH v6 15/20] rust: io: implement a view type for `Coherent`
Daniel Almeida <[email protected]> Fri, 10 Jul 2026 22:32:27 -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: > > 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]>