Skip to main content

dma_api/
dbox.rs

1use core::{alloc::Layout, marker::PhantomData, ptr::NonNull};
2
3use crate::{DeviceDma, DmaAddr, DmaDirection, DmaError, DmaPod, common::DmaAllocation};
4
5pub struct CoherentBox<T: DmaPod> {
6    data: DmaAllocation,
7    _marker: PhantomData<T>,
8}
9
10unsafe impl<T: DmaPod + Send> Send for CoherentBox<T> {}
11unsafe impl<T: DmaPod + Sync> Sync for CoherentBox<T> {}
12
13impl<T: DmaPod> CoherentBox<T> {
14    pub(crate) fn new_zero(os: &DeviceDma) -> Result<Self, DmaError> {
15        Self::new_zero_with_align(os, core::mem::align_of::<T>())
16    }
17
18    pub(crate) fn new_zero_with_align(os: &DeviceDma, align: usize) -> Result<Self, DmaError> {
19        let data = DmaAllocation::new_zero_coherent(os, box_layout::<T>(align)?)?;
20        Ok(Self {
21            data,
22            _marker: PhantomData,
23        })
24    }
25
26    pub fn dma_addr(&self) -> DmaAddr {
27        self.data.handle.dma_addr()
28    }
29
30    pub fn read_cpu(&self) -> T {
31        unsafe { self.as_ptr().read() }
32    }
33
34    pub fn write_cpu(&mut self, value: T) {
35        unsafe { self.as_ptr().write(value) };
36    }
37
38    pub fn modify_cpu(&mut self, f: impl FnOnce(&mut T)) {
39        let mut value = self.read_cpu();
40        f(&mut value);
41        self.write_cpu(value);
42    }
43
44    pub fn as_ptr(&self) -> NonNull<T> {
45        self.data.handle.as_ptr().cast::<T>()
46    }
47
48    /// # Safety
49    ///
50    /// The caller must ensure the device is not concurrently accessing this
51    /// memory in a way that races with CPU writes.
52    pub unsafe fn as_bytes_mut_cpu(&mut self) -> &mut [u8] {
53        self.data.as_mut_slice()
54    }
55}
56
57pub struct ContiguousBox<T: DmaPod> {
58    data: DmaAllocation,
59    _marker: PhantomData<T>,
60}
61
62unsafe impl<T: DmaPod + Send> Send for ContiguousBox<T> {}
63unsafe impl<T: DmaPod + Sync> Sync for ContiguousBox<T> {}
64
65impl<T: DmaPod> ContiguousBox<T> {
66    pub(crate) fn new_zero(os: &DeviceDma, direction: DmaDirection) -> Result<Self, DmaError> {
67        Self::new_zero_with_align(os, core::mem::align_of::<T>(), direction)
68    }
69
70    pub(crate) fn new_zero_with_align(
71        os: &DeviceDma,
72        align: usize,
73        direction: DmaDirection,
74    ) -> Result<Self, DmaError> {
75        let data = DmaAllocation::new_zero_contiguous(os, box_layout::<T>(align)?, direction)?;
76        Ok(Self {
77            data,
78            _marker: PhantomData,
79        })
80    }
81
82    pub fn dma_addr(&self) -> DmaAddr {
83        self.data.handle.dma_addr()
84    }
85
86    pub fn read_cpu(&self) -> T {
87        unsafe { self.as_ptr().read() }
88    }
89
90    pub fn write_cpu(&mut self, value: T) {
91        unsafe { self.as_ptr().write(value) };
92    }
93
94    pub fn modify_cpu(&mut self, f: impl FnOnce(&mut T)) {
95        let mut value = self.read_cpu();
96        f(&mut value);
97        self.write_cpu(value);
98    }
99
100    pub fn sync_for_device_all(&self) {
101        self.data.sync_for_device(0, core::mem::size_of::<T>());
102    }
103
104    pub fn sync_for_cpu_all(&self) {
105        self.data.sync_for_cpu(0, core::mem::size_of::<T>());
106    }
107
108    pub fn prepare_for_device_all(&self) {
109        self.sync_for_device_all();
110    }
111
112    pub fn complete_for_cpu_all(&self) {
113        self.sync_for_cpu_all();
114    }
115
116    pub fn write_for_device(&mut self, value: T) {
117        self.write_cpu(value);
118        self.prepare_for_device_all();
119    }
120
121    pub fn modify_for_device(&mut self, f: impl FnOnce(&mut T)) {
122        self.modify_cpu(f);
123        self.prepare_for_device_all();
124    }
125
126    pub fn read_from_device(&self) -> T {
127        self.complete_for_cpu_all();
128        self.read_cpu()
129    }
130
131    pub fn as_ptr(&self) -> NonNull<T> {
132        self.data.handle.as_ptr().cast::<T>()
133    }
134
135    /// # Safety
136    ///
137    /// The caller must ensure the device is not concurrently accessing this
138    /// memory in a way that races with CPU writes.
139    pub unsafe fn as_bytes_mut_cpu(&mut self) -> &mut [u8] {
140        self.data.as_mut_slice()
141    }
142}
143
144fn box_layout<T>(align: usize) -> Result<Layout, DmaError> {
145    Ok(Layout::from_size_align(
146        core::mem::size_of::<T>(),
147        align.max(core::mem::align_of::<T>()),
148    )?)
149}