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::{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    pub fn create_tx_queue(&mut self) -> Result<TxQueue, NetError> {
110        let irq_guard = self.irq_guard();
111        let queue = self
112            .interface()
113            .create_tx_queue()
114            .ok_or_else(|| other_error("failed to create tx queue"))?;
115        let config = queue.config();
116        let pool = make_pool(self.inner.dma_op, config, DmaDirection::ToDevice)?;
117        let waker = self.inner.tx_wakers.register(queue.id());
118        drop(irq_guard);
119
120        Ok(TxQueue {
121            interface: queue,
122            pool,
123            inflight: BTreeMap::new(),
124            config,
125            _waker: waker,
126        })
127    }
128
129    pub fn create_rx_queue(&mut self) -> Result<RxQueue, NetError> {
130        let irq_guard = self.irq_guard();
131        let queue = self
132            .interface()
133            .create_rx_queue()
134            .ok_or_else(|| other_error("failed to create rx queue"))?;
135        let config = queue.config();
136        let pool = make_pool(self.inner.dma_op, config, DmaDirection::FromDevice)?;
137        let waker = self.inner.rx_wakers.register(queue.id());
138        drop(irq_guard);
139
140        let mut rx = RxQueue {
141            interface: queue,
142            pool,
143            inflight: BTreeMap::new(),
144            config,
145            _waker: waker,
146        };
147        rx.prefill()?;
148        Ok(rx)
149    }
150
151    pub fn irq_handler(&self) -> IrqHandler {
152        IrqHandler {
153            inner: self.inner.clone(),
154        }
155    }
156}
157
158fn make_pool(
159    dma_op: &'static dyn DmaOp,
160    config: QueueConfig,
161    direction: DmaDirection,
162) -> Result<ContiguousBufferPool, NetError> {
163    let layout = Layout::from_size_align(config.buf_size, config.align.max(1))
164        .map_err(|_| other_error("invalid queue layout"))?;
165    let dma = DeviceDma::new(config.dma_mask, dma_op);
166    Ok(dma.contiguous_buffer_pool(layout, direction, config.ring_size))
167}
168
169pub struct IrqHandler {
170    inner: Arc<NetInner>,
171}
172
173unsafe impl Sync for IrqHandler {}
174
175impl IrqHandler {
176    pub fn handle(&self) {
177        let iface = unsafe { &mut **self.inner.interface.get() };
178        let event = iface.handle_irq();
179        for id in event.tx_queue.iter() {
180            self.inner.tx_wakers.wake(id);
181        }
182        for id in event.rx_queue.iter() {
183            self.inner.rx_wakers.wake(id);
184        }
185    }
186}
187
188pub struct TxQueue {
189    interface: Box<dyn ITxQueue>,
190    pool: ContiguousBufferPool,
191    inflight: BTreeMap<u64, ContiguousBuffer>,
192    config: QueueConfig,
193    _waker: Arc<AtomicWaker>,
194}
195
196impl TxQueue {
197    fn capacity(&self) -> usize {
198        self.config.ring_size.saturating_sub(1)
199    }
200
201    fn reclaim_bounded(&mut self, limit: usize) -> Result<usize, NetError> {
202        let mut reclaimed = 0;
203        while reclaimed < limit {
204            let Some(bus_addr) = self.interface.reclaim() else {
205                break;
206            };
207            let Some(buff) = self.inflight.remove(&bus_addr) else {
208                return Err(other_error("reclaimed unknown tx buffer"));
209            };
210            drop(buff);
211            reclaimed += 1;
212        }
213        Ok(reclaimed)
214    }
215
216    pub fn id(&self) -> usize {
217        self.interface.id()
218    }
219
220    pub fn buf_size(&self) -> usize {
221        self.config.buf_size
222    }
223
224    pub fn prepare_send<R>(
225        &mut self,
226        len: usize,
227        f: impl FnOnce(&mut [u8]) -> R,
228    ) -> Result<(R, TxPending<'_>), NetError> {
229        if len > self.config.buf_size {
230            return Err(other_error("tx packet too large"));
231        }
232
233        self.reclaim_bounded(self.capacity().max(1))?;
234
235        let mut buff = self.pool.alloc()?;
236        let bus_addr = buff.dma_addr().as_u64();
237        let ret = buff.write_with_cpu(len, f);
238        Ok((
239            ret,
240            TxPending {
241                queue: self,
242                len,
243                bus_addr,
244                buff: Some(buff),
245            },
246        ))
247    }
248}
249
250pub struct TxPending<'a> {
251    queue: &'a mut TxQueue,
252    len: usize,
253    bus_addr: u64,
254    buff: Option<ContiguousBuffer>,
255}
256
257impl TxPending<'_> {
258    pub fn bus_addr(&self) -> u64 {
259        self.bus_addr
260    }
261
262    pub fn len(&self) -> usize {
263        self.len
264    }
265
266    pub fn is_empty(&self) -> bool {
267        self.len == 0
268    }
269
270    pub fn try_submit(&mut self) -> Result<(), NetError> {
271        self.queue.reclaim_bounded(self.queue.capacity().max(1))?;
272        let buff = self
273            .buff
274            .as_ref()
275            .expect("tx pending buffer should exist until submit succeeds");
276        buff.prepare_for_device(0, self.len);
277        self.queue.interface.submit(DmaBuffer {
278            virt: buff.as_ptr(),
279            bus_addr: self.bus_addr,
280            len: self.len,
281        })?;
282        let buff = self
283            .buff
284            .take()
285            .expect("tx pending buffer should exist until submit succeeds");
286        self.queue.inflight.insert(self.bus_addr, buff);
287        Ok(())
288    }
289}
290
291pub struct RxQueue {
292    interface: Box<dyn IRxQueue>,
293    pool: ContiguousBufferPool,
294    inflight: BTreeMap<u64, ContiguousBuffer>,
295    config: QueueConfig,
296    _waker: Arc<AtomicWaker>,
297}
298
299impl RxQueue {
300    fn capacity(&self) -> usize {
301        self.config.ring_size.saturating_sub(1)
302    }
303
304    fn prefill(&mut self) -> Result<(), NetError> {
305        while self.inflight.len() < self.capacity() {
306            let buff = self.pool.alloc()?;
307            if let Err(err) = self.submit_buffer(buff) {
308                if matches!(err, NetError::Retry) {
309                    break;
310                }
311                return Err(err);
312            }
313        }
314        Ok(())
315    }
316
317    fn submit_buffer(&mut self, buff: ContiguousBuffer) -> Result<(), NetError> {
318        let bus_addr = buff.dma_addr().as_u64();
319        let len = self.config.buf_size.min(buff.len());
320        buff.prepare_for_device(0, len);
321        self.interface.submit(DmaBuffer {
322            virt: buff.as_ptr(),
323            bus_addr,
324            len,
325        })?;
326        self.inflight.insert(bus_addr, buff);
327        Ok(())
328    }
329
330    fn reclaim_packet(&mut self) -> Result<Option<(ContiguousBuffer, usize)>, NetError> {
331        let Some((bus_addr, len)) = self.interface.reclaim() else {
332            return Ok(None);
333        };
334        let Some(buff) = self.inflight.remove(&bus_addr) else {
335            return Err(other_error("reclaimed unknown rx buffer"));
336        };
337        let packet_len = len.min(self.config.buf_size).min(buff.len());
338        buff.complete_for_cpu(0, packet_len);
339        Ok(Some((buff, packet_len)))
340    }
341
342    pub fn id(&self) -> usize {
343        self.interface.id()
344    }
345
346    pub fn buf_size(&self) -> usize {
347        self.config.buf_size
348    }
349
350    pub fn try_receive(&mut self) -> Option<RxPacket<'_>> {
351        match self.reclaim_packet() {
352            Ok(Some((buff, len))) => Some(RxPacket {
353                queue: self,
354                len,
355                buff: Some(buff),
356            }),
357            Ok(None) | Err(_) => None,
358        }
359    }
360
361    pub fn receive<R>(&mut self, f: impl FnOnce(&[u8]) -> R) -> Option<R> {
362        let packet = self.try_receive()?;
363        Some(packet.consume(f))
364    }
365}
366
367pub struct RxPacket<'a> {
368    queue: &'a mut RxQueue,
369    len: usize,
370    buff: Option<ContiguousBuffer>,
371}
372
373impl RxPacket<'_> {
374    pub fn len(&self) -> usize {
375        self.len
376    }
377
378    pub fn is_empty(&self) -> bool {
379        self.len == 0
380    }
381
382    pub fn consume<R>(mut self, f: impl FnOnce(&[u8]) -> R) -> R {
383        let buff = self.buff.as_ref().expect("rx packet buffer should exist");
384        let ret = buff.read_with_cpu(self.len, f);
385        if let Some(buff) = self.buff.take() {
386            let _ = self.queue.submit_buffer(buff);
387        }
388        ret
389    }
390}
391
392impl Drop for RxPacket<'_> {
393    fn drop(&mut self) {
394        if let Some(buff) = self.buff.take() {
395            let _ = self.queue.submit_buffer(buff);
396        }
397    }
398}