Skip to main content

rd_net/
lib.rs

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}