kernel/dma.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Direct memory access (DMA).
4//!
5//! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h)
6
7use crate::{
8 bindings,
9 device::{
10 self,
11 Bound,
12 Core, //
13 },
14 error::to_result,
15 prelude::*,
16 ptr::KnownSize,
17 sync::aref::ARef,
18 transmute::{
19 AsBytes,
20 FromBytes, //
21 }, //
22};
23use core::{
24 ops::{
25 Deref,
26 DerefMut, //
27 },
28 ptr::NonNull, //
29};
30
31/// DMA address type.
32///
33/// Represents a bus address used for Direct Memory Access (DMA) operations.
34///
35/// This is an alias of the kernel's `dma_addr_t`, which may be `u32` or `u64` depending on
36/// `CONFIG_ARCH_DMA_ADDR_T_64BIT`.
37///
38/// Note that this may be `u64` even on 32-bit architectures.
39pub type DmaAddress = bindings::dma_addr_t;
40
41/// Trait to be implemented by DMA capable bus devices.
42///
43/// The [`dma::Device`](Device) trait should be implemented by bus specific device representations,
44/// where the underlying bus is DMA capable, such as:
45#[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")]
46/// * [`platform::Device`](::kernel::platform::Device)
47pub trait Device: AsRef<device::Device<Core>> {
48 /// Set up the device's DMA streaming addressing capabilities.
49 ///
50 /// This method is usually called once from `probe()` as soon as the device capabilities are
51 /// known.
52 ///
53 /// # Safety
54 ///
55 /// This method must not be called concurrently with any DMA allocation or mapping primitives,
56 /// such as [`Coherent::zeroed`].
57 unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result {
58 // SAFETY:
59 // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
60 // - The safety requirement of this function guarantees that there are no concurrent calls
61 // to DMA allocation and mapping primitives using this mask.
62 to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) })
63 }
64
65 /// Set up the device's DMA coherent addressing capabilities.
66 ///
67 /// This method is usually called once from `probe()` as soon as the device capabilities are
68 /// known.
69 ///
70 /// # Safety
71 ///
72 /// This method must not be called concurrently with any DMA allocation or mapping primitives,
73 /// such as [`Coherent::zeroed`].
74 unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result {
75 // SAFETY:
76 // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
77 // - The safety requirement of this function guarantees that there are no concurrent calls
78 // to DMA allocation and mapping primitives using this mask.
79 to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) })
80 }
81
82 /// Set up the device's DMA addressing capabilities.
83 ///
84 /// This is a combination of [`Device::dma_set_mask`] and [`Device::dma_set_coherent_mask`].
85 ///
86 /// This method is usually called once from `probe()` as soon as the device capabilities are
87 /// known.
88 ///
89 /// # Safety
90 ///
91 /// This method must not be called concurrently with any DMA allocation or mapping primitives,
92 /// such as [`Coherent::zeroed`].
93 unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result {
94 // SAFETY:
95 // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
96 // - The safety requirement of this function guarantees that there are no concurrent calls
97 // to DMA allocation and mapping primitives using this mask.
98 to_result(unsafe {
99 bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value())
100 })
101 }
102
103 /// Set the maximum size of a single DMA segment the device may request.
104 ///
105 /// This method is usually called once from `probe()` as soon as the device capabilities are
106 /// known.
107 ///
108 /// # Safety
109 ///
110 /// This method must not be called concurrently with any DMA allocation or mapping primitives,
111 /// such as [`Coherent::zeroed`].
112 unsafe fn dma_set_max_seg_size(&self, size: u32) {
113 // SAFETY:
114 // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
115 // - The safety requirement of this function guarantees that there are no concurrent calls
116 // to DMA allocation and mapping primitives using this parameter.
117 unsafe { bindings::dma_set_max_seg_size(self.as_ref().as_raw(), size) }
118 }
119}
120
121/// A DMA mask that holds a bitmask with the lowest `n` bits set.
122///
123/// Use [`DmaMask::new`] or [`DmaMask::try_new`] to construct a value. Values
124/// are guaranteed to never exceed the bit width of `u64`.
125///
126/// This is the Rust equivalent of the C macro `DMA_BIT_MASK()`.
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub struct DmaMask(u64);
129
130impl DmaMask {
131 /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
132 ///
133 /// For `n <= 64`, sets exactly the lowest `n` bits.
134 /// For `n > 64`, results in a build error.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use kernel::dma::DmaMask;
140 ///
141 /// let mask0 = DmaMask::new::<0>();
142 /// assert_eq!(mask0.value(), 0);
143 ///
144 /// let mask1 = DmaMask::new::<1>();
145 /// assert_eq!(mask1.value(), 0b1);
146 ///
147 /// let mask64 = DmaMask::new::<64>();
148 /// assert_eq!(mask64.value(), u64::MAX);
149 ///
150 /// // Build failure.
151 /// // let mask_overflow = DmaMask::new::<100>();
152 /// ```
153 #[inline]
154 pub const fn new<const N: u32>() -> Self {
155 let Ok(mask) = Self::try_new(N) else {
156 build_error!("Invalid DMA Mask.");
157 };
158
159 mask
160 }
161
162 /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
163 ///
164 /// For `n <= 64`, sets exactly the lowest `n` bits.
165 /// For `n > 64`, returns [`EINVAL`].
166 ///
167 /// # Examples
168 ///
169 /// ```
170 /// use kernel::dma::DmaMask;
171 ///
172 /// let mask0 = DmaMask::try_new(0)?;
173 /// assert_eq!(mask0.value(), 0);
174 ///
175 /// let mask1 = DmaMask::try_new(1)?;
176 /// assert_eq!(mask1.value(), 0b1);
177 ///
178 /// let mask64 = DmaMask::try_new(64)?;
179 /// assert_eq!(mask64.value(), u64::MAX);
180 ///
181 /// let mask_overflow = DmaMask::try_new(100);
182 /// assert!(mask_overflow.is_err());
183 /// # Ok::<(), Error>(())
184 /// ```
185 #[inline]
186 pub const fn try_new(n: u32) -> Result<Self> {
187 Ok(Self(match n {
188 0 => 0,
189 1..=64 => u64::MAX >> (64 - n),
190 _ => return Err(EINVAL),
191 }))
192 }
193
194 /// Returns the underlying `u64` bitmask value.
195 #[inline]
196 pub const fn value(&self) -> u64 {
197 self.0
198 }
199}
200
201/// Possible attributes associated with a DMA mapping.
202///
203/// They can be combined with the operators `|`, `&`, and `!`.
204///
205/// Values can be used from the [`attrs`] module.
206///
207/// # Examples
208///
209/// ```
210/// # use kernel::device::{Bound, Device};
211/// use kernel::dma::{attrs::*, Coherent};
212///
213/// # fn test(dev: &Device<Bound>) -> Result {
214/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
215/// let c: Coherent<[u64]> =
216/// Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, attribs)?;
217/// # Ok::<(), Error>(()) }
218/// ```
219#[derive(Clone, Copy, PartialEq)]
220#[repr(transparent)]
221pub struct Attrs(u32);
222
223impl Attrs {
224 /// Get the raw representation of this attribute.
225 pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
226 self.0 as crate::ffi::c_ulong
227 }
228
229 /// Check whether `flags` is contained in `self`.
230 pub fn contains(self, flags: Attrs) -> bool {
231 (self & flags) == flags
232 }
233}
234
235impl core::ops::BitOr for Attrs {
236 type Output = Self;
237 fn bitor(self, rhs: Self) -> Self::Output {
238 Self(self.0 | rhs.0)
239 }
240}
241
242impl core::ops::BitAnd for Attrs {
243 type Output = Self;
244 fn bitand(self, rhs: Self) -> Self::Output {
245 Self(self.0 & rhs.0)
246 }
247}
248
249impl core::ops::Not for Attrs {
250 type Output = Self;
251 fn not(self) -> Self::Output {
252 Self(!self.0)
253 }
254}
255
256/// DMA mapping attributes.
257pub mod attrs {
258 use super::Attrs;
259
260 /// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
261 /// and writes may pass each other.
262 pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
263
264 /// Specifies that writes to the mapping may be buffered to improve performance.
265 pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
266
267 /// Lets the platform to avoid creating a kernel virtual mapping for the allocated buffer.
268 pub const DMA_ATTR_NO_KERNEL_MAPPING: Attrs = Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
269
270 /// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming
271 /// that it has been already transferred to 'device' domain.
272 pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC);
273
274 /// Forces contiguous allocation of the buffer in physical memory.
275 pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS);
276
277 /// Hints DMA-mapping subsystem that it's probably not worth the time to try
278 /// to allocate memory to in a way that gives better TLB efficiency.
279 pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES);
280
281 /// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
282 /// `__GFP_NOWARN`).
283 pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN);
284
285 /// Indicates that the buffer is fully accessible at an elevated privilege level (and
286 /// ideally inaccessible or at least read-only at lesser-privileged levels).
287 pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED);
288
289 /// Indicates that the buffer is MMIO memory.
290 pub const DMA_ATTR_MMIO: Attrs = Attrs(bindings::DMA_ATTR_MMIO);
291}
292
293/// DMA data direction.
294///
295/// Corresponds to the C [`enum dma_data_direction`].
296///
297/// [`enum dma_data_direction`]: srctree/include/linux/dma-direction.h
298#[derive(Copy, Clone, PartialEq, Eq, Debug)]
299#[repr(u32)]
300pub enum DataDirection {
301 /// The DMA mapping is for bidirectional data transfer.
302 ///
303 /// This is used when the buffer can be both read from and written to by the device.
304 /// The cache for the corresponding memory region is both flushed and invalidated.
305 Bidirectional = Self::const_cast(bindings::dma_data_direction_DMA_BIDIRECTIONAL),
306
307 /// The DMA mapping is for data transfer from memory to the device (write).
308 ///
309 /// The CPU has prepared data in the buffer, and the device will read it.
310 /// The cache for the corresponding memory region is flushed before device access.
311 ToDevice = Self::const_cast(bindings::dma_data_direction_DMA_TO_DEVICE),
312
313 /// The DMA mapping is for data transfer from the device to memory (read).
314 ///
315 /// The device will write data into the buffer for the CPU to read.
316 /// The cache for the corresponding memory region is invalidated before CPU access.
317 FromDevice = Self::const_cast(bindings::dma_data_direction_DMA_FROM_DEVICE),
318
319 /// The DMA mapping is not for data transfer.
320 ///
321 /// This is primarily for debugging purposes. With this direction, the DMA mapping API
322 /// will not perform any cache coherency operations.
323 None = Self::const_cast(bindings::dma_data_direction_DMA_NONE),
324}
325
326impl DataDirection {
327 /// Casts the bindgen-generated enum type to a `u32` at compile time.
328 ///
329 /// This function will cause a compile-time error if the underlying value of the
330 /// C enum is out of bounds for `u32`.
331 const fn const_cast(val: bindings::dma_data_direction) -> u32 {
332 // CAST: The C standard allows compilers to choose different integer types for enums.
333 // To safely check the value, we cast it to a wide signed integer type (`i128`)
334 // which can hold any standard C integer enum type without truncation.
335 let wide_val = val as i128;
336
337 // Check if the value is outside the valid range for the target type `u32`.
338 // CAST: `u32::MAX` is cast to `i128` to match the type of `wide_val` for the comparison.
339 if wide_val < 0 || wide_val > u32::MAX as i128 {
340 // Trigger a compile-time error in a const context.
341 build_error!("C enum value is out of bounds for the target type `u32`.");
342 }
343
344 // CAST: This cast is valid because the check above guarantees that `wide_val`
345 // is within the representable range of `u32`.
346 wide_val as u32
347 }
348}
349
350impl From<DataDirection> for bindings::dma_data_direction {
351 /// Returns the raw representation of [`enum dma_data_direction`].
352 fn from(direction: DataDirection) -> Self {
353 // CAST: `direction as u32` gets the underlying representation of our `#[repr(u32)]` enum.
354 // The subsequent cast to `Self` (the bindgen type) assumes the C enum is compatible
355 // with the enum variants of `DataDirection`, which is a valid assumption given our
356 // compile-time checks.
357 direction as u32 as Self
358 }
359}
360
361/// CPU-owned DMA allocation that can be converted into a device-shared [`Coherent`] object.
362///
363/// Unlike [`Coherent`], a [`CoherentBox`] is guaranteed to be fully owned by the CPU -- its DMA
364/// address is not exposed and it cannot be accessed by a device. This means it can safely be used
365/// like a normal boxed allocation (e.g. direct reads, writes, and mutable slices are all safe).
366///
367/// A typical use is to allocate a [`CoherentBox`], populate it with normal CPU access, and then
368/// convert it into a [`Coherent`] object to share it with the device.
369///
370/// # Examples
371///
372/// `CoherentBox<T>`:
373///
374/// ```
375/// # use kernel::device::{
376/// # Bound,
377/// # Device,
378/// # };
379/// use kernel::dma::{attrs::*,
380/// Coherent,
381/// CoherentBox,
382/// };
383///
384/// # fn test(dev: &Device<Bound>) -> Result {
385/// let mut dmem: CoherentBox<u64> = CoherentBox::zeroed(dev, GFP_KERNEL)?;
386/// *dmem = 42;
387/// let dmem: Coherent<u64> = dmem.into();
388/// # Ok::<(), Error>(()) }
389/// ```
390///
391/// `CoherentBox<[T]>`:
392///
393///
394/// ```
395/// # use kernel::device::{
396/// # Bound,
397/// # Device,
398/// # };
399/// use kernel::dma::{attrs::*,
400/// Coherent,
401/// CoherentBox,
402/// };
403///
404/// # fn test(dev: &Device<Bound>) -> Result {
405/// let mut dmem: CoherentBox<[u64]> = CoherentBox::zeroed_slice(dev, 4, GFP_KERNEL)?;
406/// dmem.fill(42);
407/// let dmem: Coherent<[u64]> = dmem.into();
408/// # Ok::<(), Error>(()) }
409/// ```
410pub struct CoherentBox<T: KnownSize + ?Sized>(Coherent<T>);
411
412impl<T: AsBytes + FromBytes> CoherentBox<[T]> {
413 /// [`CoherentBox`] variant of [`Coherent::zeroed_slice_with_attrs`].
414 #[inline]
415 pub fn zeroed_slice_with_attrs(
416 dev: &device::Device<Bound>,
417 count: usize,
418 gfp_flags: kernel::alloc::Flags,
419 dma_attrs: Attrs,
420 ) -> Result<Self> {
421 Coherent::zeroed_slice_with_attrs(dev, count, gfp_flags, dma_attrs).map(Self)
422 }
423
424 /// Same as [CoherentBox::zeroed_slice_with_attrs], but with `dma::Attrs(0)`.
425 #[inline]
426 pub fn zeroed_slice(
427 dev: &device::Device<Bound>,
428 count: usize,
429 gfp_flags: kernel::alloc::Flags,
430 ) -> Result<Self> {
431 Self::zeroed_slice_with_attrs(dev, count, gfp_flags, Attrs(0))
432 }
433
434 /// Initializes the element at `i` using the given initializer.
435 ///
436 /// Returns `EINVAL` if `i` is out of bounds.
437 pub fn init_at<E>(&mut self, i: usize, init: impl Init<T, E>) -> Result
438 where
439 Error: From<E>,
440 {
441 if i >= self.0.len() {
442 return Err(EINVAL);
443 }
444
445 let ptr = &raw mut self[i];
446
447 // SAFETY:
448 // - `ptr` is valid, properly aligned, and within this allocation.
449 // - `T: AsBytes + FromBytes` guarantees all bit patterns are valid, so partial writes on
450 // error cannot leave the element in an invalid state.
451 // - The DMA address has not been exposed yet, so there is no concurrent device access.
452 unsafe { init.__init(ptr)? };
453
454 Ok(())
455 }
456}
457
458impl<T: AsBytes + FromBytes> CoherentBox<T> {
459 /// Same as [`CoherentBox::zeroed_slice_with_attrs`], but for a single element.
460 #[inline]
461 pub fn zeroed_with_attrs(
462 dev: &device::Device<Bound>,
463 gfp_flags: kernel::alloc::Flags,
464 dma_attrs: Attrs,
465 ) -> Result<Self> {
466 Coherent::zeroed_with_attrs(dev, gfp_flags, dma_attrs).map(Self)
467 }
468
469 /// Same as [`CoherentBox::zeroed_slice`], but for a single element.
470 #[inline]
471 pub fn zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
472 Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
473 }
474}
475
476impl<T: KnownSize + ?Sized> Deref for CoherentBox<T> {
477 type Target = T;
478
479 #[inline]
480 fn deref(&self) -> &Self::Target {
481 // SAFETY:
482 // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
483 // device.
484 // - We have exclusive access to `self.0`.
485 unsafe { self.0.as_ref() }
486 }
487}
488
489impl<T: AsBytes + FromBytes + KnownSize + ?Sized> DerefMut for CoherentBox<T> {
490 #[inline]
491 fn deref_mut(&mut self) -> &mut Self::Target {
492 // SAFETY:
493 // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
494 // device.
495 // - We have exclusive access to `self.0`.
496 unsafe { self.0.as_mut() }
497 }
498}
499
500impl<T: AsBytes + FromBytes + KnownSize + ?Sized> From<CoherentBox<T>> for Coherent<T> {
501 #[inline]
502 fn from(value: CoherentBox<T>) -> Self {
503 value.0
504 }
505}
506
507/// An abstraction of the `dma_alloc_coherent` API.
508///
509/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
510/// large coherent DMA regions.
511///
512/// A [`Coherent`] instance contains a pointer to the allocated region (in the
513/// processor's virtual address space) and the device address which can be given to the device
514/// as the DMA address base of the region. The region is released once [`Coherent`]
515/// is dropped.
516///
517/// # Invariants
518///
519/// - For the lifetime of an instance of [`Coherent`], the `cpu_addr` is a valid pointer
520/// to an allocated region of coherent memory and `dma_handle` is the DMA address base of the
521/// region.
522/// - The size in bytes of the allocation is equal to size information via pointer.
523// TODO
524//
525// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
526// reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure
527// that device resources can never survive device unbind.
528//
529// However, it is neither desirable nor necessary to protect the allocated memory of the DMA
530// allocation from surviving device unbind; it would require RCU read side critical sections to
531// access the memory, which may require subsequent unnecessary copies.
532//
533// Hence, find a way to revoke the device resources of a `Coherent`, but not the
534// entire `Coherent` including the allocated memory itself.
535pub struct Coherent<T: KnownSize + ?Sized> {
536 dev: ARef<device::Device>,
537 dma_handle: DmaAddress,
538 cpu_addr: NonNull<T>,
539 dma_attrs: Attrs,
540}
541
542impl<T: KnownSize + ?Sized> Coherent<T> {
543 /// Returns the size in bytes of this allocation.
544 #[inline]
545 pub fn size(&self) -> usize {
546 T::size(self.cpu_addr.as_ptr())
547 }
548
549 /// Returns the raw pointer to the allocated region in the CPU's virtual address space.
550 #[inline]
551 pub fn as_ptr(&self) -> *const T {
552 self.cpu_addr.as_ptr()
553 }
554
555 /// Returns the raw pointer to the allocated region in the CPU's virtual address space as
556 /// a mutable pointer.
557 #[inline]
558 pub fn as_mut_ptr(&self) -> *mut T {
559 self.cpu_addr.as_ptr()
560 }
561
562 /// Returns a DMA handle which may be given to the device as the DMA address base of
563 /// the region.
564 #[inline]
565 pub fn dma_handle(&self) -> DmaAddress {
566 self.dma_handle
567 }
568
569 /// Returns a reference to the data in the region.
570 ///
571 /// # Safety
572 ///
573 /// * Callers must ensure that the device does not read/write to/from memory while the returned
574 /// slice is live.
575 /// * Callers must ensure that this call does not race with a write to the same region while
576 /// the returned slice is live.
577 #[inline]
578 pub unsafe fn as_ref(&self) -> &T {
579 // SAFETY: per safety requirement.
580 unsafe { &*self.as_ptr() }
581 }
582
583 /// Returns a mutable reference to the data in the region.
584 ///
585 /// # Safety
586 ///
587 /// * Callers must ensure that the device does not read/write to/from memory while the returned
588 /// slice is live.
589 /// * Callers must ensure that this call does not race with a read or write to the same region
590 /// while the returned slice is live.
591 #[expect(clippy::mut_from_ref, reason = "unsafe to use API")]
592 #[inline]
593 pub unsafe fn as_mut(&self) -> &mut T {
594 // SAFETY: per safety requirement.
595 unsafe { &mut *self.as_mut_ptr() }
596 }
597
598 /// Reads the value of `field` and ensures that its type is [`FromBytes`].
599 ///
600 /// # Safety
601 ///
602 /// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is
603 /// validated beforehand.
604 ///
605 /// Public but hidden since it should only be used from [`dma_read`] macro.
606 #[doc(hidden)]
607 pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F {
608 // SAFETY:
609 // - By the safety requirements field is valid.
610 // - Using read_volatile() here is not sound as per the usual rules, the usage here is
611 // a special exception with the following notes in place. When dealing with a potential
612 // race from a hardware or code outside kernel (e.g. user-space program), we need that
613 // read on a valid memory is not UB. Currently read_volatile() is used for this, and the
614 // rationale behind is that it should generate the same code as READ_ONCE() which the
615 // kernel already relies on to avoid UB on data races. Note that the usage of
616 // read_volatile() is limited to this particular case, it cannot be used to prevent
617 // the UB caused by racing between two kernel functions nor do they provide atomicity.
618 unsafe { field.read_volatile() }
619 }
620
621 /// Writes a value to `field` and ensures that its type is [`AsBytes`].
622 ///
623 /// # Safety
624 ///
625 /// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is
626 /// validated beforehand.
627 ///
628 /// Public but hidden since it should only be used from [`dma_write`] macro.
629 #[doc(hidden)]
630 pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) {
631 // SAFETY:
632 // - By the safety requirements field is valid.
633 // - Using write_volatile() here is not sound as per the usual rules, the usage here is
634 // a special exception with the following notes in place. When dealing with a potential
635 // race from a hardware or code outside kernel (e.g. user-space program), we need that
636 // write on a valid memory is not UB. Currently write_volatile() is used for this, and the
637 // rationale behind is that it should generate the same code as WRITE_ONCE() which the
638 // kernel already relies on to avoid UB on data races. Note that the usage of
639 // write_volatile() is limited to this particular case, it cannot be used to prevent
640 // the UB caused by racing between two kernel functions nor do they provide atomicity.
641 unsafe { field.write_volatile(val) }
642 }
643}
644
645impl<T: AsBytes + FromBytes> Coherent<T> {
646 /// Allocates a region of `T` of coherent memory.
647 fn alloc_with_attrs(
648 dev: &device::Device<Bound>,
649 gfp_flags: kernel::alloc::Flags,
650 dma_attrs: Attrs,
651 ) -> Result<Self> {
652 const {
653 assert!(
654 core::mem::size_of::<T>() > 0,
655 "It doesn't make sense for the allocated type to be a ZST"
656 );
657 }
658
659 let mut dma_handle = 0;
660 // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
661 let addr = unsafe {
662 bindings::dma_alloc_attrs(
663 dev.as_raw(),
664 core::mem::size_of::<T>(),
665 &mut dma_handle,
666 gfp_flags.as_raw(),
667 dma_attrs.as_raw(),
668 )
669 };
670 let cpu_addr = NonNull::new(addr.cast()).ok_or(ENOMEM)?;
671 // INVARIANT:
672 // - We just successfully allocated a coherent region which is adequately sized for `T`,
673 // hence the cpu address is valid.
674 // - We also hold a refcounted reference to the device.
675 Ok(Self {
676 dev: dev.into(),
677 dma_handle,
678 cpu_addr,
679 dma_attrs,
680 })
681 }
682
683 /// Allocates a region of type `T` of coherent memory.
684 ///
685 /// # Examples
686 ///
687 /// ```
688 /// # use kernel::device::{
689 /// # Bound,
690 /// # Device,
691 /// # };
692 /// use kernel::dma::{
693 /// attrs::*,
694 /// Coherent,
695 /// };
696 ///
697 /// # fn test(dev: &Device<Bound>) -> Result {
698 /// let c: Coherent<[u64; 4]> =
699 /// Coherent::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
700 /// # Ok::<(), Error>(()) }
701 /// ```
702 #[inline]
703 pub fn zeroed_with_attrs(
704 dev: &device::Device<Bound>,
705 gfp_flags: kernel::alloc::Flags,
706 dma_attrs: Attrs,
707 ) -> Result<Self> {
708 Self::alloc_with_attrs(dev, gfp_flags | __GFP_ZERO, dma_attrs)
709 }
710
711 /// Performs the same functionality as [`Coherent::zeroed_with_attrs`], except the
712 /// `dma_attrs` is 0 by default.
713 #[inline]
714 pub fn zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
715 Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
716 }
717
718 /// Same as [`Coherent::zeroed_with_attrs`], but instead of a zero-initialization the memory is
719 /// initialized with `init`.
720 pub fn init_with_attrs<E>(
721 dev: &device::Device<Bound>,
722 gfp_flags: kernel::alloc::Flags,
723 dma_attrs: Attrs,
724 init: impl Init<T, E>,
725 ) -> Result<Self>
726 where
727 Error: From<E>,
728 {
729 let dmem = Self::alloc_with_attrs(dev, gfp_flags, dma_attrs)?;
730 let ptr = dmem.as_mut_ptr();
731
732 // SAFETY:
733 // - `ptr` is valid, properly aligned, and points to exclusively owned memory.
734 // - If `__init` fails, `self` is dropped, which safely frees the underlying `Coherent`'s
735 // DMA memory. `T: AsBytes + FromBytes` ensures there are no complex `Drop` requirements
736 // we are bypassing.
737 unsafe { init.__init(ptr)? };
738
739 Ok(dmem)
740 }
741
742 /// Same as [`Coherent::zeroed`], but instead of a zero-initialization the memory is initialized
743 /// with `init`.
744 #[inline]
745 pub fn init<E>(
746 dev: &device::Device<Bound>,
747 gfp_flags: kernel::alloc::Flags,
748 init: impl Init<T, E>,
749 ) -> Result<Self>
750 where
751 Error: From<E>,
752 {
753 Self::init_with_attrs(dev, gfp_flags, Attrs(0), init)
754 }
755
756 /// Allocates a region of `[T; len]` of coherent memory.
757 fn alloc_slice_with_attrs(
758 dev: &device::Device<Bound>,
759 len: usize,
760 gfp_flags: kernel::alloc::Flags,
761 dma_attrs: Attrs,
762 ) -> Result<Coherent<[T]>> {
763 const {
764 assert!(
765 core::mem::size_of::<T>() > 0,
766 "It doesn't make sense for the allocated type to be a ZST"
767 );
768 }
769
770 // `dma_alloc_attrs` cannot handle zero-length allocation, bail early.
771 if len == 0 {
772 Err(EINVAL)?;
773 }
774
775 let size = core::mem::size_of::<T>().checked_mul(len).ok_or(ENOMEM)?;
776 let mut dma_handle = 0;
777 // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
778 let addr = unsafe {
779 bindings::dma_alloc_attrs(
780 dev.as_raw(),
781 size,
782 &mut dma_handle,
783 gfp_flags.as_raw(),
784 dma_attrs.as_raw(),
785 )
786 };
787 let cpu_addr = NonNull::slice_from_raw_parts(NonNull::new(addr.cast()).ok_or(ENOMEM)?, len);
788 // INVARIANT:
789 // - We just successfully allocated a coherent region which is adequately sized for
790 // `[T; len]`, hence the cpu address is valid.
791 // - We also hold a refcounted reference to the device.
792 Ok(Coherent {
793 dev: dev.into(),
794 dma_handle,
795 cpu_addr,
796 dma_attrs,
797 })
798 }
799
800 /// Allocates a zeroed region of type `T` of coherent memory.
801 ///
802 /// Unlike `Coherent::<[T; N]>::zeroed_with_attrs`, `Coherent::<T>::zeroed_slices` support
803 /// a runtime length.
804 ///
805 /// # Examples
806 ///
807 /// ```
808 /// # use kernel::device::{
809 /// # Bound,
810 /// # Device,
811 /// # };
812 /// use kernel::dma::{
813 /// attrs::*,
814 /// Coherent,
815 /// };
816 ///
817 /// # fn test(dev: &Device<Bound>) -> Result {
818 /// let c: Coherent<[u64]> =
819 /// Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
820 /// # Ok::<(), Error>(()) }
821 /// ```
822 #[inline]
823 pub fn zeroed_slice_with_attrs(
824 dev: &device::Device<Bound>,
825 len: usize,
826 gfp_flags: kernel::alloc::Flags,
827 dma_attrs: Attrs,
828 ) -> Result<Coherent<[T]>> {
829 Coherent::alloc_slice_with_attrs(dev, len, gfp_flags | __GFP_ZERO, dma_attrs)
830 }
831
832 /// Performs the same functionality as [`Coherent::zeroed_slice_with_attrs`], except the
833 /// `dma_attrs` is 0 by default.
834 #[inline]
835 pub fn zeroed_slice(
836 dev: &device::Device<Bound>,
837 len: usize,
838 gfp_flags: kernel::alloc::Flags,
839 ) -> Result<Coherent<[T]>> {
840 Self::zeroed_slice_with_attrs(dev, len, gfp_flags, Attrs(0))
841 }
842}
843
844impl<T> Coherent<[T]> {
845 /// Returns the number of elements `T` in this allocation.
846 ///
847 /// Note that this is not the size of the allocation in bytes, which is provided by
848 /// [`Self::size`].
849 #[inline]
850 #[expect(clippy::len_without_is_empty, reason = "Coherent slice is never empty")]
851 pub fn len(&self) -> usize {
852 self.cpu_addr.len()
853 }
854}
855
856/// Note that the device configured to do DMA must be halted before this object is dropped.
857impl<T: KnownSize + ?Sized> Drop for Coherent<T> {
858 fn drop(&mut self) {
859 let size = T::size(self.cpu_addr.as_ptr());
860 // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
861 // The cpu address, and the dma handle are valid due to the type invariants on
862 // `Coherent`.
863 unsafe {
864 bindings::dma_free_attrs(
865 self.dev.as_raw(),
866 size,
867 self.cpu_addr.as_ptr().cast(),
868 self.dma_handle,
869 self.dma_attrs.as_raw(),
870 )
871 }
872 }
873}
874
875// SAFETY: It is safe to send a `Coherent` to another thread if `T`
876// can be sent to another thread.
877unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<T> {}
878
879/// Reads a field of an item from an allocated region of structs.
880///
881/// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating
882/// to a [`Coherent`] and `proj` is a [projection specification](kernel::ptr::project!).
883///
884/// # Examples
885///
886/// ```
887/// use kernel::device::Device;
888/// use kernel::dma::{attrs::*, Coherent};
889///
890/// struct MyStruct { field: u32, }
891///
892/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
893/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
894/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
895/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
896///
897/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result {
898/// let whole = kernel::dma_read!(alloc, [2]?);
899/// let field = kernel::dma_read!(alloc, [1]?.field);
900/// # Ok::<(), Error>(()) }
901/// ```
902#[macro_export]
903macro_rules! dma_read {
904 ($dma:expr, $($proj:tt)*) => {{
905 let dma = &$dma;
906 let ptr = $crate::ptr::project!(
907 $crate::dma::Coherent::as_ptr(dma), $($proj)*
908 );
909 // SAFETY: The pointer created by the projection is within the DMA region.
910 unsafe { $crate::dma::Coherent::field_read(dma, ptr) }
911 }};
912}
913
914/// Writes to a field of an item from an allocated region of structs.
915///
916/// The syntax is of the form `kernel::dma_write!(dma, proj, val)` where `dma` is an expression
917/// evaluating to a [`Coherent`], `proj` is a
918/// [projection specification](kernel::ptr::project!), and `val` is the value to be written to the
919/// projected location.
920///
921/// # Examples
922///
923/// ```
924/// use kernel::device::Device;
925/// use kernel::dma::{attrs::*, Coherent};
926///
927/// struct MyStruct { member: u32, }
928///
929/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
930/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
931/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
932/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
933///
934/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result {
935/// kernel::dma_write!(alloc, [2]?.member, 0xf);
936/// kernel::dma_write!(alloc, [1]?, MyStruct { member: 0xf });
937/// # Ok::<(), Error>(()) }
938/// ```
939#[macro_export]
940macro_rules! dma_write {
941 (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) => {{
942 let dma = &$dma;
943 let ptr = $crate::ptr::project!(
944 mut $crate::dma::Coherent::as_mut_ptr(dma), $($proj)*
945 );
946 let val = $val;
947 // SAFETY: The pointer created by the projection is within the DMA region.
948 unsafe { $crate::dma::Coherent::field_write(dma, ptr, val) }
949 }};
950 (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => {
951 $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*])
952 };
953 (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr]? $($rest:tt)*]) => {
954 $crate::dma_write!(@parse [$dma] [$($proj)* [$index]?] [$($rest)*])
955 };
956 (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr] $($rest:tt)*]) => {
957 $crate::dma_write!(@parse [$dma] [$($proj)* [$index]] [$($rest)*])
958 };
959 ($dma:expr, $($rest:tt)*) => {
960 $crate::dma_write!(@parse [$dma] [] [$($rest)*])
961 };
962}