xref: /linux/rust/kernel/dma.rs (revision dc1d9408c961c1c4d4b3b99a1d9390c17e13de71)
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 
7 use crate::{
8     bindings,
9     debugfs,
10     device::{
11         self,
12         Bound,
13         Core, //
14     },
15     error::to_result,
16     fs::file,
17     prelude::*,
18     ptr::KnownSize,
19     sync::aref::ARef,
20     transmute::{
21         AsBytes,
22         FromBytes, //
23     }, //
24     uaccess::UserSliceWriter,
25 };
26 use core::{
27     ops::{
28         Deref,
29         DerefMut, //
30     },
31     ptr::NonNull, //
32 };
33 
34 /// DMA address type.
35 ///
36 /// Represents a bus address used for Direct Memory Access (DMA) operations.
37 ///
38 /// This is an alias of the kernel's `dma_addr_t`, which may be `u32` or `u64` depending on
39 /// `CONFIG_ARCH_DMA_ADDR_T_64BIT`.
40 ///
41 /// Note that this may be `u64` even on 32-bit architectures.
42 pub type DmaAddress = bindings::dma_addr_t;
43 
44 /// Trait to be implemented by DMA capable bus devices.
45 ///
46 /// The [`dma::Device`](Device) trait should be implemented by bus specific device representations,
47 /// where the underlying bus is DMA capable, such as:
48 #[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")]
49 /// * [`platform::Device`](::kernel::platform::Device)
50 pub trait Device: AsRef<device::Device<Core>> {
51     /// Set up the device's DMA streaming addressing capabilities.
52     ///
53     /// This method is usually called once from `probe()` as soon as the device capabilities are
54     /// known.
55     ///
56     /// # Safety
57     ///
58     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
59     /// such as [`Coherent::zeroed`].
dma_set_mask(&self, mask: DmaMask) -> Result60     unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result {
61         // SAFETY:
62         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
63         // - The safety requirement of this function guarantees that there are no concurrent calls
64         //   to DMA allocation and mapping primitives using this mask.
65         to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) })
66     }
67 
68     /// Set up the device's DMA coherent addressing capabilities.
69     ///
70     /// This method is usually called once from `probe()` as soon as the device capabilities are
71     /// known.
72     ///
73     /// # Safety
74     ///
75     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
76     /// such as [`Coherent::zeroed`].
dma_set_coherent_mask(&self, mask: DmaMask) -> Result77     unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result {
78         // SAFETY:
79         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
80         // - The safety requirement of this function guarantees that there are no concurrent calls
81         //   to DMA allocation and mapping primitives using this mask.
82         to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) })
83     }
84 
85     /// Set up the device's DMA addressing capabilities.
86     ///
87     /// This is a combination of [`Device::dma_set_mask`] and [`Device::dma_set_coherent_mask`].
88     ///
89     /// This method is usually called once from `probe()` as soon as the device capabilities are
90     /// known.
91     ///
92     /// # Safety
93     ///
94     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
95     /// such as [`Coherent::zeroed`].
dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result96     unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result {
97         // SAFETY:
98         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
99         // - The safety requirement of this function guarantees that there are no concurrent calls
100         //   to DMA allocation and mapping primitives using this mask.
101         to_result(unsafe {
102             bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value())
103         })
104     }
105 
106     /// Set the maximum size of a single DMA segment the device may request.
107     ///
108     /// This method is usually called once from `probe()` as soon as the device capabilities are
109     /// known.
110     ///
111     /// # Safety
112     ///
113     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
114     /// such as [`Coherent::zeroed`].
dma_set_max_seg_size(&self, size: u32)115     unsafe fn dma_set_max_seg_size(&self, size: u32) {
116         // SAFETY:
117         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
118         // - The safety requirement of this function guarantees that there are no concurrent calls
119         //   to DMA allocation and mapping primitives using this parameter.
120         unsafe { bindings::dma_set_max_seg_size(self.as_ref().as_raw(), size) }
121     }
122 }
123 
124 /// A DMA mask that holds a bitmask with the lowest `n` bits set.
125 ///
126 /// Use [`DmaMask::new`] or [`DmaMask::try_new`] to construct a value. Values
127 /// are guaranteed to never exceed the bit width of `u64`.
128 ///
129 /// This is the Rust equivalent of the C macro `DMA_BIT_MASK()`.
130 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
131 pub struct DmaMask(u64);
132 
133 impl DmaMask {
134     /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
135     ///
136     /// For `n <= 64`, sets exactly the lowest `n` bits.
137     /// For `n > 64`, results in a build error.
138     ///
139     /// # Examples
140     ///
141     /// ```
142     /// use kernel::dma::DmaMask;
143     ///
144     /// let mask0 = DmaMask::new::<0>();
145     /// assert_eq!(mask0.value(), 0);
146     ///
147     /// let mask1 = DmaMask::new::<1>();
148     /// assert_eq!(mask1.value(), 0b1);
149     ///
150     /// let mask64 = DmaMask::new::<64>();
151     /// assert_eq!(mask64.value(), u64::MAX);
152     ///
153     /// // Build failure.
154     /// // let mask_overflow = DmaMask::new::<100>();
155     /// ```
156     #[inline]
new<const N: u32>() -> Self157     pub const fn new<const N: u32>() -> Self {
158         let Ok(mask) = Self::try_new(N) else {
159             build_error!("Invalid DMA Mask.");
160         };
161 
162         mask
163     }
164 
165     /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
166     ///
167     /// For `n <= 64`, sets exactly the lowest `n` bits.
168     /// For `n > 64`, returns [`EINVAL`].
169     ///
170     /// # Examples
171     ///
172     /// ```
173     /// use kernel::dma::DmaMask;
174     ///
175     /// let mask0 = DmaMask::try_new(0)?;
176     /// assert_eq!(mask0.value(), 0);
177     ///
178     /// let mask1 = DmaMask::try_new(1)?;
179     /// assert_eq!(mask1.value(), 0b1);
180     ///
181     /// let mask64 = DmaMask::try_new(64)?;
182     /// assert_eq!(mask64.value(), u64::MAX);
183     ///
184     /// let mask_overflow = DmaMask::try_new(100);
185     /// assert!(mask_overflow.is_err());
186     /// # Ok::<(), Error>(())
187     /// ```
188     #[inline]
try_new(n: u32) -> Result<Self>189     pub const fn try_new(n: u32) -> Result<Self> {
190         Ok(Self(match n {
191             0 => 0,
192             1..=64 => u64::MAX >> (64 - n),
193             _ => return Err(EINVAL),
194         }))
195     }
196 
197     /// Returns the underlying `u64` bitmask value.
198     #[inline]
value(&self) -> u64199     pub const fn value(&self) -> u64 {
200         self.0
201     }
202 }
203 
204 /// Possible attributes associated with a DMA mapping.
205 ///
206 /// They can be combined with the operators `|`, `&`, and `!`.
207 ///
208 /// Values can be used from the [`attrs`] module.
209 ///
210 /// # Examples
211 ///
212 /// ```
213 /// # use kernel::device::{Bound, Device};
214 /// use kernel::dma::{attrs::*, Coherent};
215 ///
216 /// # fn test(dev: &Device<Bound>) -> Result {
217 /// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
218 /// let c: Coherent<[u64]> =
219 ///     Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, attribs)?;
220 /// # Ok::<(), Error>(()) }
221 /// ```
222 #[derive(Clone, Copy, PartialEq)]
223 #[repr(transparent)]
224 pub struct Attrs(u32);
225 
226 impl Attrs {
227     /// Get the raw representation of this attribute.
as_raw(self) -> crate::ffi::c_ulong228     pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
229         self.0 as crate::ffi::c_ulong
230     }
231 
232     /// Check whether `flags` is contained in `self`.
contains(self, flags: Attrs) -> bool233     pub fn contains(self, flags: Attrs) -> bool {
234         (self & flags) == flags
235     }
236 }
237 
238 impl core::ops::BitOr for Attrs {
239     type Output = Self;
bitor(self, rhs: Self) -> Self::Output240     fn bitor(self, rhs: Self) -> Self::Output {
241         Self(self.0 | rhs.0)
242     }
243 }
244 
245 impl core::ops::BitAnd for Attrs {
246     type Output = Self;
bitand(self, rhs: Self) -> Self::Output247     fn bitand(self, rhs: Self) -> Self::Output {
248         Self(self.0 & rhs.0)
249     }
250 }
251 
252 impl core::ops::Not for Attrs {
253     type Output = Self;
not(self) -> Self::Output254     fn not(self) -> Self::Output {
255         Self(!self.0)
256     }
257 }
258 
259 /// DMA mapping attributes.
260 pub mod attrs {
261     use super::Attrs;
262 
263     /// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
264     /// and writes may pass each other.
265     pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
266 
267     /// Specifies that writes to the mapping may be buffered to improve performance.
268     pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
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)]
300 pub 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 
326 impl 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`.
const_cast(val: bindings::dma_data_direction) -> u32331     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 
350 impl From<DataDirection> for bindings::dma_data_direction {
351     /// Returns the raw representation of [`enum dma_data_direction`].
from(direction: DataDirection) -> Self352     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 /// ```
410 pub struct CoherentBox<T: KnownSize + ?Sized>(Coherent<T>);
411 
412 impl<T: AsBytes + FromBytes> CoherentBox<[T]> {
413     /// [`CoherentBox`] variant of [`Coherent::zeroed_slice_with_attrs`].
414     #[inline]
zeroed_slice_with_attrs( dev: &device::Device<Bound>, count: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self>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]
zeroed_slice( dev: &device::Device<Bound>, count: usize, gfp_flags: kernel::alloc::Flags, ) -> Result<Self>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.
init_at<E>(&mut self, i: usize, init: impl Init<T, E>) -> Result where Error: From<E>,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     /// Allocates a region of coherent memory of the same size as `data` and initializes it with a
458     /// copy of its contents.
459     ///
460     /// This is the [`CoherentBox`] variant of [`Coherent::from_slice_with_attrs`].
461     ///
462     /// # Examples
463     ///
464     /// ```
465     /// use core::ops::Deref;
466     ///
467     /// # use kernel::device::{Bound, Device};
468     /// use kernel::dma::{
469     ///     attrs::*,
470     ///     CoherentBox
471     /// };
472     ///
473     /// # fn test(dev: &Device<Bound>) -> Result {
474     /// let data = [0u8, 1u8, 2u8, 3u8];
475     /// let c: CoherentBox<[u8]> =
476     ///     CoherentBox::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
477     ///
478     /// assert_eq!(c.deref(), &data);
479     /// # Ok::<(), Error>(()) }
480     /// ```
from_slice_with_attrs( dev: &device::Device<Bound>, data: &[T], gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self> where T: Copy,481     pub fn from_slice_with_attrs(
482         dev: &device::Device<Bound>,
483         data: &[T],
484         gfp_flags: kernel::alloc::Flags,
485         dma_attrs: Attrs,
486     ) -> Result<Self>
487     where
488         T: Copy,
489     {
490         let mut slice = Self(Coherent::<T>::alloc_slice_with_attrs(
491             dev,
492             data.len(),
493             gfp_flags,
494             dma_attrs,
495         )?);
496 
497         // PANIC: `slice` was created with length `data.len()`.
498         slice.copy_from_slice(data);
499 
500         Ok(slice)
501     }
502 
503     /// Performs the same functionality as [`CoherentBox::from_slice_with_attrs`], except the
504     /// `dma_attrs` is 0 by default.
505     #[inline]
from_slice( dev: &device::Device<Bound>, data: &[T], gfp_flags: kernel::alloc::Flags, ) -> Result<Self> where T: Copy,506     pub fn from_slice(
507         dev: &device::Device<Bound>,
508         data: &[T],
509         gfp_flags: kernel::alloc::Flags,
510     ) -> Result<Self>
511     where
512         T: Copy,
513     {
514         Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
515     }
516 }
517 
518 impl<T: AsBytes + FromBytes> CoherentBox<T> {
519     /// Same as [`CoherentBox::zeroed_slice_with_attrs`], but for a single element.
520     #[inline]
zeroed_with_attrs( dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self>521     pub fn zeroed_with_attrs(
522         dev: &device::Device<Bound>,
523         gfp_flags: kernel::alloc::Flags,
524         dma_attrs: Attrs,
525     ) -> Result<Self> {
526         Coherent::zeroed_with_attrs(dev, gfp_flags, dma_attrs).map(Self)
527     }
528 
529     /// Same as [`CoherentBox::zeroed_slice`], but for a single element.
530     #[inline]
zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self>531     pub fn zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
532         Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
533     }
534 }
535 
536 impl<T: KnownSize + ?Sized> Deref for CoherentBox<T> {
537     type Target = T;
538 
539     #[inline]
deref(&self) -> &Self::Target540     fn deref(&self) -> &Self::Target {
541         // SAFETY:
542         // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
543         //   device.
544         // - We have exclusive access to `self.0`.
545         unsafe { self.0.as_ref() }
546     }
547 }
548 
549 impl<T: AsBytes + FromBytes + KnownSize + ?Sized> DerefMut for CoherentBox<T> {
550     #[inline]
deref_mut(&mut self) -> &mut Self::Target551     fn deref_mut(&mut self) -> &mut Self::Target {
552         // SAFETY:
553         // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
554         //   device.
555         // - We have exclusive access to `self.0`.
556         unsafe { self.0.as_mut() }
557     }
558 }
559 
560 impl<T: AsBytes + FromBytes + KnownSize + ?Sized> From<CoherentBox<T>> for Coherent<T> {
561     #[inline]
from(value: CoherentBox<T>) -> Self562     fn from(value: CoherentBox<T>) -> Self {
563         value.0
564     }
565 }
566 
567 /// An abstraction of the `dma_alloc_coherent` API.
568 ///
569 /// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
570 /// large coherent DMA regions.
571 ///
572 /// A [`Coherent`] instance contains a pointer to the allocated region (in the
573 /// processor's virtual address space) and the device address which can be given to the device
574 /// as the DMA address base of the region. The region is released once [`Coherent`]
575 /// is dropped.
576 ///
577 /// # Invariants
578 ///
579 /// - For the lifetime of an instance of [`Coherent`], the `cpu_addr` is a valid pointer
580 ///   to an allocated region of coherent memory and `dma_handle` is the DMA address base of the
581 ///   region.
582 /// - The size in bytes of the allocation is equal to size information via pointer.
583 // TODO
584 //
585 // DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
586 // reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure
587 // that device resources can never survive device unbind.
588 //
589 // However, it is neither desirable nor necessary to protect the allocated memory of the DMA
590 // allocation from surviving device unbind; it would require RCU read side critical sections to
591 // access the memory, which may require subsequent unnecessary copies.
592 //
593 // Hence, find a way to revoke the device resources of a `Coherent`, but not the
594 // entire `Coherent` including the allocated memory itself.
595 pub struct Coherent<T: KnownSize + ?Sized> {
596     dev: ARef<device::Device>,
597     dma_handle: DmaAddress,
598     cpu_addr: NonNull<T>,
599     dma_attrs: Attrs,
600 }
601 
602 impl<T: KnownSize + ?Sized> Coherent<T> {
603     /// Returns the size in bytes of this allocation.
604     #[inline]
size(&self) -> usize605     pub fn size(&self) -> usize {
606         T::size(self.cpu_addr.as_ptr())
607     }
608 
609     /// Returns the raw pointer to the allocated region in the CPU's virtual address space.
610     #[inline]
as_ptr(&self) -> *const T611     pub fn as_ptr(&self) -> *const T {
612         self.cpu_addr.as_ptr()
613     }
614 
615     /// Returns the raw pointer to the allocated region in the CPU's virtual address space as
616     /// a mutable pointer.
617     #[inline]
as_mut_ptr(&self) -> *mut T618     pub fn as_mut_ptr(&self) -> *mut T {
619         self.cpu_addr.as_ptr()
620     }
621 
622     /// Returns a DMA handle which may be given to the device as the DMA address base of
623     /// the region.
624     #[inline]
dma_handle(&self) -> DmaAddress625     pub fn dma_handle(&self) -> DmaAddress {
626         self.dma_handle
627     }
628 
629     /// Returns a reference to the data in the region.
630     ///
631     /// # Safety
632     ///
633     /// * Callers must ensure that the device does not read/write to/from memory while the returned
634     ///   slice is live.
635     /// * Callers must ensure that this call does not race with a write to the same region while
636     ///   the returned slice is live.
637     #[inline]
as_ref(&self) -> &T638     pub unsafe fn as_ref(&self) -> &T {
639         // SAFETY: per safety requirement.
640         unsafe { &*self.as_ptr() }
641     }
642 
643     /// Returns a mutable reference to the data in the region.
644     ///
645     /// # Safety
646     ///
647     /// * Callers must ensure that the device does not read/write to/from memory while the returned
648     ///   slice is live.
649     /// * Callers must ensure that this call does not race with a read or write to the same region
650     ///   while the returned slice is live.
651     #[expect(clippy::mut_from_ref, reason = "unsafe to use API")]
652     #[inline]
as_mut(&self) -> &mut T653     pub unsafe fn as_mut(&self) -> &mut T {
654         // SAFETY: per safety requirement.
655         unsafe { &mut *self.as_mut_ptr() }
656     }
657 
658     /// Reads the value of `field` and ensures that its type is [`FromBytes`].
659     ///
660     /// # Safety
661     ///
662     /// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is
663     /// validated beforehand.
664     ///
665     /// Public but hidden since it should only be used from [`dma_read`] macro.
666     #[doc(hidden)]
field_read<F: FromBytes>(&self, field: *const F) -> F667     pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F {
668         // SAFETY:
669         // - By the safety requirements field is valid.
670         // - Using read_volatile() here is not sound as per the usual rules, the usage here is
671         // a special exception with the following notes in place. When dealing with a potential
672         // race from a hardware or code outside kernel (e.g. user-space program), we need that
673         // read on a valid memory is not UB. Currently read_volatile() is used for this, and the
674         // rationale behind is that it should generate the same code as READ_ONCE() which the
675         // kernel already relies on to avoid UB on data races. Note that the usage of
676         // read_volatile() is limited to this particular case, it cannot be used to prevent
677         // the UB caused by racing between two kernel functions nor do they provide atomicity.
678         unsafe { field.read_volatile() }
679     }
680 
681     /// Writes a value to `field` and ensures that its type is [`AsBytes`].
682     ///
683     /// # Safety
684     ///
685     /// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is
686     /// validated beforehand.
687     ///
688     /// Public but hidden since it should only be used from [`dma_write`] macro.
689     #[doc(hidden)]
field_write<F: AsBytes>(&self, field: *mut F, val: F)690     pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) {
691         // SAFETY:
692         // - By the safety requirements field is valid.
693         // - Using write_volatile() here is not sound as per the usual rules, the usage here is
694         // a special exception with the following notes in place. When dealing with a potential
695         // race from a hardware or code outside kernel (e.g. user-space program), we need that
696         // write on a valid memory is not UB. Currently write_volatile() is used for this, and the
697         // rationale behind is that it should generate the same code as WRITE_ONCE() which the
698         // kernel already relies on to avoid UB on data races. Note that the usage of
699         // write_volatile() is limited to this particular case, it cannot be used to prevent
700         // the UB caused by racing between two kernel functions nor do they provide atomicity.
701         unsafe { field.write_volatile(val) }
702     }
703 }
704 
705 impl<T: AsBytes + FromBytes> Coherent<T> {
706     /// Allocates a region of `T` of coherent memory.
alloc_with_attrs( dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self>707     fn alloc_with_attrs(
708         dev: &device::Device<Bound>,
709         gfp_flags: kernel::alloc::Flags,
710         dma_attrs: Attrs,
711     ) -> Result<Self> {
712         const {
713             assert!(
714                 core::mem::size_of::<T>() > 0,
715                 "It doesn't make sense for the allocated type to be a ZST"
716             );
717         }
718 
719         let mut dma_handle = 0;
720         // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
721         let addr = unsafe {
722             bindings::dma_alloc_attrs(
723                 dev.as_raw(),
724                 core::mem::size_of::<T>(),
725                 &mut dma_handle,
726                 gfp_flags.as_raw(),
727                 dma_attrs.as_raw(),
728             )
729         };
730         let cpu_addr = NonNull::new(addr.cast()).ok_or(ENOMEM)?;
731         // INVARIANT:
732         // - We just successfully allocated a coherent region which is adequately sized for `T`,
733         //   hence the cpu address is valid.
734         // - We also hold a refcounted reference to the device.
735         Ok(Self {
736             dev: dev.into(),
737             dma_handle,
738             cpu_addr,
739             dma_attrs,
740         })
741     }
742 
743     /// Allocates a region of type `T` of coherent memory.
744     ///
745     /// # Examples
746     ///
747     /// ```
748     /// # use kernel::device::{
749     /// #     Bound,
750     /// #     Device,
751     /// # };
752     /// use kernel::dma::{
753     ///     attrs::*,
754     ///     Coherent,
755     /// };
756     ///
757     /// # fn test(dev: &Device<Bound>) -> Result {
758     /// let c: Coherent<[u64; 4]> =
759     ///     Coherent::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
760     /// # Ok::<(), Error>(()) }
761     /// ```
762     #[inline]
zeroed_with_attrs( dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self>763     pub fn zeroed_with_attrs(
764         dev: &device::Device<Bound>,
765         gfp_flags: kernel::alloc::Flags,
766         dma_attrs: Attrs,
767     ) -> Result<Self> {
768         Self::alloc_with_attrs(dev, gfp_flags | __GFP_ZERO, dma_attrs)
769     }
770 
771     /// Performs the same functionality as [`Coherent::zeroed_with_attrs`], except the
772     /// `dma_attrs` is 0 by default.
773     #[inline]
zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self>774     pub fn zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
775         Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
776     }
777 
778     /// Same as [`Coherent::zeroed_with_attrs`], but instead of a zero-initialization the memory is
779     /// initialized with `init`.
init_with_attrs<E>( dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, init: impl Init<T, E>, ) -> Result<Self> where Error: From<E>,780     pub fn init_with_attrs<E>(
781         dev: &device::Device<Bound>,
782         gfp_flags: kernel::alloc::Flags,
783         dma_attrs: Attrs,
784         init: impl Init<T, E>,
785     ) -> Result<Self>
786     where
787         Error: From<E>,
788     {
789         let dmem = Self::alloc_with_attrs(dev, gfp_flags, dma_attrs)?;
790         let ptr = dmem.as_mut_ptr();
791 
792         // SAFETY:
793         // - `ptr` is valid, properly aligned, and points to exclusively owned memory.
794         // - If `__init` fails, `self` is dropped, which safely frees the underlying `Coherent`'s
795         //   DMA memory. `T: AsBytes + FromBytes` ensures there are no complex `Drop` requirements
796         //   we are bypassing.
797         unsafe { init.__init(ptr)? };
798 
799         Ok(dmem)
800     }
801 
802     /// Same as [`Coherent::zeroed`], but instead of a zero-initialization the memory is initialized
803     /// with `init`.
804     #[inline]
init<E>( dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags, init: impl Init<T, E>, ) -> Result<Self> where Error: From<E>,805     pub fn init<E>(
806         dev: &device::Device<Bound>,
807         gfp_flags: kernel::alloc::Flags,
808         init: impl Init<T, E>,
809     ) -> Result<Self>
810     where
811         Error: From<E>,
812     {
813         Self::init_with_attrs(dev, gfp_flags, Attrs(0), init)
814     }
815 
816     /// Allocates a region of `[T; len]` of coherent memory.
alloc_slice_with_attrs( dev: &device::Device<Bound>, len: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Coherent<[T]>>817     fn alloc_slice_with_attrs(
818         dev: &device::Device<Bound>,
819         len: usize,
820         gfp_flags: kernel::alloc::Flags,
821         dma_attrs: Attrs,
822     ) -> Result<Coherent<[T]>> {
823         const {
824             assert!(
825                 core::mem::size_of::<T>() > 0,
826                 "It doesn't make sense for the allocated type to be a ZST"
827             );
828         }
829 
830         // `dma_alloc_attrs` cannot handle zero-length allocation, bail early.
831         if len == 0 {
832             Err(EINVAL)?;
833         }
834 
835         let size = core::mem::size_of::<T>().checked_mul(len).ok_or(ENOMEM)?;
836         let mut dma_handle = 0;
837         // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
838         let addr = unsafe {
839             bindings::dma_alloc_attrs(
840                 dev.as_raw(),
841                 size,
842                 &mut dma_handle,
843                 gfp_flags.as_raw(),
844                 dma_attrs.as_raw(),
845             )
846         };
847         let cpu_addr = NonNull::slice_from_raw_parts(NonNull::new(addr.cast()).ok_or(ENOMEM)?, len);
848         // INVARIANT:
849         // - We just successfully allocated a coherent region which is adequately sized for
850         //   `[T; len]`, hence the cpu address is valid.
851         // - We also hold a refcounted reference to the device.
852         Ok(Coherent {
853             dev: dev.into(),
854             dma_handle,
855             cpu_addr,
856             dma_attrs,
857         })
858     }
859 
860     /// Allocates a zeroed region of type `T` of coherent memory.
861     ///
862     /// Unlike `Coherent::<[T; N]>::zeroed_with_attrs`, `Coherent::<T>::zeroed_slices` support
863     /// a runtime length.
864     ///
865     /// # Examples
866     ///
867     /// ```
868     /// # use kernel::device::{
869     /// #     Bound,
870     /// #     Device,
871     /// # };
872     /// use kernel::dma::{
873     ///     attrs::*,
874     ///     Coherent,
875     /// };
876     ///
877     /// # fn test(dev: &Device<Bound>) -> Result {
878     /// let c: Coherent<[u64]> =
879     ///     Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
880     /// # Ok::<(), Error>(()) }
881     /// ```
882     #[inline]
zeroed_slice_with_attrs( dev: &device::Device<Bound>, len: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Coherent<[T]>>883     pub fn zeroed_slice_with_attrs(
884         dev: &device::Device<Bound>,
885         len: usize,
886         gfp_flags: kernel::alloc::Flags,
887         dma_attrs: Attrs,
888     ) -> Result<Coherent<[T]>> {
889         Coherent::alloc_slice_with_attrs(dev, len, gfp_flags | __GFP_ZERO, dma_attrs)
890     }
891 
892     /// Performs the same functionality as [`Coherent::zeroed_slice_with_attrs`], except the
893     /// `dma_attrs` is 0 by default.
894     #[inline]
zeroed_slice( dev: &device::Device<Bound>, len: usize, gfp_flags: kernel::alloc::Flags, ) -> Result<Coherent<[T]>>895     pub fn zeroed_slice(
896         dev: &device::Device<Bound>,
897         len: usize,
898         gfp_flags: kernel::alloc::Flags,
899     ) -> Result<Coherent<[T]>> {
900         Self::zeroed_slice_with_attrs(dev, len, gfp_flags, Attrs(0))
901     }
902 
903     /// Allocates a region of coherent memory of the same size as `data` and initializes it with a
904     /// copy of its contents.
905     ///
906     /// # Examples
907     ///
908     /// ```
909     /// # use kernel::device::{Bound, Device};
910     /// use kernel::dma::{
911     ///     attrs::*,
912     ///     Coherent
913     /// };
914     ///
915     /// # fn test(dev: &Device<Bound>) -> Result {
916     /// let data = [0u8, 1u8, 2u8, 3u8];
917     /// // `c` has the same content as `data`.
918     /// let c: Coherent<[u8]> =
919     ///     Coherent::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
920     ///
921     /// # Ok::<(), Error>(()) }
922     /// ```
923     #[inline]
from_slice_with_attrs( dev: &device::Device<Bound>, data: &[T], gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Coherent<[T]>> where T: Copy,924     pub fn from_slice_with_attrs(
925         dev: &device::Device<Bound>,
926         data: &[T],
927         gfp_flags: kernel::alloc::Flags,
928         dma_attrs: Attrs,
929     ) -> Result<Coherent<[T]>>
930     where
931         T: Copy,
932     {
933         CoherentBox::from_slice_with_attrs(dev, data, gfp_flags, dma_attrs).map(Into::into)
934     }
935 
936     /// Performs the same functionality as [`Coherent::from_slice_with_attrs`], except the
937     /// `dma_attrs` is 0 by default.
938     #[inline]
from_slice( dev: &device::Device<Bound>, data: &[T], gfp_flags: kernel::alloc::Flags, ) -> Result<Coherent<[T]>> where T: Copy,939     pub fn from_slice(
940         dev: &device::Device<Bound>,
941         data: &[T],
942         gfp_flags: kernel::alloc::Flags,
943     ) -> Result<Coherent<[T]>>
944     where
945         T: Copy,
946     {
947         Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
948     }
949 }
950 
951 impl<T> Coherent<[T]> {
952     /// Returns the number of elements `T` in this allocation.
953     ///
954     /// Note that this is not the size of the allocation in bytes, which is provided by
955     /// [`Self::size`].
956     #[inline]
957     #[expect(clippy::len_without_is_empty, reason = "Coherent slice is never empty")]
len(&self) -> usize958     pub fn len(&self) -> usize {
959         self.cpu_addr.len()
960     }
961 }
962 
963 /// Note that the device configured to do DMA must be halted before this object is dropped.
964 impl<T: KnownSize + ?Sized> Drop for Coherent<T> {
drop(&mut self)965     fn drop(&mut self) {
966         let size = T::size(self.cpu_addr.as_ptr());
967         // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
968         // The cpu address, and the dma handle are valid due to the type invariants on
969         // `Coherent`.
970         unsafe {
971             bindings::dma_free_attrs(
972                 self.dev.as_raw(),
973                 size,
974                 self.cpu_addr.as_ptr().cast(),
975                 self.dma_handle,
976                 self.dma_attrs.as_raw(),
977             )
978         }
979     }
980 }
981 
982 // SAFETY: It is safe to send a `Coherent` to another thread if `T`
983 // can be sent to another thread.
984 unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<T> {}
985 
986 // SAFETY: Sharing `&Coherent` across threads is safe if `T` is `Sync`, because all
987 // methods that access the buffer contents (`field_read`, `field_write`, `as_slice`,
988 // `as_slice_mut`) are `unsafe`, and callers are responsible for ensuring no data races occur.
989 // The safe methods only return metadata or raw pointers whose use requires `unsafe`.
990 unsafe impl<T: KnownSize + ?Sized + AsBytes + FromBytes + Sync> Sync for Coherent<T> {}
991 
992 impl<T: KnownSize + AsBytes + ?Sized> debugfs::BinaryWriter for Coherent<T> {
write_to_slice( &self, writer: &mut UserSliceWriter, offset: &mut file::Offset, ) -> Result<usize>993     fn write_to_slice(
994         &self,
995         writer: &mut UserSliceWriter,
996         offset: &mut file::Offset,
997     ) -> Result<usize> {
998         if offset.is_negative() {
999             return Err(EINVAL);
1000         }
1001 
1002         // If the offset is too large for a usize (e.g. on 32-bit platforms),
1003         // then consider that as past EOF and just return 0 bytes.
1004         let Ok(offset_val) = usize::try_from(*offset) else {
1005             return Ok(0);
1006         };
1007 
1008         let count = self.size().saturating_sub(offset_val).min(writer.len());
1009 
1010         writer.write_dma(self, offset_val, count)?;
1011 
1012         *offset += count as i64;
1013         Ok(count)
1014     }
1015 }
1016 
1017 /// An opaque DMA allocation without a kernel virtual mapping.
1018 ///
1019 /// Unlike [`Coherent`], a `CoherentHandle` does not provide CPU access to the allocated memory.
1020 /// The allocation is always performed with `DMA_ATTR_NO_KERNEL_MAPPING`, meaning no kernel
1021 /// virtual mapping is created for the buffer. The value returned by the C API as the CPU
1022 /// address is an opaque handle used only to free the allocation.
1023 ///
1024 /// This is useful for buffers that are only ever accessed by hardware.
1025 ///
1026 /// # Invariants
1027 ///
1028 /// - `cpu_handle` holds the opaque handle returned by `dma_alloc_attrs` with
1029 ///   `DMA_ATTR_NO_KERNEL_MAPPING` set, and is only valid for passing back to `dma_free_attrs`.
1030 /// - `dma_handle` is the corresponding bus address for device DMA.
1031 /// - `size` is the allocation size in bytes as passed to `dma_alloc_attrs`.
1032 /// - `dma_attrs` contains the attributes used for the allocation, always including
1033 ///   `DMA_ATTR_NO_KERNEL_MAPPING`.
1034 pub struct CoherentHandle {
1035     dev: ARef<device::Device>,
1036     dma_handle: DmaAddress,
1037     cpu_handle: NonNull<c_void>,
1038     size: usize,
1039     dma_attrs: Attrs,
1040 }
1041 
1042 impl CoherentHandle {
1043     /// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
1044     ///
1045     /// Additional DMA attributes may be passed via `dma_attrs`; `DMA_ATTR_NO_KERNEL_MAPPING` is
1046     /// always set implicitly.
1047     ///
1048     /// Returns `EINVAL` if `size` is zero, `ENOMEM` if the allocation fails.
alloc_with_attrs( dev: &device::Device<Bound>, size: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, ) -> Result<Self>1049     pub fn alloc_with_attrs(
1050         dev: &device::Device<Bound>,
1051         size: usize,
1052         gfp_flags: kernel::alloc::Flags,
1053         dma_attrs: Attrs,
1054     ) -> Result<Self> {
1055         if size == 0 {
1056             return Err(EINVAL);
1057         }
1058 
1059         let dma_attrs = dma_attrs | Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
1060         let mut dma_handle = 0;
1061         // SAFETY: `dev.as_raw()` is valid by the type invariant on `device::Device`.
1062         let cpu_handle = unsafe {
1063             bindings::dma_alloc_attrs(
1064                 dev.as_raw(),
1065                 size,
1066                 &mut dma_handle,
1067                 gfp_flags.as_raw(),
1068                 dma_attrs.as_raw(),
1069             )
1070         };
1071 
1072         let cpu_handle = NonNull::new(cpu_handle).ok_or(ENOMEM)?;
1073 
1074         // INVARIANT: `cpu_handle` is the opaque handle from a successful `dma_alloc_attrs` call
1075         // with `DMA_ATTR_NO_KERNEL_MAPPING`, `dma_handle` is the corresponding DMA address,
1076         // and we hold a refcounted reference to the device.
1077         Ok(Self {
1078             dev: dev.into(),
1079             dma_handle,
1080             cpu_handle,
1081             size,
1082             dma_attrs,
1083         })
1084     }
1085 
1086     /// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
1087     #[inline]
alloc( dev: &device::Device<Bound>, size: usize, gfp_flags: kernel::alloc::Flags, ) -> Result<Self>1088     pub fn alloc(
1089         dev: &device::Device<Bound>,
1090         size: usize,
1091         gfp_flags: kernel::alloc::Flags,
1092     ) -> Result<Self> {
1093         Self::alloc_with_attrs(dev, size, gfp_flags, Attrs(0))
1094     }
1095 
1096     /// Returns the DMA handle for this allocation.
1097     ///
1098     /// This address can be programmed into device hardware for DMA access.
1099     #[inline]
dma_handle(&self) -> DmaAddress1100     pub fn dma_handle(&self) -> DmaAddress {
1101         self.dma_handle
1102     }
1103 
1104     /// Returns the size in bytes of this allocation.
1105     #[inline]
size(&self) -> usize1106     pub fn size(&self) -> usize {
1107         self.size
1108     }
1109 }
1110 
1111 impl Drop for CoherentHandle {
drop(&mut self)1112     fn drop(&mut self) {
1113         // SAFETY: All values are valid by the type invariants on `CoherentHandle`.
1114         // `cpu_handle` is the opaque handle from `dma_alloc_attrs` and is passed back unchanged.
1115         unsafe {
1116             bindings::dma_free_attrs(
1117                 self.dev.as_raw(),
1118                 self.size,
1119                 self.cpu_handle.as_ptr(),
1120                 self.dma_handle,
1121                 self.dma_attrs.as_raw(),
1122             )
1123         }
1124     }
1125 }
1126 
1127 // SAFETY: `CoherentHandle` only holds a device reference, a DMA handle, an opaque CPU handle,
1128 // and a size. None of these are tied to a specific thread.
1129 unsafe impl Send for CoherentHandle {}
1130 
1131 // SAFETY: `CoherentHandle` provides no CPU access to the underlying allocation. The only
1132 // operations on `&CoherentHandle` are reading the DMA handle and size, both of which are
1133 // plain `Copy` values.
1134 unsafe impl Sync for CoherentHandle {}
1135 
1136 /// Reads a field of an item from an allocated region of structs.
1137 ///
1138 /// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating
1139 /// to a [`Coherent`] and `proj` is a [projection specification](kernel::ptr::project!).
1140 ///
1141 /// # Examples
1142 ///
1143 /// ```
1144 /// use kernel::device::Device;
1145 /// use kernel::dma::{attrs::*, Coherent};
1146 ///
1147 /// struct MyStruct { field: u32, }
1148 ///
1149 /// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
1150 /// unsafe impl kernel::transmute::FromBytes for MyStruct{};
1151 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
1152 /// unsafe impl kernel::transmute::AsBytes for MyStruct{};
1153 ///
1154 /// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result {
1155 /// let whole = kernel::dma_read!(alloc, [2]?);
1156 /// let field = kernel::dma_read!(alloc, [1]?.field);
1157 /// # Ok::<(), Error>(()) }
1158 /// ```
1159 #[macro_export]
1160 macro_rules! dma_read {
1161     ($dma:expr, $($proj:tt)*) => {{
1162         let dma = &$dma;
1163         let ptr = $crate::ptr::project!(
1164             $crate::dma::Coherent::as_ptr(dma), $($proj)*
1165         );
1166         // SAFETY: The pointer created by the projection is within the DMA region.
1167         unsafe { $crate::dma::Coherent::field_read(dma, ptr) }
1168     }};
1169 }
1170 
1171 /// Writes to a field of an item from an allocated region of structs.
1172 ///
1173 /// The syntax is of the form `kernel::dma_write!(dma, proj, val)` where `dma` is an expression
1174 /// evaluating to a [`Coherent`], `proj` is a
1175 /// [projection specification](kernel::ptr::project!), and `val` is the value to be written to the
1176 /// projected location.
1177 ///
1178 /// # Examples
1179 ///
1180 /// ```
1181 /// use kernel::device::Device;
1182 /// use kernel::dma::{attrs::*, Coherent};
1183 ///
1184 /// struct MyStruct { member: u32, }
1185 ///
1186 /// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
1187 /// unsafe impl kernel::transmute::FromBytes for MyStruct{};
1188 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
1189 /// unsafe impl kernel::transmute::AsBytes for MyStruct{};
1190 ///
1191 /// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result {
1192 /// kernel::dma_write!(alloc, [2]?.member, 0xf);
1193 /// kernel::dma_write!(alloc, [1]?, MyStruct { member: 0xf });
1194 /// # Ok::<(), Error>(()) }
1195 /// ```
1196 #[macro_export]
1197 macro_rules! dma_write {
1198     (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) => {{
1199         let dma = &$dma;
1200         let ptr = $crate::ptr::project!(
1201             mut $crate::dma::Coherent::as_mut_ptr(dma), $($proj)*
1202         );
1203         let val = $val;
1204         // SAFETY: The pointer created by the projection is within the DMA region.
1205         unsafe { $crate::dma::Coherent::field_write(dma, ptr, val) }
1206     }};
1207     (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => {
1208         $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*])
1209     };
1210     (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr]? $($rest:tt)*]) => {
1211         $crate::dma_write!(@parse [$dma] [$($proj)* [$index]?] [$($rest)*])
1212     };
1213     (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr] $($rest:tt)*]) => {
1214         $crate::dma_write!(@parse [$dma] [$($proj)* [$index]] [$($rest)*])
1215     };
1216     ($dma:expr, $($rest:tt)*) => {
1217         $crate::dma_write!(@parse [$dma] [] [$($rest)*])
1218     };
1219 }
1220