xref: /linux/rust/kernel/dma.rs (revision bed87375f90f44cd2f9fe804a469274127d38593)
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     io::{
18         IoBackend,
19         IoBase,
20         IoCapable,
21         IoCopyable,
22         SysMem,
23         SysMemBackend, //
24     },
25     prelude::*,
26     ptr::KnownSize,
27     transmute::{
28         AsBytes,
29         FromBytes, //
30     },
31     uaccess::UserSliceWriter, //
32 };
33 use core::{
34     ops::{
35         Deref,
36         DerefMut, //
37     },
38     ptr::NonNull, //
39 };
40 
41 /// DMA address type.
42 ///
43 /// Represents a bus address used for Direct Memory Access (DMA) operations.
44 ///
45 /// This is an alias of the kernel's `dma_addr_t`, which may be `u32` or `u64` depending on
46 /// `CONFIG_ARCH_DMA_ADDR_T_64BIT`.
47 ///
48 /// Note that this may be `u64` even on 32-bit architectures.
49 pub type DmaAddress = bindings::dma_addr_t;
50 
51 /// Trait to be implemented by DMA capable bus devices.
52 ///
53 /// The [`dma::Device`](Device) trait should be implemented by bus specific device representations,
54 /// where the underlying bus is DMA capable, such as:
55 #[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")]
56 /// * [`platform::Device`](::kernel::platform::Device)
57 pub trait Device<'a>: AsRef<device::Device<Core<'a>>> {
58     /// Set up the device's DMA streaming addressing capabilities.
59     ///
60     /// This method is usually called once from `probe()` as soon as the device capabilities are
61     /// known.
62     ///
63     /// # Safety
64     ///
65     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
66     /// such as [`Coherent::zeroed`].
67     unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result {
68         // SAFETY:
69         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
70         // - The safety requirement of this function guarantees that there are no concurrent calls
71         //   to DMA allocation and mapping primitives using this mask.
72         to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) })
73     }
74 
75     /// Set up the device's DMA coherent addressing capabilities.
76     ///
77     /// This method is usually called once from `probe()` as soon as the device capabilities are
78     /// known.
79     ///
80     /// # Safety
81     ///
82     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
83     /// such as [`Coherent::zeroed`].
84     unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result {
85         // SAFETY:
86         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
87         // - The safety requirement of this function guarantees that there are no concurrent calls
88         //   to DMA allocation and mapping primitives using this mask.
89         to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) })
90     }
91 
92     /// Set up the device's DMA addressing capabilities.
93     ///
94     /// This is a combination of [`Device::dma_set_mask`] and [`Device::dma_set_coherent_mask`].
95     ///
96     /// This method is usually called once from `probe()` as soon as the device capabilities are
97     /// known.
98     ///
99     /// # Safety
100     ///
101     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
102     /// such as [`Coherent::zeroed`].
103     unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result {
104         // SAFETY:
105         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
106         // - The safety requirement of this function guarantees that there are no concurrent calls
107         //   to DMA allocation and mapping primitives using this mask.
108         to_result(unsafe {
109             bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value())
110         })
111     }
112 
113     /// Set the maximum size of a single DMA segment the device may request.
114     ///
115     /// This method is usually called once from `probe()` as soon as the device capabilities are
116     /// known.
117     ///
118     /// # Safety
119     ///
120     /// This method must not be called concurrently with any DMA allocation or mapping primitives,
121     /// such as [`Coherent::zeroed`].
122     unsafe fn dma_set_max_seg_size(&self, size: u32) {
123         // SAFETY:
124         // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
125         // - The safety requirement of this function guarantees that there are no concurrent calls
126         //   to DMA allocation and mapping primitives using this parameter.
127         unsafe { bindings::dma_set_max_seg_size(self.as_ref().as_raw(), size) }
128     }
129 }
130 
131 /// A DMA mask that holds a bitmask with the lowest `n` bits set.
132 ///
133 /// Use [`DmaMask::new`] or [`DmaMask::try_new`] to construct a value. Values
134 /// are guaranteed to never exceed the bit width of `u64`.
135 ///
136 /// This is the Rust equivalent of the C macro `DMA_BIT_MASK()`.
137 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
138 pub struct DmaMask(u64);
139 
140 impl DmaMask {
141     /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
142     ///
143     /// For `n <= 64`, sets exactly the lowest `n` bits.
144     /// For `n > 64`, results in a build error.
145     ///
146     /// # Examples
147     ///
148     /// ```
149     /// use kernel::dma::DmaMask;
150     ///
151     /// let mask0 = DmaMask::new::<0>();
152     /// assert_eq!(mask0.value(), 0);
153     ///
154     /// let mask1 = DmaMask::new::<1>();
155     /// assert_eq!(mask1.value(), 0b1);
156     ///
157     /// let mask64 = DmaMask::new::<64>();
158     /// assert_eq!(mask64.value(), u64::MAX);
159     ///
160     /// // Build failure.
161     /// // let mask_overflow = DmaMask::new::<100>();
162     /// ```
163     #[inline]
164     pub const fn new<const N: u32>() -> Self {
165         let Ok(mask) = Self::try_new(N) else {
166             build_error!("Invalid DMA Mask.");
167         };
168 
169         mask
170     }
171 
172     /// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
173     ///
174     /// For `n <= 64`, sets exactly the lowest `n` bits.
175     /// For `n > 64`, returns [`EINVAL`].
176     ///
177     /// # Examples
178     ///
179     /// ```
180     /// use kernel::dma::DmaMask;
181     ///
182     /// let mask0 = DmaMask::try_new(0)?;
183     /// assert_eq!(mask0.value(), 0);
184     ///
185     /// let mask1 = DmaMask::try_new(1)?;
186     /// assert_eq!(mask1.value(), 0b1);
187     ///
188     /// let mask64 = DmaMask::try_new(64)?;
189     /// assert_eq!(mask64.value(), u64::MAX);
190     ///
191     /// let mask_overflow = DmaMask::try_new(100);
192     /// assert!(mask_overflow.is_err());
193     /// # Ok::<(), Error>(())
194     /// ```
195     #[inline]
196     pub const fn try_new(n: u32) -> Result<Self> {
197         Ok(Self(match n {
198             0 => 0,
199             1..=64 => u64::MAX >> (64 - n),
200             _ => return Err(EINVAL),
201         }))
202     }
203 
204     /// Returns the underlying `u64` bitmask value.
205     #[inline]
206     pub const fn value(&self) -> u64 {
207         self.0
208     }
209 }
210 
211 /// Possible attributes associated with a DMA mapping.
212 ///
213 /// They can be combined with the operators `|`, `&`, and `!`.
214 ///
215 /// Values can be used from the [`attrs`] module.
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// # use kernel::device::{Bound, Device};
221 /// use kernel::dma::{attrs::*, Coherent};
222 ///
223 /// # fn test(dev: &Device<Bound>) -> Result {
224 /// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
225 /// let c: Coherent<'_, [u64]> =
226 ///     Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, attribs)?;
227 /// # Ok::<(), Error>(()) }
228 /// ```
229 #[derive(Clone, Copy, PartialEq)]
230 #[repr(transparent)]
231 pub struct Attrs(u32);
232 
233 impl Attrs {
234     /// Get the raw representation of this attribute.
235     pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
236         self.0 as crate::ffi::c_ulong
237     }
238 
239     /// Check whether `flags` is contained in `self`.
240     pub fn contains(self, flags: Attrs) -> bool {
241         (self & flags) == flags
242     }
243 }
244 
245 impl core::ops::BitOr for Attrs {
246     type Output = Self;
247     fn bitor(self, rhs: Self) -> Self::Output {
248         Self(self.0 | rhs.0)
249     }
250 }
251 
252 impl core::ops::BitAnd for Attrs {
253     type Output = Self;
254     fn bitand(self, rhs: Self) -> Self::Output {
255         Self(self.0 & rhs.0)
256     }
257 }
258 
259 impl core::ops::Not for Attrs {
260     type Output = Self;
261     fn not(self) -> Self::Output {
262         Self(!self.0)
263     }
264 }
265 
266 /// DMA mapping attributes.
267 pub mod attrs {
268     use super::Attrs;
269 
270     /// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
271     /// and writes may pass each other.
272     pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
273 
274     /// Specifies that writes to the mapping may be buffered to improve performance.
275     pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
276 
277     /// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming
278     /// that it has been already transferred to 'device' domain.
279     pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC);
280 
281     /// Forces contiguous allocation of the buffer in physical memory.
282     pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS);
283 
284     /// Hints DMA-mapping subsystem that it's probably not worth the time to try
285     /// to allocate memory to in a way that gives better TLB efficiency.
286     pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES);
287 
288     /// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
289     /// `__GFP_NOWARN`).
290     pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN);
291 
292     /// Indicates that the buffer is fully accessible at an elevated privilege level (and
293     /// ideally inaccessible or at least read-only at lesser-privileged levels).
294     pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED);
295 
296     /// Indicates that the buffer is MMIO memory.
297     pub const DMA_ATTR_MMIO: Attrs = Attrs(bindings::DMA_ATTR_MMIO);
298 }
299 
300 /// DMA data direction.
301 ///
302 /// Corresponds to the C [`enum dma_data_direction`].
303 ///
304 /// [`enum dma_data_direction`]: srctree/include/linux/dma-direction.h
305 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
306 #[repr(u32)]
307 pub enum DataDirection {
308     /// The DMA mapping is for bidirectional data transfer.
309     ///
310     /// This is used when the buffer can be both read from and written to by the device.
311     /// The cache for the corresponding memory region is both flushed and invalidated.
312     Bidirectional = Self::const_cast(bindings::dma_data_direction_DMA_BIDIRECTIONAL),
313 
314     /// The DMA mapping is for data transfer from memory to the device (write).
315     ///
316     /// The CPU has prepared data in the buffer, and the device will read it.
317     /// The cache for the corresponding memory region is flushed before device access.
318     ToDevice = Self::const_cast(bindings::dma_data_direction_DMA_TO_DEVICE),
319 
320     /// The DMA mapping is for data transfer from the device to memory (read).
321     ///
322     /// The device will write data into the buffer for the CPU to read.
323     /// The cache for the corresponding memory region is invalidated before CPU access.
324     FromDevice = Self::const_cast(bindings::dma_data_direction_DMA_FROM_DEVICE),
325 
326     /// The DMA mapping is not for data transfer.
327     ///
328     /// This is primarily for debugging purposes. With this direction, the DMA mapping API
329     /// will not perform any cache coherency operations.
330     None = Self::const_cast(bindings::dma_data_direction_DMA_NONE),
331 }
332 
333 impl DataDirection {
334     /// Casts the bindgen-generated enum type to a `u32` at compile time.
335     ///
336     /// This function will cause a compile-time error if the underlying value of the
337     /// C enum is out of bounds for `u32`.
338     const fn const_cast(val: bindings::dma_data_direction) -> u32 {
339         // CAST: The C standard allows compilers to choose different integer types for enums.
340         // To safely check the value, we cast it to a wide signed integer type (`i128`)
341         // which can hold any standard C integer enum type without truncation.
342         let wide_val = val as i128;
343 
344         // Check if the value is outside the valid range for the target type `u32`.
345         // CAST: `u32::MAX` is cast to `i128` to match the type of `wide_val` for the comparison.
346         if wide_val < 0 || wide_val > u32::MAX as i128 {
347             // Trigger a compile-time error in a const context.
348             build_error!("C enum value is out of bounds for the target type `u32`.");
349         }
350 
351         // CAST: This cast is valid because the check above guarantees that `wide_val`
352         // is within the representable range of `u32`.
353         wide_val as u32
354     }
355 }
356 
357 impl From<DataDirection> for bindings::dma_data_direction {
358     /// Returns the raw representation of [`enum dma_data_direction`].
359     fn from(direction: DataDirection) -> Self {
360         // CAST: `direction as u32` gets the underlying representation of our `#[repr(u32)]` enum.
361         // The subsequent cast to `Self` (the bindgen type) assumes the C enum is compatible
362         // with the enum variants of `DataDirection`, which is a valid assumption given our
363         // compile-time checks.
364         direction as u32 as Self
365     }
366 }
367 
368 /// CPU-owned DMA allocation that can be converted into a device-shared [`Coherent`] object.
369 ///
370 /// Unlike [`Coherent`], a [`CoherentBox`] is guaranteed to be fully owned by the CPU -- its DMA
371 /// address is not exposed and it cannot be accessed by a device. This means it can safely be used
372 /// like a normal boxed allocation (e.g. direct reads, writes, and mutable slices are all safe).
373 ///
374 /// A typical use is to allocate a [`CoherentBox`], populate it with normal CPU access, and then
375 /// convert it into a [`Coherent`] object to share it with the device.
376 ///
377 /// # Examples
378 ///
379 /// `CoherentBox<T>`:
380 ///
381 /// ```
382 /// # use kernel::device::{
383 /// #     Bound,
384 /// #     Device,
385 /// # };
386 /// use kernel::dma::{attrs::*,
387 ///     Coherent,
388 ///     CoherentBox,
389 /// };
390 ///
391 /// # fn test(dev: &Device<Bound>) -> Result {
392 /// let mut dmem: CoherentBox<'_, u64> = CoherentBox::zeroed(dev, GFP_KERNEL)?;
393 /// *dmem = 42;
394 /// let dmem: Coherent<'_, u64> = dmem.into();
395 /// # Ok::<(), Error>(()) }
396 /// ```
397 ///
398 /// `CoherentBox<[T]>`:
399 ///
400 ///
401 /// ```
402 /// # use kernel::device::{
403 /// #     Bound,
404 /// #     Device,
405 /// # };
406 /// use kernel::dma::{attrs::*,
407 ///     Coherent,
408 ///     CoherentBox,
409 /// };
410 ///
411 /// # fn test(dev: &Device<Bound>) -> Result {
412 /// let mut dmem: CoherentBox<'_, [u64]> = CoherentBox::zeroed_slice(dev, 4, GFP_KERNEL)?;
413 /// dmem.fill(42);
414 /// let dmem: Coherent<'_, [u64]> = dmem.into();
415 /// # Ok::<(), Error>(()) }
416 /// ```
417 pub struct CoherentBox<'a, T: KnownSize + ?Sized>(Coherent<'a, T>);
418 
419 impl<'a, T: AsBytes + FromBytes> CoherentBox<'a, [T]> {
420     /// [`CoherentBox`] variant of [`Coherent::zeroed_slice_with_attrs`].
421     #[inline]
422     pub fn zeroed_slice_with_attrs(
423         dev: &'a device::Device<Bound>,
424         count: usize,
425         gfp_flags: kernel::alloc::Flags,
426         dma_attrs: Attrs,
427     ) -> Result<Self> {
428         Coherent::zeroed_slice_with_attrs(dev, count, gfp_flags, dma_attrs).map(Self)
429     }
430 
431     /// Same as [CoherentBox::zeroed_slice_with_attrs], but with `dma::Attrs(0)`.
432     #[inline]
433     pub fn zeroed_slice(
434         dev: &'a device::Device<Bound>,
435         count: usize,
436         gfp_flags: kernel::alloc::Flags,
437     ) -> Result<Self> {
438         Self::zeroed_slice_with_attrs(dev, count, gfp_flags, Attrs(0))
439     }
440 
441     /// Initializes the element at `i` using the given initializer.
442     ///
443     /// Returns `EINVAL` if `i` is out of bounds.
444     pub fn init_at<E>(&mut self, i: usize, init: impl Init<T, E>) -> Result
445     where
446         Error: From<E>,
447     {
448         if i >= self.0.len() {
449             return Err(EINVAL);
450         }
451 
452         let ptr = &raw mut self[i];
453 
454         // SAFETY:
455         // - `ptr` is valid, properly aligned, and within this allocation.
456         // - `T: AsBytes + FromBytes` guarantees all bit patterns are valid, so partial writes on
457         //   error cannot leave the element in an invalid state.
458         // - The DMA address has not been exposed yet, so there is no concurrent device access.
459         unsafe { pin_init::raw_try_init(ptr, init)? };
460 
461         Ok(())
462     }
463 
464     /// Allocates a region of coherent memory of the same size as `data` and initializes it with a
465     /// copy of its contents.
466     ///
467     /// This is the [`CoherentBox`] variant of [`Coherent::from_slice_with_attrs`].
468     ///
469     /// # Examples
470     ///
471     /// ```
472     /// use core::ops::Deref;
473     ///
474     /// # use kernel::device::{Bound, Device};
475     /// use kernel::dma::{
476     ///     attrs::*,
477     ///     CoherentBox
478     /// };
479     ///
480     /// # fn test(dev: &Device<Bound>) -> Result {
481     /// let data = [0u8, 1u8, 2u8, 3u8];
482     /// let c: CoherentBox<'_, [u8]> =
483     ///     CoherentBox::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
484     ///
485     /// assert_eq!(c.deref(), &data);
486     /// # Ok::<(), Error>(()) }
487     /// ```
488     pub fn from_slice_with_attrs(
489         dev: &'a device::Device<Bound>,
490         data: &[T],
491         gfp_flags: kernel::alloc::Flags,
492         dma_attrs: Attrs,
493     ) -> Result<Self>
494     where
495         T: Copy,
496     {
497         let mut slice = Self(Coherent::<T>::alloc_slice_with_attrs(
498             dev,
499             data.len(),
500             gfp_flags,
501             dma_attrs,
502         )?);
503 
504         // PANIC: `slice` was created with length `data.len()`.
505         slice.copy_from_slice(data);
506 
507         Ok(slice)
508     }
509 
510     /// Performs the same functionality as [`CoherentBox::from_slice_with_attrs`], except the
511     /// `dma_attrs` is 0 by default.
512     #[inline]
513     pub fn from_slice(
514         dev: &'a device::Device<Bound>,
515         data: &[T],
516         gfp_flags: kernel::alloc::Flags,
517     ) -> Result<Self>
518     where
519         T: Copy,
520     {
521         Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
522     }
523 }
524 
525 impl<'a, T: AsBytes + FromBytes> CoherentBox<'a, T> {
526     /// Same as [`CoherentBox::zeroed_slice_with_attrs`], but for a single element.
527     #[inline]
528     pub fn zeroed_with_attrs(
529         dev: &'a device::Device<Bound>,
530         gfp_flags: kernel::alloc::Flags,
531         dma_attrs: Attrs,
532     ) -> Result<Self> {
533         Coherent::zeroed_with_attrs(dev, gfp_flags, dma_attrs).map(Self)
534     }
535 
536     /// Same as [`CoherentBox::zeroed_slice`], but for a single element.
537     #[inline]
538     pub fn zeroed(dev: &'a device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
539         Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
540     }
541 }
542 
543 impl<T: KnownSize + ?Sized> Deref for CoherentBox<'_, T> {
544     type Target = T;
545 
546     #[inline]
547     fn deref(&self) -> &Self::Target {
548         // SAFETY:
549         // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
550         //   device.
551         // - We have exclusive access to `self.0`.
552         unsafe { self.0.as_ref() }
553     }
554 }
555 
556 impl<T: AsBytes + FromBytes + KnownSize + ?Sized> DerefMut for CoherentBox<'_, T> {
557     #[inline]
558     fn deref_mut(&mut self) -> &mut Self::Target {
559         // SAFETY:
560         // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
561         //   device.
562         // - We have exclusive access to `self.0`.
563         unsafe { self.0.as_mut() }
564     }
565 }
566 
567 impl<'a, T: AsBytes + FromBytes + KnownSize + ?Sized> From<CoherentBox<'a, T>> for Coherent<'a, T> {
568     #[inline]
569     fn from(value: CoherentBox<'a, T>) -> Self {
570         value.0
571     }
572 }
573 
574 /// An abstraction of the `dma_alloc_coherent` API.
575 ///
576 /// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
577 /// large coherent DMA regions.
578 ///
579 /// A [`Coherent`] instance contains a pointer to the allocated region (in the
580 /// processor's virtual address space) and the device address which can be given to the device
581 /// as the DMA address base of the region. The region is released once [`Coherent`]
582 /// is dropped.
583 ///
584 /// # Invariants
585 ///
586 /// - For the lifetime of an instance of [`Coherent`], the `cpu_addr` is a valid pointer
587 ///   to an allocated region of coherent memory and `dma_addr` is the DMA address base of the
588 ///   region.
589 /// - The size in bytes of the allocation is equal to size information via pointer.
590 //
591 // The lifetime parameter ties DMA allocations to the device's bound scope, ensuring they are freed
592 // before the device is unbound under normal circumstances. However, if a `Coherent` is leaked (e.g.
593 // via `mem::forget`), device resources such as IOMMU mappings will not be released.  Making all
594 // constructors `unsafe` to prevent this is considered too restrictive for the common case; this
595 // soundness hole is accepted for now.
596 pub struct Coherent<'a, T: KnownSize + ?Sized> {
597     dev: &'a device::Device<Bound>,
598     dma_addr: DmaAddress,
599     cpu_addr: NonNull<T>,
600     dma_attrs: Attrs,
601 }
602 
603 impl<T: KnownSize + ?Sized> Coherent<'_, T> {
604     /// Returns the size in bytes of this allocation.
605     #[inline]
606     pub fn size(&self) -> usize {
607         T::size(self.cpu_addr.as_ptr())
608     }
609 
610     /// Returns the raw pointer to the allocated region in the CPU's virtual address space.
611     #[inline]
612     pub fn as_ptr(&self) -> *const T {
613         self.cpu_addr.as_ptr()
614     }
615 
616     /// Returns the raw pointer to the allocated region in the CPU's virtual address space as
617     /// a mutable pointer.
618     #[inline]
619     pub fn as_mut_ptr(&self) -> *mut T {
620         self.cpu_addr.as_ptr()
621     }
622 
623     /// Returns a DMA address which may be given to the device as the base of the region.
624     #[inline]
625     pub fn dma_address(&self) -> DmaAddress {
626         self.dma_addr
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]
638     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]
653     pub unsafe fn as_mut(&self) -> &mut T {
654         // SAFETY: per safety requirement.
655         unsafe { &mut *self.as_mut_ptr() }
656     }
657 }
658 
659 impl<'a, T: AsBytes + FromBytes> Coherent<'a, T> {
660     /// Allocates a region of `T` of coherent memory.
661     fn alloc_with_attrs(
662         dev: &'a device::Device<Bound>,
663         gfp_flags: kernel::alloc::Flags,
664         dma_attrs: Attrs,
665     ) -> Result<Self> {
666         const {
667             assert!(
668                 core::mem::size_of::<T>() > 0,
669                 "It doesn't make sense for the allocated type to be a ZST"
670             );
671         }
672 
673         let mut dma_addr = 0;
674         // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
675         let addr = unsafe {
676             bindings::dma_alloc_attrs(
677                 dev.as_raw(),
678                 core::mem::size_of::<T>(),
679                 &mut dma_addr,
680                 gfp_flags.as_raw(),
681                 dma_attrs.as_raw(),
682             )
683         };
684         let cpu_addr = NonNull::new(addr.cast()).ok_or(ENOMEM)?;
685         // INVARIANT:
686         // - We just successfully allocated a coherent region which is adequately sized for `T`,
687         //   hence the cpu address is valid.
688         // - `dev` is a valid reference to a bound device that outlives this allocation.
689         Ok(Self {
690             dev,
691             dma_addr,
692             cpu_addr,
693             dma_attrs,
694         })
695     }
696 
697     /// Allocates a region of type `T` of coherent memory.
698     ///
699     /// # Examples
700     ///
701     /// ```
702     /// # use kernel::device::{
703     /// #     Bound,
704     /// #     Device,
705     /// # };
706     /// use kernel::dma::{
707     ///     attrs::*,
708     ///     Coherent,
709     /// };
710     ///
711     /// # fn test(dev: &Device<Bound>) -> Result {
712     /// let c: Coherent<'_, [u64; 4]> =
713     ///     Coherent::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
714     /// # Ok::<(), Error>(()) }
715     /// ```
716     #[inline]
717     pub fn zeroed_with_attrs(
718         dev: &'a device::Device<Bound>,
719         gfp_flags: kernel::alloc::Flags,
720         dma_attrs: Attrs,
721     ) -> Result<Self> {
722         Self::alloc_with_attrs(dev, gfp_flags | __GFP_ZERO, dma_attrs)
723     }
724 
725     /// Performs the same functionality as [`Coherent::zeroed_with_attrs`], except the
726     /// `dma_attrs` is 0 by default.
727     #[inline]
728     pub fn zeroed(dev: &'a device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
729         Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
730     }
731 
732     /// Same as [`Coherent::zeroed_with_attrs`], but instead of a zero-initialization the memory is
733     /// initialized with `init`.
734     pub fn init_with_attrs<E>(
735         dev: &'a device::Device<Bound>,
736         gfp_flags: kernel::alloc::Flags,
737         dma_attrs: Attrs,
738         init: impl Init<T, E>,
739     ) -> Result<Self>
740     where
741         Error: From<E>,
742     {
743         let dmem = Self::alloc_with_attrs(dev, gfp_flags, dma_attrs)?;
744         let ptr = dmem.as_mut_ptr();
745 
746         // SAFETY:
747         // - `ptr` is valid, properly aligned, and points to exclusively owned memory.
748         // - If `raw_try_init` fails, `self` is dropped, which safely frees the underlying
749         //   `Coherent`'s DMA memory. `T: AsBytes + FromBytes` ensures there are no complex `Drop`
750         //   requirements we are bypassing.
751         unsafe { pin_init::raw_try_init(ptr, init)? };
752 
753         Ok(dmem)
754     }
755 
756     /// Same as [`Coherent::zeroed`], but instead of a zero-initialization the memory is initialized
757     /// with `init`.
758     #[inline]
759     pub fn init<E>(
760         dev: &'a device::Device<Bound>,
761         gfp_flags: kernel::alloc::Flags,
762         init: impl Init<T, E>,
763     ) -> Result<Self>
764     where
765         Error: From<E>,
766     {
767         Self::init_with_attrs(dev, gfp_flags, Attrs(0), init)
768     }
769 
770     /// Allocates a region of `[T; len]` of coherent memory.
771     fn alloc_slice_with_attrs(
772         dev: &'a device::Device<Bound>,
773         len: usize,
774         gfp_flags: kernel::alloc::Flags,
775         dma_attrs: Attrs,
776     ) -> Result<Coherent<'a, [T]>> {
777         const {
778             assert!(
779                 core::mem::size_of::<T>() > 0,
780                 "It doesn't make sense for the allocated type to be a ZST"
781             );
782         }
783 
784         // `dma_alloc_attrs` cannot handle zero-length allocation, bail early.
785         if len == 0 {
786             Err(EINVAL)?;
787         }
788 
789         let size = core::mem::size_of::<T>().checked_mul(len).ok_or(ENOMEM)?;
790         let mut dma_addr = 0;
791         // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
792         let addr = unsafe {
793             bindings::dma_alloc_attrs(
794                 dev.as_raw(),
795                 size,
796                 &mut dma_addr,
797                 gfp_flags.as_raw(),
798                 dma_attrs.as_raw(),
799             )
800         };
801         let cpu_addr = NonNull::slice_from_raw_parts(NonNull::new(addr.cast()).ok_or(ENOMEM)?, len);
802         // INVARIANT:
803         // - We just successfully allocated a coherent region which is adequately sized for
804         //   `[T; len]`, hence the cpu address is valid.
805         // - `dev` is a valid reference to a bound device that outlives this allocation.
806         Ok(Coherent {
807             dev,
808             dma_addr,
809             cpu_addr,
810             dma_attrs,
811         })
812     }
813 
814     /// Allocates a zeroed region of type `T` of coherent memory.
815     ///
816     /// Unlike `Coherent::<[T; N]>::zeroed_with_attrs`, `Coherent::<T>::zeroed_slices` support
817     /// a runtime length.
818     ///
819     /// # Examples
820     ///
821     /// ```
822     /// # use kernel::device::{
823     /// #     Bound,
824     /// #     Device,
825     /// # };
826     /// use kernel::dma::{
827     ///     attrs::*,
828     ///     Coherent,
829     /// };
830     ///
831     /// # fn test(dev: &Device<Bound>) -> Result {
832     /// let c: Coherent<'_, [u64]> =
833     ///     Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
834     /// # Ok::<(), Error>(()) }
835     /// ```
836     #[inline]
837     pub fn zeroed_slice_with_attrs(
838         dev: &'a device::Device<Bound>,
839         len: usize,
840         gfp_flags: kernel::alloc::Flags,
841         dma_attrs: Attrs,
842     ) -> Result<Coherent<'a, [T]>> {
843         Coherent::alloc_slice_with_attrs(dev, len, gfp_flags | __GFP_ZERO, dma_attrs)
844     }
845 
846     /// Performs the same functionality as [`Coherent::zeroed_slice_with_attrs`], except the
847     /// `dma_attrs` is 0 by default.
848     #[inline]
849     pub fn zeroed_slice(
850         dev: &'a device::Device<Bound>,
851         len: usize,
852         gfp_flags: kernel::alloc::Flags,
853     ) -> Result<Coherent<'a, [T]>> {
854         Self::zeroed_slice_with_attrs(dev, len, gfp_flags, Attrs(0))
855     }
856 
857     /// Allocates a region of coherent memory of the same size as `data` and initializes it with a
858     /// copy of its contents.
859     ///
860     /// # Examples
861     ///
862     /// ```
863     /// # use kernel::device::{Bound, Device};
864     /// use kernel::dma::{
865     ///     attrs::*,
866     ///     Coherent
867     /// };
868     ///
869     /// # fn test(dev: &Device<Bound>) -> Result {
870     /// let data = [0u8, 1u8, 2u8, 3u8];
871     /// // `c` has the same content as `data`.
872     /// let c: Coherent<'_, [u8]> =
873     ///     Coherent::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
874     ///
875     /// # Ok::<(), Error>(()) }
876     /// ```
877     #[inline]
878     pub fn from_slice_with_attrs(
879         dev: &'a device::Device<Bound>,
880         data: &[T],
881         gfp_flags: kernel::alloc::Flags,
882         dma_attrs: Attrs,
883     ) -> Result<Coherent<'a, [T]>>
884     where
885         T: Copy,
886     {
887         CoherentBox::from_slice_with_attrs(dev, data, gfp_flags, dma_attrs).map(Into::into)
888     }
889 
890     /// Performs the same functionality as [`Coherent::from_slice_with_attrs`], except the
891     /// `dma_attrs` is 0 by default.
892     #[inline]
893     pub fn from_slice(
894         dev: &'a device::Device<Bound>,
895         data: &[T],
896         gfp_flags: kernel::alloc::Flags,
897     ) -> Result<Coherent<'a, [T]>>
898     where
899         T: Copy,
900     {
901         Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
902     }
903 }
904 
905 impl<T> Coherent<'_, [T]> {
906     /// Returns the number of elements `T` in this allocation.
907     ///
908     /// Note that this is not the size of the allocation in bytes, which is provided by
909     /// [`Self::size`].
910     #[inline]
911     #[expect(clippy::len_without_is_empty, reason = "Coherent slice is never empty")]
912     pub fn len(&self) -> usize {
913         self.cpu_addr.len()
914     }
915 }
916 
917 /// Note that the device configured to do DMA must be halted before this object is dropped.
918 impl<T: KnownSize + ?Sized> Drop for Coherent<'_, T> {
919     fn drop(&mut self) {
920         let size = T::size(self.cpu_addr.as_ptr());
921         // SAFETY: Device pointer is guaranteed as valid by the lifetime of this `Coherent`.
922         // The cpu address, and the dma address are valid due to the type invariants on
923         // `Coherent`.
924         unsafe {
925             bindings::dma_free_attrs(
926                 self.dev.as_raw(),
927                 size,
928                 self.cpu_addr.as_ptr().cast(),
929                 self.dma_addr,
930                 self.dma_attrs.as_raw(),
931             )
932         }
933     }
934 }
935 
936 // SAFETY: It is safe to send a `Coherent` to another thread if `T`
937 // can be sent to another thread.
938 unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<'_, T> {}
939 
940 // SAFETY: Sharing `&Coherent` across threads is safe if `T` is `Sync`, because all
941 // methods that access the buffer contents (`field_read`, `field_write`, `as_slice`,
942 // `as_slice_mut`) are `unsafe`, and callers are responsible for ensuring no data races occur.
943 // The safe methods only return metadata or raw pointers whose use requires `unsafe`.
944 unsafe impl<T: KnownSize + ?Sized + AsBytes + FromBytes + Sync> Sync for Coherent<'_, T> {}
945 
946 impl<T: KnownSize + AsBytes + ?Sized> debugfs::BinaryWriter for Coherent<'_, T> {
947     fn write_to_slice(
948         &self,
949         writer: &mut UserSliceWriter,
950         offset: &mut file::Offset,
951     ) -> Result<usize> {
952         if offset.is_negative() {
953             return Err(EINVAL);
954         }
955 
956         // If the offset is too large for a usize (e.g. on 32-bit platforms),
957         // then consider that as past EOF and just return 0 bytes.
958         let Ok(offset_val) = usize::try_from(*offset) else {
959             return Ok(0);
960         };
961 
962         if offset_val >= self.size() {
963             return Ok(0);
964         }
965 
966         let count = (self.size() - offset_val).min(writer.len());
967 
968         writer.write_dma(self, offset_val, count)?;
969 
970         *offset += count as i64;
971         Ok(count)
972     }
973 }
974 
975 /// An opaque DMA allocation without a kernel virtual mapping.
976 ///
977 /// Unlike [`Coherent`], a `CoherentHandle` does not provide CPU access to the allocated memory.
978 /// The allocation is always performed with `DMA_ATTR_NO_KERNEL_MAPPING`, meaning no kernel
979 /// virtual mapping is created for the buffer. The value returned by the C API as the CPU
980 /// address is an opaque handle used only to free the allocation.
981 ///
982 /// This is useful for buffers that are only ever accessed by hardware.
983 ///
984 /// # Invariants
985 ///
986 /// - `cpu_handle` holds the opaque handle returned by `dma_alloc_attrs` with
987 ///   `DMA_ATTR_NO_KERNEL_MAPPING` set, and is only valid for passing back to `dma_free_attrs`.
988 /// - `dma_addr` is the corresponding bus address for device DMA.
989 /// - `size` is the allocation size in bytes as passed to `dma_alloc_attrs`.
990 /// - `dma_attrs` contains the attributes used for the allocation, always including
991 ///   `DMA_ATTR_NO_KERNEL_MAPPING`.
992 pub struct CoherentHandle<'a> {
993     dev: &'a device::Device<Bound>,
994     dma_addr: DmaAddress,
995     cpu_handle: NonNull<c_void>,
996     size: usize,
997     dma_attrs: Attrs,
998 }
999 
1000 impl<'a> CoherentHandle<'a> {
1001     /// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
1002     ///
1003     /// Additional DMA attributes may be passed via `dma_attrs`; `DMA_ATTR_NO_KERNEL_MAPPING` is
1004     /// always set implicitly.
1005     ///
1006     /// Returns `EINVAL` if `size` is zero, `ENOMEM` if the allocation fails.
1007     pub fn alloc_with_attrs(
1008         dev: &'a device::Device<Bound>,
1009         size: usize,
1010         gfp_flags: kernel::alloc::Flags,
1011         dma_attrs: Attrs,
1012     ) -> Result<Self> {
1013         if size == 0 {
1014             return Err(EINVAL);
1015         }
1016 
1017         let dma_attrs = dma_attrs | Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
1018         let mut dma_addr = 0;
1019         // SAFETY: `dev.as_raw()` is valid by the type invariant on `device::Device`.
1020         let cpu_handle = unsafe {
1021             bindings::dma_alloc_attrs(
1022                 dev.as_raw(),
1023                 size,
1024                 &mut dma_addr,
1025                 gfp_flags.as_raw(),
1026                 dma_attrs.as_raw(),
1027             )
1028         };
1029 
1030         let cpu_handle = NonNull::new(cpu_handle).ok_or(ENOMEM)?;
1031 
1032         // INVARIANT: `cpu_handle` is the opaque handle from a successful `dma_alloc_attrs` call
1033         // with `DMA_ATTR_NO_KERNEL_MAPPING`, `dma_addr` is the corresponding DMA address,
1034         // and `dev` is a valid reference to a bound device that outlives this allocation.
1035         Ok(Self {
1036             dev,
1037             dma_addr,
1038             cpu_handle,
1039             size,
1040             dma_attrs,
1041         })
1042     }
1043 
1044     /// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
1045     #[inline]
1046     pub fn alloc(
1047         dev: &'a device::Device<Bound>,
1048         size: usize,
1049         gfp_flags: kernel::alloc::Flags,
1050     ) -> Result<Self> {
1051         Self::alloc_with_attrs(dev, size, gfp_flags, Attrs(0))
1052     }
1053 
1054     /// Returns the DMA address for this allocation.
1055     ///
1056     /// This address can be programmed into device hardware for DMA access.
1057     #[inline]
1058     pub fn dma_address(&self) -> DmaAddress {
1059         self.dma_addr
1060     }
1061 
1062     /// Returns the size in bytes of this allocation.
1063     #[inline]
1064     pub fn size(&self) -> usize {
1065         self.size
1066     }
1067 }
1068 
1069 impl Drop for CoherentHandle<'_> {
1070     fn drop(&mut self) {
1071         // SAFETY: All values are valid by the type invariants on `CoherentHandle`.
1072         // `cpu_handle` is the opaque handle from `dma_alloc_attrs` and is passed back unchanged.
1073         unsafe {
1074             bindings::dma_free_attrs(
1075                 self.dev.as_raw(),
1076                 self.size,
1077                 self.cpu_handle.as_ptr(),
1078                 self.dma_addr,
1079                 self.dma_attrs.as_raw(),
1080             )
1081         }
1082     }
1083 }
1084 
1085 // SAFETY: `CoherentHandle` only holds a device reference, a DMA address, an opaque CPU handle,
1086 // and a size. None of these are tied to a specific thread.
1087 unsafe impl Send for CoherentHandle<'_> {}
1088 
1089 // SAFETY: `CoherentHandle` provides no CPU access to the underlying allocation. The only
1090 // operations on `&CoherentHandle` are reading the DMA address and size, both of which are
1091 // plain `Copy` values.
1092 unsafe impl Sync for CoherentHandle<'_> {}
1093 
1094 /// View type for `Coherent`.
1095 ///
1096 /// This is same as [`SysMem`] but with additional information that allows handing out a DMA
1097 /// address.
1098 pub struct CoherentView<'a, T: ?Sized> {
1099     cpu_addr: SysMem<'a, T>,
1100     dma_addr: DmaAddress,
1101 }
1102 
1103 impl<T: ?Sized> Copy for CoherentView<'_, T> {}
1104 impl<T: ?Sized> Clone for CoherentView<'_, T> {
1105     #[inline]
1106     fn clone(&self) -> Self {
1107         *self
1108     }
1109 }
1110 
1111 impl<'a, T: ?Sized> CoherentView<'a, T> {
1112     /// Erase the DMA address information and obtain a [`SysMem`] view of the same memory region.
1113     #[inline]
1114     pub fn as_sys_mem(self) -> SysMem<'a, T> {
1115         self.cpu_addr
1116     }
1117 
1118     /// Returns the DMA address which may be given to the device as base of the region.
1119     #[inline]
1120     pub fn dma_address(self) -> DmaAddress {
1121         self.dma_addr
1122     }
1123 
1124     /// Returns a reference to the data in the region.
1125     ///
1126     /// # Safety
1127     ///
1128     /// * Callers must ensure that the device does not read/write to/from memory while the returned
1129     ///   reference is live.
1130     /// * Callers must ensure that this call does not race with a write (including call to `as_mut`)
1131     ///   to the same region while the returned reference is live.
1132     #[inline]
1133     pub unsafe fn as_ref(self) -> &'a T {
1134         // SAFETY: pointer is aligned and valid per type invariant. Aliasing rule is satisfied per
1135         // safety requirement.
1136         unsafe { &*self.cpu_addr.as_ptr() }
1137     }
1138 
1139     /// Returns a mutable reference to the data in the region.
1140     ///
1141     /// # Safety
1142     ///
1143     /// * Callers must ensure that the device does not read/write to/from memory while the returned
1144     ///   reference is live.
1145     /// * Callers must ensure that this call does not race with a read (including call to `as_ref`)
1146     ///   or write (including call to `as_mut`) to the same region while the returned reference is
1147     ///   live.
1148     #[inline]
1149     pub unsafe fn as_mut(self) -> &'a mut T {
1150         // SAFETY: pointer is aligned and valid per type invariant. Aliasing rule is satisfied per
1151         // safety requirement.
1152         unsafe { &mut *self.cpu_addr.as_ptr() }
1153     }
1154 }
1155 
1156 /// `IoBackend` implementation for `Coherent`.
1157 pub struct CoherentIoBackend;
1158 
1159 impl IoBackend for CoherentIoBackend {
1160     type View<'a, T: ?Sized + KnownSize> = CoherentView<'a, T>;
1161 
1162     #[inline]
1163     fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
1164         SysMemBackend::as_ptr(view.cpu_addr)
1165     }
1166 
1167     #[inline]
1168     unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
1169         view: Self::View<'a, T>,
1170         ptr: *mut U,
1171     ) -> Self::View<'a, U> {
1172         let offset = ptr.addr() - view.cpu_addr.as_ptr().addr();
1173         // CAST: The offset DMA address can never overflow.
1174         let dma_addr = view.dma_addr + offset as DmaAddress;
1175         CoherentView {
1176             dma_addr,
1177             // SAFETY: Per safety requirement.
1178             cpu_addr: unsafe { SysMemBackend::project_view(view.cpu_addr, ptr) },
1179         }
1180     }
1181 }
1182 
1183 impl<T> IoCapable<T> for CoherentIoBackend
1184 where
1185     SysMemBackend: IoCapable<T>,
1186 {
1187     #[inline]
1188     fn io_read<'a>(view: Self::View<'a, T>) -> T {
1189         SysMemBackend::io_read(view.cpu_addr)
1190     }
1191 
1192     #[inline]
1193     fn io_write<'a>(view: Self::View<'a, T>, value: T) {
1194         SysMemBackend::io_write(view.cpu_addr, value)
1195     }
1196 }
1197 
1198 impl IoCopyable for CoherentIoBackend {
1199     #[inline]
1200     unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {
1201         // SAFETY: Per safety requirement.
1202         unsafe { SysMemBackend::copy_from_io(view.cpu_addr, buffer) }
1203     }
1204 
1205     #[inline]
1206     unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {
1207         // SAFETY: Per safety requirement.
1208         unsafe { SysMemBackend::copy_to_io(view.cpu_addr, buffer) }
1209     }
1210 
1211     #[inline]
1212     fn copy_read<T: zerocopy::FromBytes>(view: Self::View<'_, T>) -> T {
1213         SysMemBackend::copy_read(view.cpu_addr)
1214     }
1215 
1216     #[inline]
1217     fn copy_write<T: zerocopy::IntoBytes>(view: Self::View<'_, T>, value: T) {
1218         SysMemBackend::copy_write(view.cpu_addr, value)
1219     }
1220 }
1221 
1222 impl<'a, T: ?Sized + KnownSize> IoBase<'a> for CoherentView<'a, T> {
1223     type Backend = CoherentIoBackend;
1224     type Target = T;
1225 
1226     #[inline]
1227     fn as_view(self) -> CoherentView<'a, Self::Target> {
1228         self
1229     }
1230 }
1231 
1232 impl<'a, T: ?Sized + KnownSize> IoBase<'a> for &'a Coherent<'_, T> {
1233     type Backend = CoherentIoBackend;
1234     type Target = T;
1235 
1236     #[inline]
1237     fn as_view(self) -> CoherentView<'a, Self::Target> {
1238         CoherentView {
1239             // SAFETY: `cpu_addr` is valid and aligned kernel accessible memory.
1240             cpu_addr: unsafe { SysMem::new(self.cpu_addr.as_ptr()) },
1241             dma_addr: self.dma_addr,
1242         }
1243     }
1244 }
1245