1#![no_std]
2
3extern crate alloc;
4
5use alloc::{boxed::Box, collections::BTreeMap, sync::Arc};
6use core::{alloc::Layout, cell::UnsafeCell};
7
8use dma_api::{DArrayPool, DBuff, DeviceDma, DmaDirection, DmaOp};
9use futures::task::AtomicWaker;
10pub use rdif_eth::*;
11
12fn other_error(msg: &'static str) -> NetError {
13 NetError::Other(Box::new(KError::Unknown(msg)))
14}
15
16struct QueueWakerMap(UnsafeCell<BTreeMap<usize, Arc<AtomicWaker>>>);
17
18impl QueueWakerMap {
19 fn new() -> Self {
20 Self(UnsafeCell::new(BTreeMap::new()))
21 }
22
23 fn register(&self, queue_id: usize) -> Arc<AtomicWaker> {
24 let waker = Arc::new(AtomicWaker::new());
25 unsafe { &mut *self.0.get() }.insert(queue_id, waker.clone());
26 waker
27 }
28
29 fn wake(&self, queue_id: usize) {
30 if let Some(waker) = unsafe { &*self.0.get() }.get(&queue_id) {
31 waker.wake();
32 }
33 }
34}
35
36struct NetInner {
37 interface: UnsafeCell<Box<dyn Interface>>,
38 dma_op: &'static dyn DmaOp,
39 tx_wakers: QueueWakerMap,
40 rx_wakers: QueueWakerMap,
41}
42
43unsafe impl Send for NetInner {}
44unsafe impl Sync for NetInner {}
45
46struct IrqGuard<'a> {
47 enabled: bool,
48 inner: &'a Net,
49}
50
51impl Drop for IrqGuard<'_> {
52 fn drop(&mut self) {
53 if self.enabled {
54 self.inner.interface().enable_irq();
55 }
56 }
57}
58
59pub struct Net {
60 inner: Arc<NetInner>,
61}
62
63impl Net {
64 pub fn new(interface: impl Interface, dma_op: &'static dyn DmaOp) -> Self {
65 Self {
66 inner: Arc::new(NetInner {
67 interface: UnsafeCell::new(Box::new(interface)),
68 dma_op,
69 tx_wakers: QueueWakerMap::new(),
70 rx_wakers: QueueWakerMap::new(),
71 }),
72 }
73 }
74
75 #[allow(clippy::mut_from_ref)]
76 fn interface(&self) -> &mut dyn Interface {
77 unsafe { &mut **self.inner.interface.get() }
78 }
79
80 fn irq_guard(&self) -> IrqGuard<'_> {
81 let enabled = self.interface().is_irq_enabled();
82 if enabled {
83 self.interface().disable_irq();
84 }
85 IrqGuard {
86 enabled,
87 inner: self,
88 }
89 }
90
91 pub fn mac_address(&self) -> [u8; 6] {
92 self.interface().mac_address()
93 }
94
95 pub fn create_tx_queue(&mut self) -> Result<TxQueue, NetError> {
96 let irq_guard = self.irq_guard();
97 let queue = self
98 .interface()
99 .create_tx_queue()
100 .ok_or_else(|| other_error("failed to create tx queue"))?;
101 let config = queue.config();
102 let pool = make_pool(self.inner.dma_op, config, DmaDirection::ToDevice)?;
103 let waker = self.inner.tx_wakers.register(queue.id());
104 drop(irq_guard);
105
106 Ok(TxQueue {
107 interface: queue,
108 pool,
109 inflight: BTreeMap::new(),
110 config,
111 _waker: waker,
112 })
113 }
114
115 pub fn create_rx_queue(&mut self) -> Result<RxQueue, NetError> {
116 let irq_guard = self.irq_guard();
117 let queue = self
118 .interface()
119 .create_rx_queue()
120 .ok_or_else(|| other_error("failed to create rx queue"))?;
121 let config = queue.config();
122 let pool = make_pool(self.inner.dma_op, config, DmaDirection::FromDevice)?;
123 let waker = self.inner.rx_wakers.register(queue.id());
124 drop(irq_guard);
125
126 let mut rx = RxQueue {
127 interface: queue,
128 pool,
129 inflight: BTreeMap::new(),
130 config,
131 _waker: waker,
132 };
133 rx.prefill()?;
134 Ok(rx)
135 }
136
137 pub fn irq_handler(&self) -> IrqHandler {
138 IrqHandler {
139 inner: self.inner.clone(),
140 }
141 }
142}
143
144fn make_pool(
145 dma_op: &'static dyn DmaOp,
146 config: QueueConfig,
147 direction: DmaDirection,
148) -> Result<DArrayPool, NetError> {
149 let layout = Layout::from_size_align(config.buf_size, config.align.max(1))
150 .map_err(|_| other_error("invalid queue layout"))?;
151 let dma = DeviceDma::new(config.dma_mask, dma_op);
152 Ok(dma.new_pool(layout, direction, config.ring_size))
153}
154
155pub struct IrqHandler {
156 inner: Arc<NetInner>,
157}
158
159unsafe impl Sync for IrqHandler {}
160
161impl IrqHandler {
162 pub fn handle(&self) {
163 let iface = unsafe { &mut **self.inner.interface.get() };
164 let event = iface.handle_irq();
165 for id in event.tx_queue.iter() {
166 self.inner.tx_wakers.wake(id);
167 }
168 for id in event.rx_queue.iter() {
169 self.inner.rx_wakers.wake(id);
170 }
171 }
172}
173
174pub struct TxQueue {
175 interface: Box<dyn ITxQueue>,
176 pool: DArrayPool,
177 inflight: BTreeMap<u64, DBuff>,
178 config: QueueConfig,
179 _waker: Arc<AtomicWaker>,
180}
181
182impl TxQueue {
183 fn capacity(&self) -> usize {
184 self.config.ring_size.saturating_sub(1)
185 }
186
187 fn reclaim_bounded(&mut self, limit: usize) -> Result<usize, NetError> {
188 let mut reclaimed = 0;
189 while reclaimed < limit {
190 let Some(bus_addr) = self.interface.reclaim() else {
191 break;
192 };
193 let Some(buff) = self.inflight.remove(&bus_addr) else {
194 return Err(other_error("reclaimed unknown tx buffer"));
195 };
196 drop(buff);
197 reclaimed += 1;
198 }
199 Ok(reclaimed)
200 }
201
202 pub fn id(&self) -> usize {
203 self.interface.id()
204 }
205
206 pub fn buf_size(&self) -> usize {
207 self.config.buf_size
208 }
209
210 pub fn prepare_send<R>(
211 &mut self,
212 len: usize,
213 f: impl FnOnce(&mut [u8]) -> R,
214 ) -> Result<(R, TxPending<'_>), NetError> {
215 if len > self.config.buf_size {
216 return Err(other_error("tx packet too large"));
217 }
218
219 self.reclaim_bounded(self.capacity().max(1))?;
220
221 let mut buff = self.pool.alloc()?;
222 let bus_addr = buff.dma_addr().as_u64();
223 let ret = buff.write_with(len, f);
224 Ok((
225 ret,
226 TxPending {
227 queue: self,
228 len,
229 bus_addr,
230 buff: Some(buff),
231 },
232 ))
233 }
234}
235
236pub struct TxPending<'a> {
237 queue: &'a mut TxQueue,
238 len: usize,
239 bus_addr: u64,
240 buff: Option<DBuff>,
241}
242
243impl TxPending<'_> {
244 pub fn bus_addr(&self) -> u64 {
245 self.bus_addr
246 }
247
248 pub fn len(&self) -> usize {
249 self.len
250 }
251
252 pub fn is_empty(&self) -> bool {
253 self.len == 0
254 }
255
256 pub fn try_submit(&mut self) -> Result<(), NetError> {
257 self.queue.reclaim_bounded(self.queue.capacity().max(1))?;
258 self.queue.interface.submit(self.bus_addr, self.len)?;
259 let buff = self
260 .buff
261 .take()
262 .expect("tx pending buffer should exist until submit succeeds");
263 self.queue.inflight.insert(self.bus_addr, buff);
264 Ok(())
265 }
266}
267
268pub struct RxQueue {
269 interface: Box<dyn IRxQueue>,
270 pool: DArrayPool,
271 inflight: BTreeMap<u64, DBuff>,
272 config: QueueConfig,
273 _waker: Arc<AtomicWaker>,
274}
275
276impl RxQueue {
277 fn capacity(&self) -> usize {
278 self.config.ring_size.saturating_sub(1)
279 }
280
281 fn prefill(&mut self) -> Result<(), NetError> {
282 while self.inflight.len() < self.capacity() {
283 let buff = self.pool.alloc()?;
284 if let Err(err) = self.submit_buffer(buff) {
285 if matches!(err, NetError::Retry) {
286 break;
287 }
288 return Err(err);
289 }
290 }
291 Ok(())
292 }
293
294 fn submit_buffer(&mut self, buff: DBuff) -> Result<(), NetError> {
295 let bus_addr = buff.dma_addr().as_u64();
296 let len = self.config.buf_size.min(buff.len());
297 self.interface.submit(bus_addr, len)?;
298 self.inflight.insert(bus_addr, buff);
299 Ok(())
300 }
301
302 fn reclaim_packet(&mut self) -> Result<Option<(DBuff, usize)>, NetError> {
303 let Some((bus_addr, len)) = self.interface.reclaim() else {
304 return Ok(None);
305 };
306 let Some(buff) = self.inflight.remove(&bus_addr) else {
307 return Err(other_error("reclaimed unknown rx buffer"));
308 };
309 let packet_len = len.min(self.config.buf_size).min(buff.len());
310 Ok(Some((buff, packet_len)))
311 }
312
313 pub fn id(&self) -> usize {
314 self.interface.id()
315 }
316
317 pub fn buf_size(&self) -> usize {
318 self.config.buf_size
319 }
320
321 pub fn try_receive(&mut self) -> Option<RxPacket<'_>> {
322 match self.reclaim_packet() {
323 Ok(Some((buff, len))) => Some(RxPacket {
324 queue: self,
325 len,
326 buff: Some(buff),
327 }),
328 Ok(None) | Err(_) => None,
329 }
330 }
331
332 pub fn receive<R>(&mut self, f: impl FnOnce(&[u8]) -> R) -> Option<R> {
333 let packet = self.try_receive()?;
334 Some(packet.consume(f))
335 }
336}
337
338pub struct RxPacket<'a> {
339 queue: &'a mut RxQueue,
340 len: usize,
341 buff: Option<DBuff>,
342}
343
344impl RxPacket<'_> {
345 pub fn len(&self) -> usize {
346 self.len
347 }
348
349 pub fn is_empty(&self) -> bool {
350 self.len == 0
351 }
352
353 pub fn consume<R>(mut self, f: impl FnOnce(&[u8]) -> R) -> R {
354 let buff = self.buff.as_ref().expect("rx packet buffer should exist");
355 let ret = buff.read_with(self.len, f);
356 if let Some(buff) = self.buff.take() {
357 let _ = self.queue.submit_buffer(buff);
358 }
359 ret
360 }
361}
362
363impl Drop for RxPacket<'_> {
364 fn drop(&mut self) {
365 if let Some(buff) = self.buff.take() {
366 let _ = self.queue.submit_buffer(buff);
367 }
368 }
369}