[PATCH 1/3] rust: dma: add ContiguousBuffer trait for streaming DMA storage

Maurice Hieronymus <[email protected]> Wed, 05 Aug 2026 23:54:41 +0200
Newsgroups org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The streaming DMA API (`dma_map_single()`) does not allocate, it maps a
buffer the caller already owns. Not every allocation qualifies: the
buffer must be a single physically contiguous region in the kernel's
linear mapping, which rules out `vmalloc()`ed memory and the stack.

Add `ContiguousBuffer`, an unsafe trait describing that requirement, and
implement it for `KBox<T>`, whose storage comes from `kmalloc()`.

The trait hands out owned storage rather than a borrowed slice, so the
mapping added in the next patch can take ownership and guarantee that no
other CPU-side reference exists while the device owns the buffer. `Data`
is bounded by `FromBytes` and `AsBytes` because the device may write an
arbitrary byte pattern into the region and may read it, so it must not
contain uninitialized padding.

Signed-off-by: Maurice Hieronymus <[email protected]>
---
 rust/kernel/dma.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 200def84fb69..8a8af5ab7feb 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -564,6 +564,63 @@ fn from(value: CoherentBox<T>) -> Self {
     }
 }
 
+/// Backing storage that can be passed to the single-buffer streaming DMA API.
+///
+/// # Safety
+///
+/// Implementers must guarantee that, for as long as `Self` is alive and not mutated:
+///
+/// * [`ptr`](Self::ptr) returns a pointer to the start of a single, physically contiguous region
+///   of [`size`](Self::size) bytes, and [`data`](Self::data) refers to exactly that region.
+/// * The region lives in the kernel's linear mapping, i.e. it is neither `vmalloc()`ed nor stack
+///   memory, both of which `dma_map_single()` rejects.
+/// * The region is DMA-safe in the sense of the [DMA API howto].
+///
+/// [DMA API howto]: srctree/Documentation/core-api/dma-api-howto.rst
+pub unsafe trait ContiguousBuffer {
+    /// The CPU-side view of the region.
+    ///
+    /// [`FromBytes`] because the device may write an arbitrary byte pattern into the region,
+    /// [`AsBytes`] because it may read the region, which must therefore have no uninitialized
+    /// padding.
+    type Data: ?Sized + FromBytes + AsBytes;
+
+    /// Returns a pointer to the start of the region.
+    fn ptr(&mut self) -> *mut c_void;
+
+    /// Returns the size of the region in bytes.
+    fn size(&self) -> usize;
+
+    /// Returns a mutable reference to the region.
+    fn data(&mut self) -> &mut Self::Data;
+}
+
+// SAFETY: `KBox` allocates via `kmalloc()`, which returns a single physically contiguous,
+// DMA-safe region in the kernel's linear mapping. All three methods describe that allocation.
+unsafe impl<T: FromBytes + AsBytes> ContiguousBuffer for KBox<T> {
+    type Data = T;
+
+    fn ptr(&mut self) -> *mut c_void {
+        let ptr = &raw mut **self;
+        ptr.cast()
+    }
+
+    fn size(&self) -> usize {
+        const {
+            assert!(
+                core::mem::size_of::<T>() > 0,
+                "It doesn't make sense to map a ZST for DMA"
+            );
+        }
+
+        core::mem::size_of_val(&**self)
+    }
+
+    fn data(&mut self) -> &mut Self::Data {
+        self
+    }
+}
+
 /// An abstraction of the `dma_alloc_coherent` API.
 ///
 /// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map

-- 
2.54.0