morpheus_network/dma/buffer.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! DMA buffer with ownership tracking.
//!
//! # Reference
//! NETWORK_IMPL_GUIDE.md ยง3.5
use super::ownership::BufferOwnership;
/// A single DMA buffer with ownership tracking.
///
/// Tracks both CPU and bus addresses, plus ownership state.
pub struct DmaBuffer {
/// CPU-accessible pointer to buffer data.
cpu_ptr: *mut u8,
/// Device-visible bus address.
bus_addr: u64,
/// Buffer capacity in bytes.
capacity: usize,
/// Current ownership state.
ownership: BufferOwnership,
/// Buffer index within the pool.
index: u16,
}
impl DmaBuffer {
/// Create a new DMA buffer.
///
/// # Safety
/// - `cpu_ptr` must point to valid DMA-capable memory
/// - `bus_addr` must be the corresponding device-visible address
pub unsafe fn new(cpu_ptr: *mut u8, bus_addr: u64, capacity: usize, index: u16) -> Self {
Self {
cpu_ptr,
bus_addr,
capacity,
ownership: BufferOwnership::Free,
index,
}
}
/// Get buffer data as slice.
///
/// # Panics
/// Panics if buffer is not DriverOwned.
pub fn as_slice(&self) -> &[u8] {
assert!(
self.ownership == BufferOwnership::DriverOwned,
"BUG: Cannot access buffer not owned by driver (state: {:?})",
self.ownership
);
unsafe { core::slice::from_raw_parts(self.cpu_ptr, self.capacity) }
}
/// Get buffer data as mutable slice.
///
/// # Panics
/// Panics if buffer is not DriverOwned.
pub fn as_mut_slice(&mut self) -> &mut [u8] {
assert!(
self.ownership == BufferOwnership::DriverOwned,
"BUG: Cannot access buffer not owned by driver (state: {:?})",
self.ownership
);
unsafe { core::slice::from_raw_parts_mut(self.cpu_ptr, self.capacity) }
}
/// Get the first `len` bytes as mutable slice.
///
/// # Panics
/// Panics if buffer is not DriverOwned or len > capacity.
pub fn as_mut_slice_len(&mut self, len: usize) -> &mut [u8] {
assert!(
len <= self.capacity,
"Requested length exceeds buffer capacity"
);
&mut self.as_mut_slice()[..len]
}
/// Get the device-visible bus address.
pub fn bus_addr(&self) -> u64 {
self.bus_addr
}
/// Get the CPU pointer.
pub fn cpu_ptr(&self) -> *mut u8 {
self.cpu_ptr
}
/// Get buffer index.
pub fn index(&self) -> u16 {
self.index
}
/// Get buffer capacity.
pub fn capacity(&self) -> usize {
self.capacity
}
/// Get current ownership state.
pub fn ownership(&self) -> BufferOwnership {
self.ownership
}
/// Check if buffer can be allocated.
pub fn is_free(&self) -> bool {
self.ownership.is_free()
}
/// Check if buffer is owned by driver.
pub fn is_driver_owned(&self) -> bool {
self.ownership.can_access()
}
/// Check if buffer is owned by device.
pub fn is_device_owned(&self) -> bool {
self.ownership.is_device_owned()
}
/// Mark buffer as allocated (Free -> DriverOwned).
///
/// # Safety
/// Only call during allocation from pool.
pub(crate) unsafe fn mark_allocated(&mut self) {
debug_assert!(self.ownership.is_free(), "Buffer must be free to allocate");
self.ownership = BufferOwnership::DriverOwned;
}
/// Mark buffer as device-owned (DriverOwned -> DeviceOwned).
///
/// # Safety
/// Only call immediately before submitting to device.
pub unsafe fn mark_device_owned(&mut self) {
debug_assert!(
self.ownership == BufferOwnership::DriverOwned,
"Buffer must be driver-owned before device transfer"
);
self.ownership = BufferOwnership::DeviceOwned;
}
/// Mark buffer as driver-owned (DeviceOwned -> DriverOwned).
///
/// # Safety
/// Only call after device confirms ownership transfer (poll completion).
pub unsafe fn mark_driver_owned(&mut self) {
debug_assert!(
self.ownership == BufferOwnership::DeviceOwned,
"Buffer must be device-owned before reclaim"
);
self.ownership = BufferOwnership::DriverOwned;
}
/// Mark buffer as free (DriverOwned -> Free).
///
/// # Safety
/// Only call during return to pool.
pub(crate) unsafe fn mark_free(&mut self) {
debug_assert!(
self.ownership == BufferOwnership::DriverOwned,
"Buffer must be driver-owned before freeing"
);
self.ownership = BufferOwnership::Free;
}
}
unsafe impl Send for DmaBuffer {}
unsafe impl Sync for DmaBuffer {}