[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