1use core::{alloc::Layout, cmp::PartialOrd, ops::Deref, ptr::NonNull};
2
3use derive_more::{
4 Add, AddAssign, Debug, Display, Div, From, Into, Mul, MulAssign, Sub, SubAssign,
5};
6
7#[derive(
8 Debug,
9 Display,
10 Clone,
11 Copy,
12 PartialEq,
13 Eq,
14 PartialOrd,
15 Hash,
16 From,
17 Into,
18 Add,
19 AddAssign,
20 Mul,
21 MulAssign,
22 Sub,
23 SubAssign,
24 Div,
25)]
26#[debug("{}", format_args!("{_0:#X}"))]
27#[display("{}", format_args!("{_0:#X}"))]
28pub struct DmaAddr(u64);
29
30impl DmaAddr {
31 pub fn as_u64(&self) -> u64 {
32 self.0
33 }
34
35 pub fn checked_add(&self, rhs: u64) -> Option<Self> {
36 self.0.checked_add(rhs).map(DmaAddr)
37 }
38}
39
40impl PartialEq<u64> for DmaAddr {
41 fn eq(&self, other: &u64) -> bool {
42 self.0 == *other
43 }
44}
45
46impl PartialOrd<u64> for DmaAddr {
47 fn partial_cmp(&self, other: &u64) -> Option<core::cmp::Ordering> {
48 self.0.partial_cmp(other)
49 }
50}
51
52#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, From, Into, Add, Mul, Sub)]
54#[debug("{}", format_args!("{_0:#X}"))]
55#[display("{}", format_args!("{_0:#X}"))]
56pub struct PhysAddr(u64);
57
58impl PhysAddr {
59 pub fn as_u64(&self) -> u64 {
60 self.0
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub enum DmaDirection {
67 ToDevice,
69 FromDevice,
71 Bidirectional,
73}
74
75#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
77pub enum DmaError {
78 #[error("DMA allocation failed")]
79 NoMemory,
80 #[error("Invalid layout")]
81 LayoutError(#[from] core::alloc::LayoutError),
82 #[error("DMA address {addr} does not match device mask {mask:#X}")]
83 DmaMaskNotMatch { addr: DmaAddr, mask: u64 },
84 #[error("DMA align mismatch: required={required:#X}, but address={address}")]
85 AlignMismatch { required: usize, address: DmaAddr },
86 #[error("Null pointer provided for DMA mapping")]
87 NullPointer,
88 #[error("Zero-sized buffer cannot be used for DMA")]
89 ZeroSizedBuffer,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
98pub struct DmaHandle {
99 pub(crate) cpu_addr: NonNull<u8>,
101 pub(crate) dma_addr: DmaAddr,
103 pub(crate) layout: Layout,
105 }
109
110impl DmaHandle {
111 pub unsafe fn new(cpu_addr: NonNull<u8>, dma_addr: DmaAddr, layout: Layout) -> Self {
130 Self {
131 cpu_addr,
132 dma_addr,
133 layout,
134 }
135 }
136
137 pub fn size(&self) -> usize {
139 self.layout.size()
140 }
141
142 pub fn align(&self) -> usize {
144 self.layout.align()
145 }
146
147 pub fn as_ptr(&self) -> NonNull<u8> {
149 self.cpu_addr
150 }
151
152 pub fn dma_addr(&self) -> DmaAddr {
154 self.dma_addr
155 }
156
157 pub fn layout(&self) -> Layout {
159 self.layout
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub struct DmaMapHandle {
165 pub(crate) handle: DmaHandle,
166 pub(crate) map_alloc_virt: Option<NonNull<u8>>,
167}
168
169impl Deref for DmaMapHandle {
170 type Target = DmaHandle;
171 fn deref(&self) -> &Self::Target {
172 &self.handle
173 }
174}
175
176impl DmaMapHandle {
177 pub unsafe fn new(
199 cpu_addr: NonNull<u8>,
200 dma_addr: DmaAddr,
201 layout: Layout,
202 alloc_virt: Option<NonNull<u8>>,
203 ) -> Self {
204 let handle = DmaHandle {
205 cpu_addr,
206 dma_addr,
207 layout,
208 };
209 Self {
210 handle,
211 map_alloc_virt: alloc_virt,
212 }
213 }
214
215 pub fn alloc_virt(&self) -> Option<NonNull<u8>> {
216 self.map_alloc_virt
217 }
218}