1#[cfg(feature = "pool")]
2use alloc::{
3 collections::VecDeque,
4 sync::{Arc, Weak},
5};
6use core::ops::{Deref, DerefMut};
7
8#[cfg(feature = "pool")]
9use ax_sync::SpinLock as Mutex;
10
11use crate::ContiguousArray;
12#[cfg(feature = "pool")]
13use crate::{DeviceDma, DmaDirection, DmaError};
14
15#[cfg(feature = "pool")]
16#[derive(Clone, Debug)]
17pub(crate) struct ContiguousBufferConfig {
18 pub size: usize,
19 pub align: usize,
20 pub direction: DmaDirection,
21}
22
23#[cfg(feature = "pool")]
24#[derive(Clone)]
25pub struct ContiguousBufferPool {
26 inner: Arc<Mutex<Inner>>,
27}
28
29pub struct ContiguousBuffer {
30 data: Option<ContiguousArray<u8>>,
31 #[cfg(feature = "pool")]
32 pool: Weak<Mutex<Inner>>,
33}
34
35unsafe impl Send for ContiguousBuffer {}
36
37impl Deref for ContiguousBuffer {
38 type Target = ContiguousArray<u8>;
39
40 fn deref(&self) -> &Self::Target {
41 self.data.as_ref().unwrap()
42 }
43}
44
45impl DerefMut for ContiguousBuffer {
46 fn deref_mut(&mut self) -> &mut Self::Target {
47 self.data.as_mut().unwrap()
48 }
49}
50
51impl Drop for ContiguousBuffer {
52 fn drop(&mut self) {
53 #[cfg(feature = "pool")]
54 if let Some(data) = self.data.take()
55 && let Some(pool) = self.pool.upgrade()
56 {
57 let mut inner = pool.lock_irqsave();
58 inner.dealloc(data);
59 }
60 }
61}
62
63#[cfg(feature = "pool")]
64struct Inner {
65 dev: DeviceDma,
66 config: ContiguousBufferConfig,
67 pool: VecDeque<ContiguousArray<u8>>,
68}
69
70#[cfg(feature = "pool")]
71impl Inner {
72 fn alloc(&mut self) -> Option<ContiguousArray<u8>> {
73 self.pool.pop_front()
74 }
75
76 fn dealloc(&mut self, data: ContiguousArray<u8>) {
77 self.pool.push_back(data);
78 }
79}
80
81#[cfg(feature = "pool")]
82impl ContiguousBufferPool {
83 pub(crate) fn with_capacity(
84 dev: DeviceDma,
85 config: ContiguousBufferConfig,
86 cap: usize,
87 ) -> ContiguousBufferPool {
88 let mut pool = VecDeque::with_capacity(cap);
89 for _ in 0..cap {
90 if let Ok(data) = ContiguousArray::new_zero_with_align(
91 &dev,
92 config.size,
93 config.align,
94 config.direction,
95 ) {
96 pool.push_back(data);
97 }
98 }
99
100 ContiguousBufferPool {
101 inner: Arc::new(Mutex::new(Inner { dev, pool, config })),
102 }
103 }
104
105 pub fn alloc(&self) -> Result<ContiguousBuffer, DmaError> {
106 let config;
107 let dev;
108 {
109 let mut inner = self.inner.lock_irqsave();
110 if let Some(data) = inner.alloc() {
111 return Ok(ContiguousBuffer {
112 data: Some(data),
113 pool: Arc::downgrade(&self.inner),
114 });
115 } else {
116 config = inner.config.clone();
117 dev = inner.dev.clone();
118 }
119 };
120
121 let data = ContiguousArray::new_zero_with_align(
122 &dev,
123 config.size,
124 config.align,
125 config.direction,
126 )?;
127 Ok(ContiguousBuffer {
128 data: Some(data),
129 pool: Arc::downgrade(&self.inner),
130 })
131 }
132}