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::{ContiguousBuffer, ContiguousBufferPool, 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 DriverGeneric for Net {
64 fn name(&self) -> &str {
65 self.interface().name()
66 }
67
68 fn raw_any(&self) -> Option<&dyn core::any::Any> {
69 Some(self)
70 }
71
72 fn raw_any_mut(&mut self) -> Option<&mut dyn core::any::Any> {
73 Some(self)
74 }
75}
76
77impl Net {
78 pub fn new(interface: impl Interface, dma_op: &'static dyn DmaOp) -> Self {
79 Self {
80 inner: Arc::new(NetInner {
81 interface: UnsafeCell::new(Box::new(interface)),
82 dma_op,
83 tx_wakers: QueueWakerMap::new(),
84 rx_wakers: QueueWakerMap::new(),
85 }),
86 }
87 }
88
89 #[allow(clippy::mut_from_ref)]
90 fn interface(&self) -> &mut dyn Interface {
91 unsafe { &mut **self.inner.interface.get() }
92 }
93
94 fn irq_guard(&self) -> IrqGuard<'_> {
95 let enabled = self.interface().is_irq_enabled();
96 if enabled {
97 self.interface().disable_irq();
98 }
99 IrqGuard {
100 enabled,
101 inner: self,
102 }
103 }
104
105 pub fn mac_address(&self) -> [u8; 6] {
106 self.interface().mac_address()
107 }
108
109 #[allow(clippy::mut_from_ref)]
116 pub fn wifi_control(&self) -> Option<&mut dyn WifiControl> {
117 self.interface().wifi_control()
118 }
119
120 pub fn enable_irq(&mut self) {
121 self.interface().enable_irq();
122 }
123
124 pub fn disable_irq(&mut self) {
125 self.interface().disable_irq();
126 }
127
128 pub fn is_irq_enabled(&self) -> bool {
129 self.interface().is_irq_enabled()
130 }
131
132 pub fn create_tx_queue(&mut self) -> Result<TxQueue, NetError> {
133 let irq_guard = self.irq_guard();
134 let queue = self
135 .interface()
136 .create_tx_queue()
137 .ok_or_else(|| other_error("failed to create tx queue"))?;
138 let config = queue.config();
139 let pool = make_pool(self.inner.dma_op, config, DmaDirection::ToDevice)?;
140 let waker = self.inner.tx_wakers.register(queue.id());
141 drop(irq_guard);
142
143 Ok(TxQueue {
144 interface: queue,
145 pool,
146 inflight: BTreeMap::new(),
147 config,
148 _waker: waker,
149 })
150 }
151
152 pub fn create_rx_queue(&mut self) -> Result<RxQueue, NetError> {
153 let irq_guard = self.irq_guard();
154 let queue = self
155 .interface()
156 .create_rx_queue()
157 .ok_or_else(|| other_error("failed to create rx queue"))?;
158 let config = queue.config();
159 let pool = make_pool(self.inner.dma_op, config, DmaDirection::FromDevice)?;
160 let waker = self.inner.rx_wakers.register(queue.id());
161 drop(irq_guard);
162
163 let mut rx = RxQueue {
164 interface: queue,
165 pool,
166 inflight: BTreeMap::new(),
167 config,
168 _waker: waker,
169 };
170 rx.prefill()?;
171 Ok(rx)
172 }
173
174 pub fn irq_handler(&self) -> IrqHandler {
175 IrqHandler {
176 inner: self.inner.clone(),
177 }
178 }
179
180 pub fn wifi_control_handle(&self) -> Option<WifiControlHandle> {
188 self.wifi_control().is_some().then(|| WifiControlHandle {
189 inner: self.inner.clone(),
190 })
191 }
192}
193
194pub struct WifiControlHandle {
200 inner: Arc<NetInner>,
201}
202
203impl Clone for WifiControlHandle {
204 fn clone(&self) -> Self {
205 Self {
206 inner: self.inner.clone(),
207 }
208 }
209}
210
211unsafe impl Send for WifiControlHandle {}
212unsafe impl Sync for WifiControlHandle {}
213
214impl WifiControlHandle {
215 #[allow(clippy::mut_from_ref)]
225 pub fn wifi_control(&self) -> Option<&mut dyn WifiControl> {
226 let iface = unsafe { &mut **self.inner.interface.get() };
227 iface.wifi_control()
228 }
229
230 pub fn mac_address(&self) -> [u8; 6] {
233 let iface = unsafe { &mut **self.inner.interface.get() };
234 iface.mac_address()
235 }
236}
237
238fn make_pool(
239 dma_op: &'static dyn DmaOp,
240 config: QueueConfig,
241 direction: DmaDirection,
242) -> Result<ContiguousBufferPool, NetError> {
243 let layout = Layout::from_size_align(config.buf_size, config.align.max(1))
244 .map_err(|_| other_error("invalid queue layout"))?;
245 let dma = DeviceDma::new(config.dma_mask, dma_op);
246 Ok(dma.contiguous_buffer_pool(layout, direction, config.ring_size))
247}
248
249pub struct IrqHandler {
250 inner: Arc<NetInner>,
251}
252
253unsafe impl Sync for IrqHandler {}
254
255impl IrqHandler {
256 pub fn enable(&self) {
257 let iface = unsafe { &mut **self.inner.interface.get() };
258 iface.enable_irq();
259 }
260
261 pub fn disable(&self) {
262 let iface = unsafe { &mut **self.inner.interface.get() };
263 iface.disable_irq();
264 }
265
266 pub fn handle_irq(&self) -> rdif_eth::Event {
274 let iface = unsafe { &mut **self.inner.interface.get() };
275 iface.handle_irq()
276 }
277
278 pub fn handle(&self) {
283 let event = self.handle_irq();
284 for id in event.tx_queue.iter() {
285 self.inner.tx_wakers.wake(id);
286 }
287 for id in event.rx_queue.iter() {
288 self.inner.rx_wakers.wake(id);
289 }
290 }
291
292 pub fn enable_irq(&self) {
293 let iface = unsafe { &mut **self.inner.interface.get() };
294 iface.enable_irq();
295 }
296
297 pub fn disable_irq(&self) {
298 let iface = unsafe { &mut **self.inner.interface.get() };
299 iface.disable_irq();
300 }
301
302 pub fn is_irq_enabled(&self) -> bool {
303 let iface = unsafe { &mut **self.inner.interface.get() };
304 iface.is_irq_enabled()
305 }
306}
307
308pub struct TxQueue {
309 interface: Box<dyn ITxQueue>,
310 pool: ContiguousBufferPool,
311 inflight: BTreeMap<u64, ContiguousBuffer>,
312 config: QueueConfig,
313 _waker: Arc<AtomicWaker>,
314}
315
316impl TxQueue {
317 fn capacity(&self) -> usize {
318 self.config.ring_size.saturating_sub(1)
319 }
320
321 fn reclaim_bounded(&mut self, limit: usize) -> Result<usize, NetError> {
322 let mut reclaimed = 0;
323 while reclaimed < limit {
324 let Some(bus_addr) = self.interface.reclaim() else {
325 break;
326 };
327 let Some(buff) = self.inflight.remove(&bus_addr) else {
328 return Err(other_error("reclaimed unknown tx buffer"));
329 };
330 drop(buff);
331 reclaimed += 1;
332 }
333 Ok(reclaimed)
334 }
335
336 pub fn id(&self) -> usize {
337 self.interface.id()
338 }
339
340 pub fn buf_size(&self) -> usize {
341 self.config.buf_size
342 }
343
344 pub fn prepare_send<R>(
345 &mut self,
346 len: usize,
347 f: impl FnOnce(&mut [u8]) -> R,
348 ) -> Result<(R, TxPending<'_>), NetError> {
349 if len > self.config.buf_size {
350 return Err(other_error("tx packet too large"));
351 }
352
353 self.reclaim_bounded(self.capacity().max(1))?;
354
355 let mut buff = self.pool.alloc()?;
356 let bus_addr = buff.dma_addr().as_u64();
357 let ret = buff.write_with_cpu(len, f);
358 Ok((
359 ret,
360 TxPending {
361 queue: self,
362 len,
363 bus_addr,
364 buff: Some(buff),
365 },
366 ))
367 }
368}
369
370pub struct TxPending<'a> {
371 queue: &'a mut TxQueue,
372 len: usize,
373 bus_addr: u64,
374 buff: Option<ContiguousBuffer>,
375}
376
377impl TxPending<'_> {
378 pub fn bus_addr(&self) -> u64 {
379 self.bus_addr
380 }
381
382 pub fn len(&self) -> usize {
383 self.len
384 }
385
386 pub fn is_empty(&self) -> bool {
387 self.len == 0
388 }
389
390 pub fn try_submit(&mut self) -> Result<(), NetError> {
391 self.queue.reclaim_bounded(self.queue.capacity().max(1))?;
392 let buff = self
393 .buff
394 .as_ref()
395 .expect("tx pending buffer should exist until submit succeeds");
396 buff.prepare_for_device(0, self.len);
397 self.queue.interface.submit(DmaBuffer {
398 virt: buff.as_ptr(),
399 bus_addr: self.bus_addr,
400 len: self.len,
401 })?;
402 let buff = self
403 .buff
404 .take()
405 .expect("tx pending buffer should exist until submit succeeds");
406 self.queue.inflight.insert(self.bus_addr, buff);
407 Ok(())
408 }
409}
410
411pub struct RxQueue {
412 interface: Box<dyn IRxQueue>,
413 pool: ContiguousBufferPool,
414 inflight: BTreeMap<u64, ContiguousBuffer>,
415 config: QueueConfig,
416 _waker: Arc<AtomicWaker>,
417}
418
419impl RxQueue {
420 fn capacity(&self) -> usize {
421 self.config.ring_size.saturating_sub(1)
422 }
423
424 fn prefill(&mut self) -> Result<(), NetError> {
425 while self.inflight.len() < self.capacity() {
426 let buff = self.pool.alloc()?;
427 if let Err(err) = self.submit_buffer(buff) {
428 if matches!(err, NetError::Retry) {
429 break;
430 }
431 return Err(err);
432 }
433 }
434 Ok(())
435 }
436
437 fn submit_buffer(&mut self, buff: ContiguousBuffer) -> Result<(), NetError> {
438 let bus_addr = buff.dma_addr().as_u64();
439 let len = self.config.buf_size.min(buff.len());
440 buff.prepare_for_device(0, len);
441 self.interface.submit(DmaBuffer {
442 virt: buff.as_ptr(),
443 bus_addr,
444 len,
445 })?;
446 self.inflight.insert(bus_addr, buff);
447 Ok(())
448 }
449
450 fn reclaim_packet(&mut self) -> Result<Option<(ContiguousBuffer, usize)>, NetError> {
451 let Some((bus_addr, len)) = self.interface.reclaim() else {
452 return Ok(None);
453 };
454 let Some(buff) = self.inflight.remove(&bus_addr) else {
455 return Err(other_error("reclaimed unknown rx buffer"));
456 };
457 let packet_len = len.min(self.config.buf_size).min(buff.len());
458 buff.complete_for_cpu(0, packet_len);
459 Ok(Some((buff, packet_len)))
460 }
461
462 pub fn id(&self) -> usize {
463 self.interface.id()
464 }
465
466 pub fn buf_size(&self) -> usize {
467 self.config.buf_size
468 }
469
470 pub fn try_receive(&mut self) -> Option<RxPacket<'_>> {
471 match self.reclaim_packet() {
472 Ok(Some((buff, len))) => Some(RxPacket {
473 queue: self,
474 len,
475 buff: Some(buff),
476 }),
477 Ok(None) | Err(_) => None,
478 }
479 }
480
481 pub fn receive<R>(&mut self, f: impl FnOnce(&[u8]) -> R) -> Option<R> {
482 let packet = self.try_receive()?;
483 Some(packet.consume(f))
484 }
485}
486
487pub struct RxPacket<'a> {
488 queue: &'a mut RxQueue,
489 len: usize,
490 buff: Option<ContiguousBuffer>,
491}
492
493impl RxPacket<'_> {
494 pub fn len(&self) -> usize {
495 self.len
496 }
497
498 pub fn is_empty(&self) -> bool {
499 self.len == 0
500 }
501
502 pub fn consume<R>(mut self, f: impl FnOnce(&[u8]) -> R) -> R {
503 let buff = self.buff.as_ref().expect("rx packet buffer should exist");
504 let ret = buff.read_with_cpu(self.len, f);
505 if let Some(buff) = self.buff.take() {
506 let _ = self.queue.submit_buffer(buff);
507 }
508 ret
509 }
510}
511
512impl Drop for RxPacket<'_> {
513 fn drop(&mut self) {
514 if let Some(buff) = self.buff.take() {
515 let _ = self.queue.submit_buffer(buff);
516 }
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use alloc::{boxed::Box, sync::Arc};
523 use core::{
524 any::Any,
525 num::NonZeroUsize,
526 ptr::NonNull,
527 sync::atomic::{AtomicUsize, Ordering},
528 task::{RawWaker, RawWakerVTable, Waker},
529 };
530
531 use dma_api::{DmaAllocHandle, DmaConstraints, DmaDirection, DmaError, DmaMapHandle};
532 use rdif_eth::{DriverGeneric, Event, IRxQueue, ITxQueue, IdList, Interface};
533
534 use super::*;
535
536 struct TestDma;
537
538 impl dma_api::DmaOp for TestDma {
539 fn page_size(&self) -> usize {
540 4096
541 }
542
543 unsafe fn alloc_contiguous(
544 &self,
545 _constraints: DmaConstraints,
546 _layout: core::alloc::Layout,
547 ) -> Option<DmaAllocHandle> {
548 panic!("test should not allocate contiguous DMA")
549 }
550
551 unsafe fn dealloc_contiguous(&self, _handle: DmaAllocHandle) {
552 panic!("test should not deallocate contiguous DMA")
553 }
554
555 unsafe fn alloc_coherent(
556 &self,
557 _constraints: DmaConstraints,
558 _layout: core::alloc::Layout,
559 ) -> Option<DmaAllocHandle> {
560 panic!("test should not allocate coherent DMA")
561 }
562
563 unsafe fn dealloc_coherent(&self, _handle: DmaAllocHandle) {
564 panic!("test should not deallocate coherent DMA")
565 }
566
567 unsafe fn map_streaming(
568 &self,
569 _constraints: DmaConstraints,
570 _addr: NonNull<u8>,
571 _size: NonZeroUsize,
572 _direction: DmaDirection,
573 ) -> Result<DmaMapHandle, DmaError> {
574 panic!("test should not map streaming DMA")
575 }
576
577 unsafe fn unmap_streaming(&self, _handle: DmaMapHandle) {
578 panic!("test should not unmap streaming DMA")
579 }
580 }
581
582 struct TestInterface {
583 irq_events: Event,
584 handle_calls: Arc<AtomicUsize>,
585 }
586
587 impl DriverGeneric for TestInterface {
588 fn name(&self) -> &str {
589 "test-net"
590 }
591
592 fn raw_any(&self) -> Option<&dyn Any> {
593 Some(self)
594 }
595
596 fn raw_any_mut(&mut self) -> Option<&mut dyn Any> {
597 Some(self)
598 }
599 }
600
601 impl Interface for TestInterface {
602 fn mac_address(&self) -> [u8; 6] {
603 [0x02, 0, 0, 0, 0, 1]
604 }
605
606 fn create_tx_queue(&mut self) -> Option<Box<dyn ITxQueue>> {
607 panic!("test should not create TX queue")
608 }
609
610 fn create_rx_queue(&mut self) -> Option<Box<dyn IRxQueue>> {
611 panic!("test should not create RX queue")
612 }
613
614 fn enable_irq(&mut self) {}
615
616 fn disable_irq(&mut self) {}
617
618 fn is_irq_enabled(&self) -> bool {
619 false
620 }
621
622 fn handle_irq(&mut self) -> Event {
623 self.handle_calls.fetch_add(1, Ordering::AcqRel);
624 self.irq_events
625 }
626 }
627
628 fn count_waker(counter: Arc<AtomicUsize>) -> Waker {
629 unsafe fn clone(data: *const ()) -> RawWaker {
630 let counter = unsafe { Arc::<AtomicUsize>::from_raw(data.cast()) };
631 let cloned = Arc::clone(&counter);
632 let _ = Arc::into_raw(counter);
633 RawWaker::new(Arc::into_raw(cloned).cast(), &VTABLE)
634 }
635
636 unsafe fn wake(data: *const ()) {
637 let counter = unsafe { Arc::<AtomicUsize>::from_raw(data.cast()) };
638 counter.fetch_add(1, Ordering::AcqRel);
639 }
640
641 unsafe fn wake_by_ref(data: *const ()) {
642 let counter = unsafe { Arc::<AtomicUsize>::from_raw(data.cast()) };
643 counter.fetch_add(1, Ordering::AcqRel);
644 let _ = Arc::into_raw(counter);
645 }
646
647 unsafe fn drop(data: *const ()) {
648 let _ = unsafe { Arc::<AtomicUsize>::from_raw(data.cast()) };
649 }
650
651 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
652 let raw = RawWaker::new(Arc::into_raw(counter).cast(), &VTABLE);
653 unsafe { Waker::from_raw(raw) }
654 }
655
656 #[test]
657 fn irq_handler_fast_path_returns_events_without_waking_registered_wakers() {
658 static DMA: TestDma = TestDma;
659 let mut rx = IdList::none();
660 rx.insert(3);
661 let mut tx = IdList::none();
662 tx.insert(5);
663 let handle_calls = Arc::new(AtomicUsize::new(0));
664 let net = Net::new(
665 TestInterface {
666 irq_events: Event {
667 tx_queue: tx,
668 rx_queue: rx,
669 },
670 handle_calls: Arc::clone(&handle_calls),
671 },
672 &DMA,
673 );
674 let rx_wake_count = Arc::new(AtomicUsize::new(0));
675 let tx_wake_count = Arc::new(AtomicUsize::new(0));
676 net.inner
677 .rx_wakers
678 .register(3)
679 .register(&count_waker(Arc::clone(&rx_wake_count)));
680 net.inner
681 .tx_wakers
682 .register(5)
683 .register(&count_waker(Arc::clone(&tx_wake_count)));
684
685 let irq = net.irq_handler();
686 let events = irq.handle_irq();
687
688 assert!(events.rx_queue.contains(3));
689 assert!(events.tx_queue.contains(5));
690 assert_eq!(handle_calls.load(Ordering::Acquire), 1);
691 assert_eq!(rx_wake_count.load(Ordering::Acquire), 0);
692 assert_eq!(tx_wake_count.load(Ordering::Acquire), 0);
693 }
694}