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 {}