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 prepare_for_device(&self) {
101 self.data.sync_for_device(0, core::mem::size_of::<T>());
102 }
103
104 pub fn complete_for_cpu(&self) {
105 self.data.sync_for_cpu(0, core::mem::size_of::<T>());
106 }
107
108 pub fn write_for_device(&mut self, value: T) {
109 self.write_cpu(value);
110 self.prepare_for_device();
111 }
112
113 pub fn modify_for_device(&mut self, f: impl FnOnce(&mut T)) {
114 self.modify_cpu(f);
115 self.prepare_for_device();
116 }
117
118 pub fn read_from_device(&self) -> T {
119 self.complete_for_cpu();
120 self.read_cpu()
121 }
122
123 pub fn as_ptr(&self) -> NonNull<T> {
124 self.data.handle().as_ptr().cast::<T>()
125 }
126
127 pub unsafe fn as_bytes_mut_cpu(&mut self) -> &mut [u8] {
132 self.data.as_mut_slice()
133 }
134}
135
136fn box_layout<T>(align: usize) -> Result<Layout, DmaError> {
137 Ok(Layout::from_size_align(
138 core::mem::size_of::<T>(),
139 align.max(core::mem::align_of::<T>()),
140 )?)
141}