dma_api/lib.rs
1#![cfg_attr(target_os = "none", no_std)]
2#![doc = include_str!("../README.md")]
3
4extern crate alloc;
5
6use core::{num::NonZeroUsize, ops::Deref, ptr::NonNull};
7
8mod osal;
9
10mod array;
11mod common;
12mod dbox;
13mod def;
14mod map_single;
15mod pool;
16
17pub use array::*;
18pub use dbox::*;
19pub use def::*;
20pub use map_single::*;
21pub use osal::DmaOp;
22pub use pool::*;
23
24impl Deref for DmaHandle {
25 type Target = core::alloc::Layout;
26 fn deref(&self) -> &Self::Target {
27 &self.layout
28 }
29}
30
31/// DMA 设备操作接口。
32///
33/// `DeviceDma` 是用于执行 DMA 操作的主要入口点,封装了平台特定的
34/// `DmaOp` 实现,并提供了分配、映射和管理 DMA 内存的方法。
35///
36/// # 创建
37///
38/// 使用 [`DeviceDma::new()`] 创建实例,需要提供:
39/// - `dma_mask`: 设备可寻址的地址掩码(如 `0xFFFFFFFF` 表示 32 位设备)
40/// - `osal`: 实现 `DmaOp` trait 的平台抽象层
41///
42/// # 示例
43///
44/// ```rust,ignore
45/// use dma_api::DeviceDma;
46///
47/// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
48/// ```
49#[derive(Clone)]
50pub struct DeviceDma {
51 os: &'static dyn DmaOp,
52 mask: u64,
53}
54
55impl DeviceDma {
56 /// 创建新的 DMA 设备实例。
57 ///
58 /// # 参数
59 ///
60 /// - `dma_mask`: 设备 DMA 地址掩码,指定设备可寻址的地址范围
61 /// - `0xFFFFFFFF`: 32 位设备(最多 4GB)
62 /// - `0xFFFFFFFFFFFFFFFF`: 64 位设备(全地址空间)
63 /// - `osal`: 实现 `DmaOp` trait 的平台抽象层引用
64 ///
65 /// # 示例
66 ///
67 /// ```rust,ignore
68 /// use dma_api::DeviceDma;
69 ///
70 /// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
71 /// ```
72 pub fn new(dma_mask: u64, osal: &'static dyn DmaOp) -> Self {
73 Self {
74 mask: dma_mask,
75 os: osal,
76 }
77 }
78
79 /// 获取设备的 DMA 地址掩码。
80 ///
81 /// # 返回
82 ///
83 /// 返回设备的 DMA 掩码值,表示设备可寻址的最大地址范围。
84 pub fn dma_mask(&self) -> u64 {
85 self.mask
86 }
87
88 /// 刷新 CPU 缓存到内存(clean 操作)。
89 ///
90 /// 将指定地址范围的 CPU 缓存数据写回到内存,确保设备可以读取到最新数据。
91 /// 用于 `ToDevice` 和 `Bidirectional` 方向的 DMA 传输前。
92 ///
93 /// # 参数
94 ///
95 /// - `addr`: 内存起始地址
96 /// - `size`: 内存大小(字节)
97 pub fn flush(&self, addr: NonNull<u8>, size: usize) {
98 self.os.flush(addr, size)
99 }
100
101 /// 使 CPU 缓存失效(invalidate 操作)。
102 ///
103 /// 使指定地址范围的 CPU 缓存失效,强制 CPU 从内存重新读取数据。
104 /// 用于 `FromDevice` 和 `Bidirectional` 方向的 DMA 传输后。
105 ///
106 /// # 参数
107 ///
108 /// - `addr`: 内存起始地址
109 /// - `size`: 内存大小(字节)
110 pub fn invalidate(&self, addr: NonNull<u8>, size: usize) {
111 self.os.invalidate(addr, size)
112 }
113
114 /// 刷新并使 CPU 缓存失效(clean and invalidate 操作)。
115 ///
116 /// 同时执行刷新和失效操作,用于确保缓存和内存完全同步。
117 ///
118 /// # 参数
119 ///
120 /// - `addr`: 内存起始地址
121 /// - `size`: 内存大小(字节)
122 pub fn flush_invalidate(&self, addr: NonNull<u8>, size: usize) {
123 self.os.flush_invalidate(addr, size)
124 }
125
126 /// 获取系统页大小。
127 ///
128 /// # 返回
129 ///
130 /// 返回系统的页大小(字节),通常为 4096。
131 pub fn page_size(&self) -> usize {
132 self.os.page_size()
133 }
134
135 fn prepare_read(
136 &self,
137 handle: &DmaMapHandle,
138 offset: usize,
139 size: usize,
140 direction: DmaDirection,
141 ) {
142 self.os.prepare_read(handle, offset, size, direction)
143 }
144
145 fn confirm_write(
146 &self,
147 handle: &DmaMapHandle,
148 offset: usize,
149 size: usize,
150 direction: DmaDirection,
151 ) {
152 self.os.confirm_write(handle, offset, size, direction)
153 }
154
155 unsafe fn alloc_coherent(&self, layout: core::alloc::Layout) -> Result<DmaHandle, DmaError> {
156 let res = unsafe { self.os.alloc_coherent(self.mask, layout) }.ok_or(DmaError::NoMemory)?;
157 match self.check_handle(&res) {
158 Ok(()) => Ok(res),
159 Err(e) => {
160 unsafe { self.dealloc_coherent(res) };
161 Err(e)
162 }
163 }
164 }
165
166 unsafe fn dealloc_coherent(&self, handle: DmaHandle) {
167 unsafe { self.os.dealloc_coherent(handle) }
168 }
169
170 fn check_handle(&self, handle: &DmaHandle) -> Result<(), DmaError> {
171 let addr: u64 = handle.dma_addr.into();
172
173 let in_mask = if handle.size() == 0 {
174 addr <= self.dma_mask()
175 } else {
176 addr.checked_add(handle.size().saturating_sub(1) as u64)
177 .map(|end| end <= self.dma_mask())
178 .unwrap_or(false)
179 };
180
181 if !in_mask {
182 return Err(DmaError::DmaMaskNotMatch {
183 addr: handle.dma_addr,
184 mask: self.dma_mask(),
185 });
186 }
187
188 let is_aligned = handle
189 .dma_addr
190 .as_u64()
191 .is_multiple_of(handle.align() as u64);
192 if !is_aligned {
193 return Err(DmaError::AlignMismatch {
194 address: handle.dma_addr,
195 required: handle.align(),
196 });
197 }
198
199 Ok(())
200 }
201
202 unsafe fn _map_single(
203 &self,
204 addr: NonNull<u8>,
205 size: NonZeroUsize,
206 align: usize,
207 direction: DmaDirection,
208 ) -> Result<DmaMapHandle, DmaError> {
209 let res = unsafe { self.os.map_single(self.mask, addr, size, align, direction) }?;
210 match self.check_handle(&res) {
211 Ok(()) => Ok(res),
212 Err(e) => {
213 unsafe { self.unmap_single(res) };
214 Err(e)
215 }
216 }
217 }
218
219 unsafe fn unmap_single(&self, handle: DmaMapHandle) {
220 unsafe { self.os.unmap_single(handle) }
221 }
222
223 /// 创建默认对齐的 DMA 数组。
224 ///
225 /// 分配一个指定大小的 DMA 可访问数组,内存初始化为零。
226 /// 数组的对齐方式使用类型 `T` 的默认对齐值。
227 ///
228 /// # 类型参数
229 ///
230 /// - `T`: 数组元素类型,必须是 `Sized` 并且实现了 `Default`
231 ///
232 /// # 参数
233 ///
234 /// - `size`: 数组长度(元素个数)
235 /// - `direction`: DMA 传输方向,决定缓存同步策略
236 ///
237 /// # 返回
238 ///
239 /// 成功时返回 `DArray<T>` 容器,失败时返回 `DmaError`
240 ///
241 /// # 示例
242 ///
243 /// ```rust,ignore
244 /// let dma_array = device.array_zero::<u32>(100, DmaDirection::FromDevice)?;
245 /// ```
246 pub fn array_zero<T>(
247 &self,
248 size: usize,
249 direction: DmaDirection,
250 ) -> Result<array::DArray<T>, DmaError> {
251 array::DArray::new_zero(self, size, direction)
252 }
253
254 /// 创建指定对齐的 DMA 数组。
255 ///
256 /// 分配一个指定大小和对齐要求的 DMA 可访问数组,内存初始化为零。
257 ///
258 /// # 类型参数
259 ///
260 /// - `T`: 数组元素类型,必须是 `Sized` 并且实现了 `Default`
261 ///
262 /// # 参数
263 ///
264 /// - `size`: 数组长度(元素个数)
265 /// - `align`: 对齐字节数(至少等于 `core::mem::align_of::<T>()`)
266 /// - `direction`: DMA 传输方向,决定缓存同步策略
267 ///
268 /// # 返回
269 ///
270 /// 成功时返回 `DArray<T>` 容器,失败时返回 `DmaError`
271 ///
272 /// # 示例
273 ///
274 /// ```rust,ignore
275 /// // 创建 64 字节对齐的数组
276 /// let dma_array = device
277 /// .array_zero_with_align::<u32>(100, 64, DmaDirection::FromDevice)?;
278 /// ```
279 pub fn array_zero_with_align<T>(
280 &self,
281 size: usize,
282 align: usize,
283 direction: DmaDirection,
284 ) -> Result<array::DArray<T>, DmaError> {
285 array::DArray::new_zero_with_align(self, size, align, direction)
286 }
287
288 /// 创建默认对齐的 DMA Box。
289 ///
290 /// 分配一个 DMA 可访问的单值容器,内存初始化为零。
291 /// 适合存储 DMA 描述符、配置结构等单个对象。
292 ///
293 /// # 类型参数
294 ///
295 /// - `T`: 存储的值类型,必须是 `Sized` 并且实现了 `Default`
296 ///
297 /// # 参数
298 ///
299 /// - `direction`: DMA 传输方向,决定缓存同步策略
300 ///
301 /// # 返回
302 ///
303 /// 成功时返回 `DBox<T>` 容器,失败时返回 `DmaError`
304 ///
305 /// # 示例
306 ///
307 /// ```rust,ignore
308 /// #[derive(Default)]
309 /// struct Descriptor {
310 /// addr: u64,
311 /// length: u32,
312 /// }
313 ///
314 /// let dma_desc = device.box_zero::<Descriptor>(DmaDirection::ToDevice)?;
315 /// ```
316 pub fn box_zero<T>(&self, direction: DmaDirection) -> Result<dbox::DBox<T>, DmaError> {
317 dbox::DBox::new_zero(self, direction)
318 }
319
320 /// 创建指定对齐的 DMA Box。
321 ///
322 /// 分配一个指定对齐要求的 DMA 可访问单值容器,内存初始化为零。
323 ///
324 /// # 类型参数
325 ///
326 /// - `T`: 存储的值类型,必须是 `Sized` 并且实现了 `Default`
327 ///
328 /// # 参数
329 ///
330 /// - `align`: 对齐字节数(至少等于 `core::mem::align_of::<T>()`)
331 /// - `direction`: DMA 传输方向,决定缓存同步策略
332 ///
333 /// # 返回
334 ///
335 /// 成功时返回 `DBox<T>` 容器,失败时返回 `DmaError`
336 ///
337 /// # 示例
338 ///
339 /// ```rust,ignore
340 /// let dma_desc = device
341 /// .box_zero_with_align::<Descriptor>(64, DmaDirection::ToDevice)?;
342 /// ```
343 pub fn box_zero_with_align<T>(
344 &self,
345 align: usize,
346 direction: DmaDirection,
347 ) -> Result<dbox::DBox<T>, DmaError> {
348 dbox::DBox::new_zero_with_align(self, align, direction)
349 }
350
351 /// 映射现有缓冲区为 DMA 可访问。
352 ///
353 /// 将已存在的缓冲区(如栈数组或堆分配的 slice)映射为 DMA 可访问区域。
354 /// 返回的 `SArrayPtr` 在离开作用域时自动解除映射。
355 ///
356 /// # 缓存同步
357 ///
358 /// **重要**: 此方法创建的映射**不会**自动同步缓存。
359 /// 你必须手动调用 `SArrayPtr` 的方法进行缓存同步:
360 /// - `to_vec()`: 读取前自动失效整个范围
361 /// - `copy_from_slice()`: 写入后自动刷新整个范围
362 ///
363 /// # 类型参数
364 ///
365 /// - `T`: 数组元素类型
366 ///
367 /// # 参数
368 ///
369 /// - `buff`: 要映射的缓冲区切片
370 /// - `align`: 对齐字节数
371 /// - `direction`: DMA 传输方向,决定手动缓存同步的行为
372 ///
373 /// # 返回
374 ///
375 /// 成功时返回 `SArrayPtr<T>` 映射句柄,失败时返回 `DmaError`
376 ///
377 /// # 示例
378 ///
379 /// ```rust,ignore
380 /// let mut buffer = [0u8; 4096];
381 ///
382 /// // 映射用于 DMA 写入
383 /// let mapping = device.map_single_array(&buffer, 64, DmaDirection::ToDevice)?;
384 ///
385 /// // 必须手动刷新缓存
386 /// mapping.copy_from_slice(&data);
387 ///
388 /// // ... 启动 DMA 传输 ...
389 ///
390 /// // 映射在作用域结束时自动解映射
391 /// ```
392 pub fn map_single_array<T>(
393 &self,
394 buff: &[T],
395 align: usize,
396 direction: DmaDirection,
397 ) -> Result<SArrayPtr<T>, DmaError> {
398 SArrayPtr::map_single(self, buff, align, direction)
399 }
400
401 pub fn new_pool(
402 &self,
403 layout: core::alloc::Layout,
404 direction: DmaDirection,
405 cap: usize,
406 ) -> DArrayPool {
407 let config = DArrayConfig {
408 size: layout.size(),
409 align: layout.align(),
410 direction,
411 };
412 DArrayPool::new_pool(self.clone(), config, cap)
413 }
414}