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 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 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}