Skip to main content

rdif_eth/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use alloc::boxed::Box;
6use core::ptr::NonNull;
7
8pub use dma_api;
9pub use rdif_base::{DriverGeneric, KError, io};
10
11// ---------------------------------------------------------------------------
12// Error
13// ---------------------------------------------------------------------------
14
15/// Errors that can occur during network device operations.
16#[derive(thiserror::Error, Debug)]
17pub enum NetError {
18    /// The requested operation is not supported by the device.
19    #[error("Operation not supported")]
20    NotSupported,
21
22    /// The operation should be retried later (e.g. queue full).
23    #[error("Operation should be retried")]
24    Retry,
25
26    /// Insufficient memory to complete the operation.
27    #[error("Insufficient memory")]
28    NoMemory,
29
30    /// The network link is down.
31    #[error("Link down")]
32    LinkDown,
33
34    /// An unspecified error occurred.
35    #[error("Other error: {0}")]
36    Other(Box<dyn core::error::Error>),
37}
38
39impl From<NetError> for io::ErrorKind {
40    fn from(value: NetError) -> Self {
41        match value {
42            NetError::NotSupported => io::ErrorKind::Unsupported,
43            NetError::Retry => io::ErrorKind::Interrupted,
44            NetError::NoMemory => io::ErrorKind::OutOfMemory,
45            NetError::LinkDown => io::ErrorKind::NotAvailable,
46            NetError::Other(e) => io::ErrorKind::Other(e),
47        }
48    }
49}
50
51impl From<dma_api::DmaError> for NetError {
52    fn from(value: dma_api::DmaError) -> Self {
53        match value {
54            dma_api::DmaError::NoMemory => NetError::NoMemory,
55            e => NetError::Other(Box::new(e)),
56        }
57    }
58}
59
60// ---------------------------------------------------------------------------
61// DMA buffer helpers
62// ---------------------------------------------------------------------------
63
64/// Queue configuration needed by the upper layer DMA pool.
65#[derive(Debug, Clone, Copy)]
66pub struct QueueConfig {
67    /// DMA addressing mask for the device.
68    pub dma_mask: u64,
69
70    /// Required alignment for buffer addresses (in bytes).
71    pub align: usize,
72
73    /// DMA packet buffer size in bytes.
74    pub buf_size: usize,
75
76    /// Descriptor ring size.
77    pub ring_size: usize,
78}
79
80/// DMA buffer passed from the runtime queue layer to a driver queue.
81#[derive(Clone, Copy, Debug)]
82pub struct DmaBuffer {
83    /// CPU virtual address for drivers that need to build descriptors from a
84    /// slice or write transport-specific headers.
85    pub virt: NonNull<u8>,
86    /// Device-visible DMA address for hardware descriptors.
87    pub bus_addr: u64,
88    /// Buffer length in bytes.
89    pub len: usize,
90}
91
92/// Bitmask tracking up to 64 queue identifiers.
93#[repr(transparent)]
94#[derive(Debug, Clone, Copy)]
95pub struct IdList(u64);
96
97impl IdList {
98    pub const fn none() -> Self {
99        Self(0)
100    }
101
102    pub fn contains(&self, id: usize) -> bool {
103        (self.0 & (1 << id)) != 0
104    }
105
106    pub fn insert(&mut self, id: usize) {
107        self.0 |= 1 << id;
108    }
109
110    pub fn remove(&mut self, id: usize) {
111        self.0 &= !(1 << id);
112    }
113
114    pub fn iter(&self) -> impl Iterator<Item = usize> {
115        let bits = self.0;
116        (0..64).filter(move |i| (bits & (1 << i)) != 0)
117    }
118}
119
120/// Event returned by [`IrqHandler::handle_irq`] indicating which queues have
121/// completed operations.
122#[derive(Debug, Clone, Copy)]
123pub struct Event {
124    /// Bitmask of TX queue IDs that have completion events.
125    pub tx_queue: IdList,
126    /// Bitmask of RX queue IDs that have completion events.
127    pub rx_queue: IdList,
128}
129
130impl Event {
131    pub const fn none() -> Self {
132        Self {
133            tx_queue: IdList::none(),
134            rx_queue: IdList::none(),
135        }
136    }
137}
138
139/// Owned interrupt endpoint for a network device.
140///
141/// Drivers that can split their control/data-plane state from the IRQ
142/// top-half should return this through [`Interface::take_irq_handler`]. The
143/// handler is then moved into the platform IRQ callback, so hard IRQ context no
144/// longer needs to lock the complete network device object.
145pub trait IrqHandler: Send + 'static {
146    /// Acknowledge/snapshot the device IRQ source and publish queue-local event
147    /// bits. Packet copies, descriptor refills, DMA reclaim, and waker
148    /// execution must stay in task/deferred context.
149    fn handle_irq(&mut self) -> Event;
150}
151
152/// Boxed owned IRQ endpoint.
153pub type BIrqHandler = Box<dyn IrqHandler>;
154
155/// Core interface that network device drivers must implement.
156///
157/// Provides device-level operations: queue creation, interrupt management,
158/// and MAC address retrieval. Individual packet I/O goes through the queue
159/// traits ([`ITxQueue`] / [`IRxQueue`]).
160pub trait Interface: DriverGeneric {
161    /// Returns the device's 6-byte MAC address.
162    fn mac_address(&self) -> [u8; 6];
163
164    /// Create a new transmit queue. Returns `None` if no more queues are
165    /// available.
166    fn create_tx_queue(&mut self) -> Option<Box<dyn ITxQueue>>;
167
168    /// Create a new receive queue. Returns `None` if no more queues are
169    /// available.
170    fn create_rx_queue(&mut self) -> Option<Box<dyn IRxQueue>>;
171
172    /// Enable device interrupts.
173    fn enable_irq(&mut self);
174
175    /// Disable device interrupts.
176    fn disable_irq(&mut self);
177
178    /// Check whether device interrupts are currently enabled.
179    fn is_irq_enabled(&self) -> bool;
180
181    /// Handle a device interrupt, returning which queues have events.
182    ///
183    /// This method is kept for non-OS test code and direct polling adapters.
184    /// Runtime IRQ registration must use [`Interface::take_irq_handler`] so the
185    /// hard IRQ callback owns a narrow endpoint instead of borrowing the full
186    /// interface object.
187    fn handle_irq(&mut self) -> Event;
188
189    /// Detach an owned IRQ endpoint from the interface.
190    ///
191    /// Returns `None` for devices without an OS-registered NIC IRQ. Drivers
192    /// with an IRQ line must return `Some` so hard IRQ callbacks do not need to
193    /// lock the whole device.
194    fn take_irq_handler(&mut self) -> Option<BIrqHandler> {
195        None
196    }
197
198    /// Optional wireless control plane.
199    ///
200    /// A plain wired NIC returns `None` (the default). A wireless device
201    /// returns its [`WifiControl`] so the upper layers can drive STA/SoftAP
202    /// control, link policy and out-of-band RX wake-up through the *same* net
203    /// device model — no separate Wi-Fi device type or registration path.
204    fn wifi_control(&mut self) -> Option<&mut dyn WifiControl> {
205        None
206    }
207}
208
209// ---------------------------------------------------------------------------
210// Optional wireless control plane
211// ---------------------------------------------------------------------------
212
213/// Wireless link policy a device reports for itself, so the protocol stack can
214/// apply it without any Wi-Fi/SoftAP-specific knowledge.
215///
216/// This is plain data carried alongside the device; the stack only sees a
217/// static IPv4 + optional single-client DHCP server lease.
218#[derive(Clone, Copy, Debug)]
219pub struct WifiLinkPolicy {
220    /// This interface's static address / SoftAP gateway.
221    pub ip: [u8; 4],
222    /// Prefix length for [`ip`](Self::ip).
223    pub prefix_len: u8,
224    /// If set, run a built-in DHCP server handing out this single address.
225    pub dhcp_server_client_ip: Option<[u8; 4]>,
226}
227
228/// Optional control plane for a wireless [`Interface`].
229///
230/// Bundles the wireless-specific capabilities (STA connect, SoftAP start, MAC,
231/// out-of-band RX wake, link policy) onto the same object that carries the data
232/// plane. A chip driver implements this on its `Interface` device so wireless
233/// devices need no bespoke lifecycle trait or registration path.
234pub trait WifiControl {
235    /// Connect to a network in STA mode (scan + associate + authenticate).
236    fn connect(&mut self, ssid: &str, password: &str) -> Result<(), NetError>;
237
238    /// Disconnect from the current STA network.
239    fn disconnect(&mut self) -> Result<(), NetError>;
240
241    /// Start an open (unencrypted) SoftAP broadcasting `ssid` on `channel`.
242    fn start_ap_open(&mut self, ssid: &[u8], channel: u8) -> Result<(), NetError>;
243
244    /// Register a wake callback for out-of-band RX.
245    ///
246    /// SDIO Wi-Fi delivers RX outside the ethernet IRQ framework, so the driver
247    /// calls this `wake` when a data frame has been enqueued, to nudge the
248    /// stack's per-device poll task.
249    fn set_rx_wake(&mut self, wake: fn());
250
251    /// The link policy this device wants applied once the stack is up. `None`
252    /// means "no special policy" (e.g. a STA that will use DHCP like any NIC).
253    fn link_policy(&self) -> Option<WifiLinkPolicy>;
254}
255
256// ---------------------------------------------------------------------------
257// Transmit queue
258// ---------------------------------------------------------------------------
259
260/// Transmit queue interface.
261///
262/// A driver creates one or more TX queues via [`Interface::create_tx_queue`]
263/// and exchanges DMA buffer bus addresses with the caller.
264pub trait ITxQueue: Send + 'static {
265    /// Queue identifier (unique within the device).
266    fn id(&self) -> usize;
267
268    /// DMA buffer configuration for this queue.
269    fn config(&self) -> QueueConfig;
270
271    /// Submit a DMA buffer for transmission.
272    ///
273    /// `bus_addr` must point to a DMA-capable buffer whose first `len` bytes
274    /// contain the packet to be transmitted.
275    fn submit(&mut self, buffer: DmaBuffer) -> Result<(), NetError>;
276
277    /// Reclaim the next completed transmit buffer.
278    ///
279    /// Returns the buffer bus address when the device has completed sending it.
280    fn reclaim(&mut self) -> Option<u64>;
281}
282
283// ---------------------------------------------------------------------------
284// Receive queue
285// ---------------------------------------------------------------------------
286
287/// Receive queue interface.
288///
289/// A driver creates one or more RX queues via [`Interface::create_rx_queue`]
290/// and exchanges DMA buffer bus addresses with the caller.
291pub trait IRxQueue: Send + 'static {
292    /// Queue identifier (unique within the device).
293    fn id(&self) -> usize;
294
295    /// DMA buffer configuration for this queue.
296    fn config(&self) -> QueueConfig;
297
298    /// Submit an empty DMA buffer to hardware.
299    ///
300    /// `bus_addr` must point to a DMA-capable buffer whose total size is `len`.
301    fn submit(&mut self, buffer: DmaBuffer) -> Result<(), NetError>;
302
303    /// Reclaim the next completed receive buffer.
304    ///
305    /// Returns the buffer bus address and the received byte count.
306    fn reclaim(&mut self) -> Option<(u64, usize)>;
307}