Skip to main content

realtek_rtl8125/
lib.rs

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};