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 [`Interface::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/// Core interface that network device drivers must implement.
140///
141/// Provides device-level operations: queue creation, interrupt management,
142/// and MAC address retrieval. Individual packet I/O goes through the queue
143/// traits ([`ITxQueue`] / [`IRxQueue`]).
144pub trait Interface: DriverGeneric {
145 /// Returns the device's 6-byte MAC address.
146 fn mac_address(&self) -> [u8; 6];
147
148 /// Create a new transmit queue. Returns `None` if no more queues are
149 /// available.
150 fn create_tx_queue(&mut self) -> Option<Box<dyn ITxQueue>>;
151
152 /// Create a new receive queue. Returns `None` if no more queues are
153 /// available.
154 fn create_rx_queue(&mut self) -> Option<Box<dyn IRxQueue>>;
155
156 /// Enable device interrupts.
157 fn enable_irq(&mut self);
158
159 /// Disable device interrupts.
160 fn disable_irq(&mut self);
161
162 /// Check whether device interrupts are currently enabled.
163 fn is_irq_enabled(&self) -> bool;
164
165 /// Handle a device interrupt, returning which queues have events.
166 fn handle_irq(&mut self) -> Event;
167
168 /// Optional wireless control plane.
169 ///
170 /// A plain wired NIC returns `None` (the default). A wireless device
171 /// returns its [`WifiControl`] so the upper layers can drive STA/SoftAP
172 /// control, link policy and out-of-band RX wake-up through the *same* net
173 /// device model — no separate Wi-Fi device type or registration path.
174 fn wifi_control(&mut self) -> Option<&mut dyn WifiControl> {
175 None
176 }
177}
178
179// ---------------------------------------------------------------------------
180// Optional wireless control plane
181// ---------------------------------------------------------------------------
182
183/// Wireless link policy a device reports for itself, so the protocol stack can
184/// apply it without any Wi-Fi/SoftAP-specific knowledge.
185///
186/// This is plain data carried alongside the device; the stack only sees a
187/// static IPv4 + optional single-client DHCP server lease.
188#[derive(Clone, Copy, Debug)]
189pub struct WifiLinkPolicy {
190 /// This interface's static address / SoftAP gateway.
191 pub ip: [u8; 4],
192 /// Prefix length for [`ip`](Self::ip).
193 pub prefix_len: u8,
194 /// If set, run a built-in DHCP server handing out this single address.
195 pub dhcp_server_client_ip: Option<[u8; 4]>,
196}
197
198/// Optional control plane for a wireless [`Interface`].
199///
200/// Bundles the wireless-specific capabilities (STA connect, SoftAP start, MAC,
201/// out-of-band RX wake, link policy) onto the same object that carries the data
202/// plane. A chip driver implements this on its `Interface` device so wireless
203/// devices need no bespoke lifecycle trait or registration path.
204pub trait WifiControl {
205 /// Connect to a network in STA mode (scan + associate + authenticate).
206 fn connect(&mut self, ssid: &str, password: &str) -> Result<(), NetError>;
207
208 /// Disconnect from the current STA network.
209 fn disconnect(&mut self) -> Result<(), NetError>;
210
211 /// Start an open (unencrypted) SoftAP broadcasting `ssid` on `channel`.
212 fn start_ap_open(&mut self, ssid: &[u8], channel: u8) -> Result<(), NetError>;
213
214 /// Register a wake callback for out-of-band RX.
215 ///
216 /// SDIO Wi-Fi delivers RX outside the ethernet IRQ framework, so the driver
217 /// calls this `wake` when a data frame has been enqueued, to nudge the
218 /// stack's per-device poll task.
219 fn set_rx_wake(&mut self, wake: fn());
220
221 /// The link policy this device wants applied once the stack is up. `None`
222 /// means "no special policy" (e.g. a STA that will use DHCP like any NIC).
223 fn link_policy(&self) -> Option<WifiLinkPolicy>;
224}
225
226// ---------------------------------------------------------------------------
227// Transmit queue
228// ---------------------------------------------------------------------------
229
230/// Transmit queue interface.
231///
232/// A driver creates one or more TX queues via [`Interface::create_tx_queue`]
233/// and exchanges DMA buffer bus addresses with the caller.
234pub trait ITxQueue: Send + 'static {
235 /// Queue identifier (unique within the device).
236 fn id(&self) -> usize;
237
238 /// DMA buffer configuration for this queue.
239 fn config(&self) -> QueueConfig;
240
241 /// Submit a DMA buffer for transmission.
242 ///
243 /// `bus_addr` must point to a DMA-capable buffer whose first `len` bytes
244 /// contain the packet to be transmitted.
245 fn submit(&mut self, buffer: DmaBuffer) -> Result<(), NetError>;
246
247 /// Reclaim the next completed transmit buffer.
248 ///
249 /// Returns the buffer bus address when the device has completed sending it.
250 fn reclaim(&mut self) -> Option<u64>;
251}
252
253// ---------------------------------------------------------------------------
254// Receive queue
255// ---------------------------------------------------------------------------
256
257/// Receive queue interface.
258///
259/// A driver creates one or more RX queues via [`Interface::create_rx_queue`]
260/// and exchanges DMA buffer bus addresses with the caller.
261pub trait IRxQueue: Send + 'static {
262 /// Queue identifier (unique within the device).
263 fn id(&self) -> usize;
264
265 /// DMA buffer configuration for this queue.
266 fn config(&self) -> QueueConfig;
267
268 /// Submit an empty DMA buffer to hardware.
269 ///
270 /// `bus_addr` must point to a DMA-capable buffer whose total size is `len`.
271 fn submit(&mut self, buffer: DmaBuffer) -> Result<(), NetError>;
272
273 /// Reclaim the next completed receive buffer.
274 ///
275 /// Returns the buffer bus address and the received byte count.
276 fn reclaim(&mut self) -> Option<(u64, usize)>;
277}