Skip to main content

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}