1#![no_std]
2
3extern crate alloc;
4
5use alloc::{boxed::Box, collections::VecDeque, sync::Arc};
6
7use descriptor::{RING_END, RxDesc, TxDesc};
8use dma_api::{DeviceDma, DmaOp};
9use log::info;
10use mmio_api::{Mmio, MmioAddr, MmioOp};
11use queue::{QueueStart, QueueStartState, Rtl8125RxQueue, Rtl8125TxQueue};
12use rdif_eth::{Event, IRxQueue, ITxQueue, Interface};
13use registers::*;
14use spin::Mutex;
15
16mod descriptor;
17mod hw;
18mod queue;
19mod registers;
20
21const DRIVER_NAME: &str = "realtek-rtl8125";
22const QUEUE_ID0: usize = 0;
23const QUEUE_SIZE: usize = 256;
24const RX_QUEUE_CONFIG_SIZE: usize = QUEUE_SIZE + 1;
25const RX_START_THRESHOLD: usize = QUEUE_SIZE;
26const MAX_PACKET: usize = 2048;
27const RX_BUF_SIZE: usize = 2048;
28const DMA_ALIGN: usize = 256;
29const DMA_CACHE_LINE_SIZE: usize = 64;
30const RX_DESC_PER_CACHE_LINE: usize = DMA_CACHE_LINE_SIZE / core::mem::size_of::<RxDesc>();
31const RX_DEFERRED_REFILL_CAPACITY: usize = QUEUE_SIZE;
32const LINK_DOWN_DROP_LOG_INTERVAL: u64 = 64;
33const EARLY_PACKET_LOG_COUNT: u64 = 8;
34const TX_SUBMIT_LOG_INTERVAL: u64 = 16;
35const TX_RECLAIM_LOG_INTERVAL: u64 = 64;
36const RX_RECLAIM_LOG_INTERVAL: u64 = 64;
37const RX_IDLE_LOG_INTERVAL: u64 = 262_144;
38const RX_OVERFLOW_REARM_IDLE_POLLS: u64 = 2048;
39const TX_LINK_SAMPLE_INTERVAL: u64 = 64;
40const OCP_STD_PHY_BASE: u32 = 0xa400;
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum ChipVersion {
44 Rtl8125A,
45 Rtl8125B,
46 Unknown(u16),
47}
48
49#[derive(Debug, Clone, Copy)]
50pub struct Rtl8125Status {
51 pub phy_status: u8,
52 pub chip_cmd: u8,
53 pub mcu: u8,
54 pub intr_status: u32,
55 pub intr_mask: u32,
56 pub rx_config: u32,
57 pub tx_config: u32,
58 pub cplus_cmd: u16,
59 pub rx_desc_base: u64,
60}
61
62impl Rtl8125Status {
63 pub const fn link_up(&self) -> bool {
64 phy_status_link_up(self.phy_status)
65 }
66}
67
68#[derive(thiserror::Error, Debug)]
69pub enum Error {
70 #[error("unsupported PCI id {vendor:#06x}:{device:#06x}")]
71 UnsupportedPciId { vendor: u16, device: u16 },
72 #[error("MMIO map failed")]
73 MmioMap(#[from] mmio_api::MapError),
74 #[error("DMA allocation failed")]
75 Dma(#[from] dma_api::DmaError),
76 #[error("invalid MAC address")]
77 InvalidMacAddress,
78 #[error("hardware reset timed out")]
79 ResetTimeout,
80 #[error("wait for {operation} timed out")]
81 HardwareTimeout { operation: &'static str },
82 #[error("invalid OCP register address {reg:#x}")]
83 InvalidOcpAddress { reg: u32 },
84}
85
86pub type Result<T> = core::result::Result<T, Error>;
87
88pub struct Rtl8125 {
89 regs: Regs,
90 _mmio: Mmio,
91 dma: DeviceDma,
92 mac: [u8; 6],
93 chip: ChipVersion,
94 tx_created: bool,
95 rx_created: bool,
96 phy_ocp_base: u32,
97 queue_start: QueueStart,
98}
99
100impl Rtl8125 {
101 pub fn check_vid_did(vendor: u16, device: u16) -> bool {
102 vendor == VENDOR_ID && device == DEVICE_ID_RTL8125
103 }
104
105 pub fn new(
106 bar_addr: impl Into<MmioAddr>,
107 bar_size: usize,
108 dma_mask: u64,
109 dma_op: &'static dyn DmaOp,
110 mmio_op: &'static dyn MmioOp,
111 ) -> Result<Self> {
112 mmio_api::init(mmio_op);
113 let mmio = mmio_api::ioremap(bar_addr.into(), bar_size.max(RTL8125_REGS_SIZE))?;
114 let regs = Regs::new(mmio.as_nonnull_ptr());
115 let dma = DeviceDma::new(dma_mask, dma_op);
116 let xid = rtl8125_xid(regs);
117 let chip = chip_version(xid);
118
119 let mut dev = Self {
120 regs,
121 _mmio: mmio,
122 dma,
123 mac: [0; 6],
124 chip,
125 tx_created: false,
126 rx_created: false,
127 phy_ocp_base: OCP_STD_PHY_BASE,
128 queue_start: Arc::new(Mutex::new(QueueStartState::default())),
129 };
130 dev.init()?;
131 info!(
132 "RTL8125 device initialized: chip={:?}, xid={:#x}, \
133 mac={:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}, status={:?}",
134 dev.chip,
135 xid,
136 dev.mac[0],
137 dev.mac[1],
138 dev.mac[2],
139 dev.mac[3],
140 dev.mac[4],
141 dev.mac[5],
142 dev.status(),
143 );
144 Ok(dev)
145 }
146
147 pub fn init(&mut self) -> Result<()> {
148 self.disable_irq();
149 self.ack_events(u32::MAX);
150 self.reset()?;
151 self.hw_init_8125()?;
152
153 self.mac = self.read_mac_address()?;
154 self.set_mac_address(self.mac);
155 self.regs.configure_cplus(self.dma.dma_mask());
156 self.regs.write_default_rx_config();
157 self.regs.write_default_tx_config();
158 self.regs.write_rx_max_size(RX_BUF_SIZE as u16 + 1);
159 self.regs.disable_interrupt_mitigation();
160 self.hw_start_8125()?;
161 self.hw_phy_config()?;
162 Ok(())
163 }
164
165 pub fn mac_address(&self) -> [u8; 6] {
166 self.mac
167 }
168
169 pub fn chip_version(&self) -> ChipVersion {
170 self.chip
171 }
172
173 pub fn poll_link(&self) -> bool {
174 self.status().link_up()
175 }
176
177 pub fn status(&self) -> Rtl8125Status {
178 read_status(self.regs)
179 }
180
181 fn read_mac_address(&self) -> Result<[u8; 6]> {
182 let mac = self.regs.read_backup_mac();
183 if is_valid_mac(mac) {
184 return Ok(mac);
185 }
186
187 let mac = self.regs.read_mac();
188 if is_valid_mac(mac) {
189 return Ok(mac);
190 }
191
192 Err(Error::InvalidMacAddress)
193 }
194
195 fn set_mac_address(&self, mac: [u8; 6]) {
196 self.regs.unlock_config();
197 self.regs.write_mac(mac);
198 self.regs.lock_config();
199 }
200
201 fn reset(&self) -> Result<()> {
202 self.regs.request_reset();
203 for _ in 0..100_000 {
204 if !self.regs.reset_pending() {
205 return Ok(());
206 }
207 core::hint::spin_loop();
208 }
209 Err(Error::ResetTimeout)
210 }
211}
212
213impl rdif_eth::DriverGeneric for Rtl8125 {
214 fn name(&self) -> &str {
215 DRIVER_NAME
216 }
217}
218
219impl Interface for Rtl8125 {
220 fn mac_address(&self) -> [u8; 6] {
221 self.mac
222 }
223
224 fn create_tx_queue(&mut self) -> Option<Box<dyn ITxQueue>> {
225 if self.tx_created {
226 return None;
227 }
228
229 let mut desc = self
230 .dma
231 .coherent_array_zero_with_align::<TxDesc>(QUEUE_SIZE, DMA_ALIGN)
232 .ok()?;
233 desc.set_cpu(
234 QUEUE_SIZE - 1,
235 TxDesc {
236 opts1: RING_END,
237 opts2: 0,
238 addr: 0,
239 },
240 );
241
242 {
243 let mut start = self.queue_start.lock();
244 start.tx_base = Some(desc.dma_addr().as_u64());
245 }
246 self.tx_created = true;
247 self.maybe_start_queues();
248
249 Some(queue::boxed_tx(Rtl8125TxQueue {
250 regs: self.regs,
251 desc,
252 dma_mask: self.dma.dma_mask(),
253 bus_addrs: [None; QUEUE_SIZE],
254 next_submit: 0,
255 next_reclaim: 0,
256 link_up: None,
257 link_down_drops: 0,
258 submitted: 0,
259 reclaimed: 0,
260 }))
261 }
262
263 fn create_rx_queue(&mut self) -> Option<Box<dyn IRxQueue>> {
264 if self.rx_created {
265 return None;
266 }
267
268 let desc = self
269 .dma
270 .coherent_array_zero_with_align::<RxDesc>(QUEUE_SIZE, DMA_ALIGN)
271 .ok()?;
272
273 {
274 let mut start = self.queue_start.lock();
275 start.rx_base = Some(desc.dma_addr().as_u64());
276 }
277 self.rx_created = true;
278 self.maybe_start_queues();
279
280 Some(queue::boxed_rx(Rtl8125RxQueue {
281 regs: self.regs,
282 desc,
283 dma_mask: self.dma.dma_mask(),
284 start: self.queue_start.clone(),
285 bus_addrs: [None; QUEUE_SIZE],
286 next_submit: 0,
287 next_reclaim: 0,
288 idle_polls: 0,
289 last_rx_rearm_idle: 0,
290 submitted: 0,
291 reclaimed: 0,
292 rx_errors: 0,
293 deferred_refill: VecDeque::with_capacity(RX_DEFERRED_REFILL_CAPACITY),
294 }))
295 }
296
297 fn enable_irq(&mut self) {
298 self.ack_events(u32::MAX);
299 self.regs.write_interrupt_mask(DEFAULT_IRQ_MASK);
300 }
301
302 fn disable_irq(&mut self) {
303 self.regs.write_interrupt_mask(0);
304 }
305
306 fn is_irq_enabled(&self) -> bool {
307 self.regs.read_interrupt_mask() != 0
308 }
309
310 fn handle_irq(&mut self) -> Event {
311 let status = self.regs.read_interrupt_status();
312 if status == 0 || status == u32::MAX {
313 return Event::none();
314 }
315
316 self.ack_events(status);
317
318 let mut event = Event::none();
319 if irq_has_tx_event(status) {
320 event.tx_queue.insert(QUEUE_ID0);
321 }
322 if irq_has_rx_event(status) {
323 event.rx_queue.insert(QUEUE_ID0);
324 }
325 if irq_has_link_change(status) {
326 info!("RTL8125 irq link change: status={:?}", self.status());
327 }
328 event
329 }
330}
331
332fn rtl8125_xid(regs: Regs) -> u16 {
333 ((regs.read_tx_config() >> 20) & 0x0fcf) as u16
334}
335
336fn read_status(regs: Regs) -> Rtl8125Status {
337 Rtl8125Status {
338 phy_status: regs.read_phy_status(),
339 chip_cmd: regs.read_chip_cmd(),
340 mcu: regs.read_mcu(),
341 intr_status: regs.read_interrupt_status(),
342 intr_mask: regs.read_interrupt_mask(),
343 rx_config: regs.read_rx_config(),
344 tx_config: regs.read_tx_config(),
345 cplus_cmd: regs.read_cplus_cmd(),
346 rx_desc_base: regs.read_rx_desc_base(),
347 }
348}
349
350pub(crate) fn set_rx_mode(regs: Regs) {
351 regs.set_multicast_filter_all();
352 regs.set_rx_accept_mode();
353}
354
355fn chip_version(xid: u16) -> ChipVersion {
356 if xid & 0x07cf == 0x0641 {
357 ChipVersion::Rtl8125B
358 } else if xid & 0x07cf == 0x0609 {
359 ChipVersion::Rtl8125A
360 } else {
361 ChipVersion::Unknown(xid)
362 }
363}
364
365fn is_valid_mac(mac: [u8; 6]) -> bool {
366 mac != [0; 6] && mac != [0xff; 6] && mac[0] & 1 == 0
367}
368
369const _: () = {
370 assert!(size_of::<TxDesc>() == 16);
371 assert!(size_of::<RxDesc>() == 16);
372};