1use core::{alloc::Layout, marker::PhantomData, ptr::NonNull};
2
3use crate::{
4 DeviceDma, DmaAddr, DmaDirection, DmaDomainId, DmaError, DmaPod,
5 common::{AllocationKind, DmaAllocation},
6};
7
8pub struct CoherentArray<T: DmaPod> {
9 data: DmaAllocation,
10 _phantom: PhantomData<T>,
11}
12
13unsafe impl<T: DmaPod + Send> Send for CoherentArray<T> {}
14unsafe impl<T: DmaPod + Sync> Sync for CoherentArray<T> {}
15
16impl<T: DmaPod> CoherentArray<T> {
17 pub(crate) fn new_zero_with_align(
18 os: &DeviceDma,
19 len: usize,
20 align: usize,
21 ) -> Result<Self, DmaError> {
22 let layout = array_layout::<T>(len, align)?;
23 Ok(Self {
24 data: DmaAllocation::new_zero_coherent(os, layout)?,
25 _phantom: PhantomData,
26 })
27 }
28
29 pub(crate) fn new_zero(os: &DeviceDma, len: usize) -> Result<Self, DmaError> {
30 Self::new_zero_with_align(os, len, core::mem::align_of::<T>())
31 }
32
33 pub fn dma_addr(&self) -> DmaAddr {
34 self.data.handle().dma_addr()
35 }
36
37 pub fn len(&self) -> usize {
38 len_from_bytes::<T>(self.data.handle().size())
39 }
40
41 pub fn is_empty(&self) -> bool {
42 self.len() == 0
43 }
44
45 pub fn bytes_len(&self) -> usize {
46 self.data.handle().size()
47 }
48
49 pub fn read_cpu(&self, index: usize) -> Option<T> {
50 read_at(self.as_ptr(), self.len(), index)
51 }
52
53 pub fn set_cpu(&mut self, index: usize, value: T) {
54 write_at(self.as_ptr(), self.len(), index, value);
55 }
56
57 pub fn copy_from_slice_cpu(&mut self, src: &[T]) {
58 copy_from_slice(self.as_ptr(), self.len(), src);
59 }
60
61 pub fn iter_cpu(&self) -> ArrayCpuIter<'_, T, Self> {
62 ArrayCpuIter {
63 array: self,
64 index: 0,
65 _phantom: PhantomData,
66 }
67 }
68
69 pub fn write_with_cpu<R>(&mut self, len: usize, f: impl FnOnce(&mut [T]) -> R) -> R {
70 assert!(len <= self.len(), "range out of bounds");
71 let data = unsafe { self.as_mut_slice_cpu() };
72 f(&mut data[..len])
73 }
74
75 pub fn read_with_cpu<R>(&self, len: usize, f: impl FnOnce(&[T]) -> R) -> R {
76 assert!(len <= self.len(), "range out of bounds");
77 let data = unsafe { core::slice::from_raw_parts(self.as_ptr().as_ptr(), len) };
78 f(data)
79 }
80
81 pub fn as_ptr(&self) -> NonNull<T> {
82 self.data.handle().as_ptr().cast::<T>()
83 }
84
85 pub fn as_slice_cpu(&self) -> &[T] {
86 unsafe { core::slice::from_raw_parts(self.as_ptr().as_ptr(), self.len()) }
87 }
88
89 pub unsafe fn as_mut_slice_cpu(&mut self) -> &mut [T] {
94 unsafe { core::slice::from_raw_parts_mut(self.as_ptr().as_ptr(), self.len()) }
95 }
96
97 pub fn try_release(mut self) -> Result<(), DmaError> {
98 self.data.try_release()
99 }
100}
101
102pub struct ContiguousArray<T: DmaPod> {
103 data: DmaAllocation,
104 _phantom: PhantomData<T>,
105}
106
107unsafe impl<T: DmaPod + Send> Send for ContiguousArray<T> {}
108unsafe impl<T: DmaPod + Sync> Sync for ContiguousArray<T> {}
109
110impl<T: DmaPod> ContiguousArray<T> {
111 pub(crate) fn new_zero_with_align(
112 os: &DeviceDma,
113 len: usize,
114 align: usize,
115 direction: DmaDirection,
116 ) -> Result<Self, DmaError> {
117 let layout = array_layout::<T>(len, align)?;
118 Ok(Self {
119 data: DmaAllocation::new_zero_contiguous(os, layout, direction)?,
120 _phantom: PhantomData,
121 })
122 }
123
124 pub(crate) fn new_zero(
125 os: &DeviceDma,
126 len: usize,
127 direction: DmaDirection,
128 ) -> Result<Self, DmaError> {
129 Self::new_zero_with_align(os, len, core::mem::align_of::<T>(), direction)
130 }
131
132 pub fn dma_addr(&self) -> DmaAddr {
133 self.data.handle().dma_addr()
134 }
135
136 pub fn len(&self) -> usize {
137 len_from_bytes::<T>(self.data.handle().size())
138 }
139
140 pub fn is_empty(&self) -> bool {
141 self.len() == 0
142 }
143
144 pub fn bytes_len(&self) -> usize {
145 self.data.handle().size()
146 }
147
148 pub fn domain_id(&self) -> DmaDomainId {
149 self.data.device.domain_id()
150 }
151
152 pub fn direction(&self) -> DmaDirection {
153 match self.data.kind {
154 AllocationKind::Contiguous { direction } => direction,
155 AllocationKind::Coherent => unreachable!("ContiguousArray cannot hold coherent DMA"),
156 }
157 }
158
159 pub fn read_cpu(&self, index: usize) -> Option<T> {
160 read_at(self.as_ptr(), self.len(), index)
161 }
162
163 pub fn set_cpu(&mut self, index: usize, value: T) {
164 write_at(self.as_ptr(), self.len(), index, value);
165 }
166
167 pub fn copy_from_slice_cpu(&mut self, src: &[T]) {
168 copy_from_slice(self.as_ptr(), self.len(), src);
169 }
170
171 pub fn iter_cpu(&self) -> ArrayCpuIter<'_, T, Self> {
172 ArrayCpuIter {
173 array: self,
174 index: 0,
175 _phantom: PhantomData,
176 }
177 }
178
179 pub fn sync_for_device(&self, offset: usize, size: usize) {
180 self.check_range(offset, size);
181 self.data.sync_for_device(offset, size);
182 }
183
184 pub fn sync_for_cpu(&self, offset: usize, size: usize) {
185 self.check_range(offset, size);
186 self.data.sync_for_cpu(offset, size);
187 }
188
189 pub fn sync_for_device_all(&self) {
190 self.data.sync_for_device(0, self.bytes_len());
191 }
192
193 pub fn sync_for_cpu_all(&self) {
194 self.data.sync_for_cpu(0, self.bytes_len());
195 }
196
197 pub fn prepare_for_device(&self, offset: usize, size: usize) {
198 self.sync_for_device(offset, size);
199 }
200
201 pub fn prepare_for_device_all(&self) {
202 self.sync_for_device_all();
203 }
204
205 pub fn complete_for_cpu(&self, offset: usize, size: usize) {
206 self.sync_for_cpu(offset, size);
207 }
208
209 pub fn complete_for_cpu_all(&self) {
210 self.sync_for_cpu_all();
211 }
212
213 pub fn write_for_device<R>(&mut self, len: usize, f: impl FnOnce(&mut [T]) -> R) -> R {
214 let ret = self.write_with_cpu(len, f);
215 self.prepare_for_device(0, len * core::mem::size_of::<T>());
216 ret
217 }
218
219 pub fn read_from_device<R>(&self, len: usize, f: impl FnOnce(&[T]) -> R) -> R {
220 let size = len * core::mem::size_of::<T>();
221 self.complete_for_cpu(0, size);
222 self.read_with_cpu(len, f)
223 }
224
225 pub fn copy_to_device_from_slice(&mut self, src: &[T]) {
226 self.copy_from_slice_cpu(src);
227 self.prepare_for_device(0, core::mem::size_of_val(src));
228 }
229
230 pub fn copy_from_device_to_slice(&self, dst: &mut [T]) {
231 self.read_from_device(dst.len(), |src| dst.copy_from_slice(src));
232 }
233
234 pub fn write_with_cpu<R>(&mut self, len: usize, f: impl FnOnce(&mut [T]) -> R) -> R {
235 assert!(len <= self.len(), "range out of bounds");
236 {
237 let data = unsafe { self.as_mut_slice_cpu() };
238 f(&mut data[..len])
239 }
240 }
241
242 pub fn read_with_cpu<R>(&self, len: usize, f: impl FnOnce(&[T]) -> R) -> R {
243 assert!(len <= self.len(), "range out of bounds");
244 let data = unsafe { core::slice::from_raw_parts(self.as_ptr().as_ptr(), len) };
245 f(data)
246 }
247
248 pub fn as_ptr(&self) -> NonNull<T> {
249 self.data.handle().as_ptr().cast::<T>()
250 }
251
252 pub fn as_slice_cpu(&self) -> &[T] {
253 unsafe { core::slice::from_raw_parts(self.as_ptr().as_ptr(), self.len()) }
254 }
255
256 pub unsafe fn as_mut_slice_cpu(&mut self) -> &mut [T] {
261 unsafe { core::slice::from_raw_parts_mut(self.as_ptr().as_ptr(), self.len()) }
262 }
263
264 fn check_range(&self, offset: usize, size: usize) {
265 assert!(
266 offset <= self.bytes_len() && size <= self.bytes_len().saturating_sub(offset),
267 "range out of bounds, offset: {}, size: {}, bytes_len: {}",
268 offset,
269 size,
270 self.bytes_len()
271 );
272 }
273}
274
275pub trait DmaArrayCpuRead<T: DmaPod> {
276 fn len(&self) -> usize;
277 fn is_empty(&self) -> bool;
278 fn read_cpu(&self, index: usize) -> Option<T>;
279}
280
281impl<T: DmaPod> DmaArrayCpuRead<T> for CoherentArray<T> {
282 fn len(&self) -> usize {
283 CoherentArray::len(self)
284 }
285
286 fn is_empty(&self) -> bool {
287 CoherentArray::is_empty(self)
288 }
289
290 fn read_cpu(&self, index: usize) -> Option<T> {
291 CoherentArray::read_cpu(self, index)
292 }
293}
294
295impl<T: DmaPod> DmaArrayCpuRead<T> for ContiguousArray<T> {
296 fn len(&self) -> usize {
297 ContiguousArray::len(self)
298 }
299
300 fn is_empty(&self) -> bool {
301 ContiguousArray::is_empty(self)
302 }
303
304 fn read_cpu(&self, index: usize) -> Option<T> {
305 ContiguousArray::read_cpu(self, index)
306 }
307}
308
309pub struct ArrayCpuIter<'a, T: DmaPod, A: DmaArrayCpuRead<T>> {
310 array: &'a A,
311 index: usize,
312 _phantom: PhantomData<T>,
313}
314
315impl<'a, T: DmaPod, A: DmaArrayCpuRead<T>> Iterator for ArrayCpuIter<'a, T, A> {
316 type Item = T;
317
318 fn next(&mut self) -> Option<Self::Item> {
319 if self.index >= self.array.len() {
320 return None;
321 }
322 let value = self.array.read_cpu(self.index);
323 self.index += 1;
324 value
325 }
326}
327
328fn array_layout<T>(len: usize, align: usize) -> Result<Layout, DmaError> {
329 let size = len
330 .checked_mul(core::mem::size_of::<T>())
331 .ok_or(DmaError::LayoutError(
332 Layout::from_size_align(usize::MAX, 1).unwrap_err(),
333 ))?;
334 Ok(Layout::from_size_align(
335 size,
336 align.max(core::mem::align_of::<T>()),
337 )?)
338}
339
340fn len_from_bytes<T>(bytes: usize) -> usize {
341 if core::mem::size_of::<T>() == 0 {
342 0
343 } else {
344 bytes / core::mem::size_of::<T>()
345 }
346}
347
348fn read_at<T: DmaPod>(ptr: NonNull<T>, len: usize, index: usize) -> Option<T> {
349 if index >= len {
350 return None;
351 }
352 Some(unsafe { ptr.add(index).read() })
353}
354
355fn write_at<T: DmaPod>(ptr: NonNull<T>, len: usize, index: usize, value: T) {
356 assert!(
357 index < len,
358 "index out of range, index: {}, len: {}",
359 index,
360 len
361 );
362 unsafe { ptr.add(index).write(value) };
363}
364
365fn copy_from_slice<T: DmaPod>(ptr: NonNull<T>, len: usize, src: &[T]) {
366 assert!(
367 src.len() <= len,
368 "source slice is larger than DMA array, src len: {}, array len: {}",
369 src.len(),
370 len
371 );
372 unsafe {
373 ptr.as_ptr()
374 .copy_from_nonoverlapping(src.as_ptr(), src.len());
375 }
376}
377
378#[cfg(axtest)]
379pub(crate) fn array_helper_len_and_layout_rules_hold_for_test() -> bool {
380 assert!(len_from_bytes::<u8>(100) == 100);
382 assert!(len_from_bytes::<u16>(100) == 50);
383 assert!(len_from_bytes::<u32>(100) == 25);
384 assert!(len_from_bytes::<u64>(100) == 12);
385
386 let layout = array_layout::<u8>(100, 1);
388 assert!(layout.is_ok());
389 let l = layout.unwrap();
390 assert!(l.size() == 100);
391
392 let overflow = array_layout::<u8>(usize::MAX, 1);
394 assert!(overflow.is_err());
395
396 let bad_align = array_layout::<u8>(10, 3); assert!(bad_align.is_err());
399
400 assert!(len_from_bytes::<u32>(0) == 0);
402
403 let empty = array_layout::<u32>(0, 4);
405 assert!(empty.is_ok());
406 assert!(empty.unwrap().size() == 0);
407
408 assert!(len_from_bytes::<u16>(5) == 2); let large_align = array_layout::<u8>(16, 4096); assert!(large_align.is_ok());
414 assert!(large_align.unwrap().align() == 4096);
415
416 true
417}
418
419#[cfg(axtest)]
420pub(crate) fn array_contiguous_methods_hold_for_test() -> bool {
421 assert!(array_helper_len_and_layout_rules_hold_for_test());
424
425 assert!(len_from_bytes::<u8>(100) == 100);
427 assert!(len_from_bytes::<u16>(100) == 50);
428 assert!(len_from_bytes::<u32>(100) == 25);
429 assert!(len_from_bytes::<u64>(100) == 12);
430
431 true
432}
433
434#[cfg(axtest)]
435pub(crate) fn array_read_at_write_at_helpers_hold_for_test() -> bool {
436 assert!(len_from_bytes::<u8>(0) == 0);
439 assert!(len_from_bytes::<u32>(0) == 0);
440
441 let empty = array_layout::<u8>(0, 1);
443 assert!(empty.is_ok());
444 assert!(empty.unwrap().size() == 0);
445
446 true
447}
448
449#[cfg(axtest)]
450pub(crate) fn array_dma_array_cpu_read_trait_hold_for_test() -> bool {
451 assert!(len_from_bytes::<u8>(100) == 100);
454 assert!(len_from_bytes::<u16>(50) == 25);
455
456 true
457}
458
459#[cfg(axtest)]
460pub(crate) fn array_layout_edge_cases_comprehensive_hold_for_test() -> bool {
461 assert!(len_from_bytes::<()>(100) == 0);
465
466 let tiny = array_layout::<u8>(1, 1);
468 assert!(tiny.is_ok());
469 assert_eq!(tiny.unwrap().size(), 1);
470
471 assert!(array_layout::<u8>(10, 3).is_err());
473
474 assert!(array_layout::<u16>(5, 2).is_ok());
476
477 assert_eq!(len_from_bytes::<u32>(40), 10); assert_eq!(len_from_bytes::<u32>(42), 10); true
484}
485
486#[cfg(axtest)]
487pub(crate) fn array_copy_from_slice_and_write_at_edge_hold_for_test() -> bool {
488 assert_eq!(len_from_bytes::<u8>(0), 0);
492 assert_eq!(len_from_bytes::<u8>(1), 1);
493 assert_eq!(len_from_bytes::<u8>(255), 255);
494
495 assert_eq!(len_from_bytes::<u16>(0), 0);
497 assert_eq!(len_from_bytes::<u16>(2), 1);
498 assert_eq!(len_from_bytes::<u16>(3), 1); assert_eq!(len_from_bytes::<u16>(4), 2);
500
501 assert_eq!(len_from_bytes::<u64>(0), 0);
503 assert_eq!(len_from_bytes::<u64>(7), 0); assert_eq!(len_from_bytes::<u64>(8), 1);
505 assert_eq!(len_from_bytes::<u64>(15), 1); assert_eq!(len_from_bytes::<u64>(16), 2);
507
508 assert!(array_layout::<u8>(0, 1).is_ok());
511 assert!(array_layout::<u8>(1, 1).is_ok());
512 assert!(array_layout::<u8>(256, 1).is_ok());
513
514 assert!(array_layout::<u16>(1, 2).is_ok()); assert!(array_layout::<u16>(100, 2).is_ok()); assert!(array_layout::<u32>(10, 4).is_ok()); assert!(array_layout::<u32>(0, 4).is_ok()); assert!(array_layout::<u64>(5, 8).is_ok()); assert!(array_layout::<u8>(10, 3).is_err()); assert!(array_layout::<u8>(10, 5).is_err()); assert!(array_layout::<u8>(10, 6).is_err()); assert!(array_layout::<u8>(10, 7).is_err()); assert!(array_layout::<u8>(10, 9).is_err()); true
533}
534
535#[cfg(axtest)]
536pub(crate) fn array_layout_overflow_and_size_align_hold_for_test() -> bool {
537 let overflow_u8 = array_layout::<u8>(usize::MAX, 1);
541 assert!(overflow_u8.is_err());
542
543 let overflow_u16 = array_layout::<u16>(usize::MAX / 2 + 1, 2);
544 assert!(overflow_u16.is_err());
545
546 let overflow_u32 = array_layout::<u32>(usize::MAX / 4 + 1, 4);
547 assert!(overflow_u32.is_err());
548
549 let large = array_layout::<u8>(1024 * 1024, 4096);
551 assert!(large.is_ok());
552 let l = large.unwrap();
553 assert_eq!(l.size(), 1024 * 1024);
554 assert_eq!(l.align(), 4096);
555
556 assert!(array_layout::<u8>(0, 1).is_ok());
558 assert!(array_layout::<u8>(0, 2).is_ok());
559 assert!(array_layout::<u8>(0, 4).is_ok());
560 assert!(array_layout::<u8>(0, 8).is_ok());
561 assert!(array_layout::<u8>(0, 16).is_ok());
562 assert!(array_layout::<u8>(0, 32).is_ok());
563 assert!(array_layout::<u8>(0, 64).is_ok());
564 assert!(array_layout::<u8>(0, 128).is_ok());
565 assert!(array_layout::<u8>(0, 256).is_ok());
566 assert!(array_layout::<u8>(0, 512).is_ok());
567 assert!(array_layout::<u8>(0, 1024).is_ok());
568 assert!(array_layout::<u8>(0, 2048).is_ok());
569 assert!(array_layout::<u8>(0, 4096).is_ok());
570
571 let a1 = array_layout::<u8>(10, 16).unwrap();
574 assert_eq!(a1.align(), 16);
575
576 let a2 = array_layout::<u16>(10, 1).unwrap();
578 assert_eq!(a2.align(), 2); true
581}