Skip to main content

dma_api/
pool.rs

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}