use core::{alloc::Layout, cmp::PartialOrd, ops::Deref, ptr::NonNull};
use derive_more::{
Add, AddAssign, Debug, Display, Div, From, Into, Mul, MulAssign, Sub, SubAssign,
};
#[derive(
Debug,
Display,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Hash,
From,
Into,
Add,
AddAssign,
Mul,
MulAssign,
Sub,
SubAssign,
Div,
)]
#[debug("{}", format_args!("{_0:#X}"))]
#[display("{}", format_args!("{_0:#X}"))]
pub struct DmaAddr(u64);
impl DmaAddr {
pub fn as_u64(&self) -> u64 {
self.0
}
pub fn checked_add(&self, rhs: u64) -> Option<Self> {
self.0.checked_add(rhs).map(DmaAddr)
}
}
impl PartialEq<u64> for DmaAddr {
fn eq(&self, other: &u64) -> bool {
self.0 == *other
}
}
impl PartialOrd<u64> for DmaAddr {
fn partial_cmp(&self, other: &u64) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, From, Into, Add, Mul, Sub)]
#[debug("{}", format_args!("{_0:#X}"))]
#[display("{}", format_args!("{_0:#X}"))]
pub struct PhysAddr(u64);
impl PhysAddr {
pub fn as_u64(&self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DmaDirection {
ToDevice,
FromDevice,
Bidirectional,
}
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
pub enum DmaError {
#[error("DMA allocation failed")]
NoMemory,
#[error("Invalid layout")]
LayoutError(#[from] core::alloc::LayoutError),
#[error("DMA address {addr} does not match device mask {mask:#X}")]
DmaMaskNotMatch { addr: DmaAddr, mask: u64 },
#[error("DMA align mismatch: required={required:#X}, but address={address}")]
AlignMismatch { required: usize, address: DmaAddr },
#[error("Null pointer provided for DMA mapping")]
NullPointer,
#[error("Zero-sized buffer cannot be used for DMA")]
ZeroSizedBuffer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DmaHandle {
pub(crate) cpu_addr: NonNull<u8>,
pub(crate) dma_addr: DmaAddr,
pub(crate) layout: Layout,
}
impl DmaHandle {
pub unsafe fn new(cpu_addr: NonNull<u8>, dma_addr: DmaAddr, layout: Layout) -> Self {
Self {
cpu_addr,
dma_addr,
layout,
}
}
pub fn size(&self) -> usize {
self.layout.size()
}
pub fn align(&self) -> usize {
self.layout.align()
}
pub fn as_ptr(&self) -> NonNull<u8> {
self.cpu_addr
}
pub fn dma_addr(&self) -> DmaAddr {
self.dma_addr
}
pub fn layout(&self) -> Layout {
self.layout
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DmaMapHandle {
pub(crate) handle: DmaHandle,
pub(crate) map_alloc_virt: Option<NonNull<u8>>,
}
impl Deref for DmaMapHandle {
type Target = DmaHandle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl DmaMapHandle {
pub unsafe fn new(
cpu_addr: NonNull<u8>,
dma_addr: DmaAddr,
layout: Layout,
alloc_virt: Option<NonNull<u8>>,
) -> Self {
let handle = DmaHandle {
cpu_addr,
dma_addr,
layout,
};
Self {
handle,
map_alloc_virt: alloc_virt,
}
}
pub fn alloc_virt(&self) -> Option<NonNull<u8>> {
self.map_alloc_virt
}
}