[PATCH v3 14/19] rust: io: implement a view type for `Coherent`
From: Gary Guo
Date: Mon Jun 08 2026 - 16:08:41 EST
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`.
Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/kernel/dma.rs | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 135 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 200def84fb69..970a667b9be2 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,132 @@ 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> 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
+ /// slice is live.
+ /// * Callers must ensure that this call does not race with a write to the same region while
+ /// the returned slice 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
+ /// slice is live.
+ /// * Callers must ensure that this call does not race with a read or write to the same region
+ /// while the returned slice 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 CoherentBackend;
+
+impl IoBackend for CoherentBackend {
+ 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 CoherentBackend
+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 = CoherentBackend;
+ 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 = CoherentBackend;
+ 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