Skip to main content

strat9_kernel/hardware/nic/
rtl8139_drv.rs

1// RTL8139 Ethernet Controller Driver
2// Reference: RTL8139/RTL8100 Series Data Sheet
3
4use crate::{
5    hardware::{
6        nic::NetworkDevice,
7        pci_client::{self as pci, Bar, ProbeCriteria},
8    },
9    memory::{allocate_dma_frame, phys_to_virt},
10};
11use alloc::{format, string::String, sync::Arc, vec::Vec};
12use core::sync::atomic::{AtomicUsize, Ordering};
13use spin::Mutex;
14
15use crate::hardware::nic::NetError;
16
17const RX_BUFFER_SIZE: usize = 8192;
18const RX_BUFFER_PAD: usize = 16;
19const TX_BUFFER_SIZE: usize = 2048;
20const TX_BUFFERS_COUNT: usize = 4;
21const MTU: usize = 1536;
22
23const CR_RST: u8 = 1 << 4;
24const CR_RE: u8 = 1 << 3;
25const CR_TE: u8 = 1 << 2;
26const CR_BUFE: u8 = 1 << 0;
27
28const RCR_WRAP: u32 = 1 << 7;
29const RCR_AB: u32 = 1 << 3;
30const RCR_AM: u32 = 1 << 2;
31const RCR_APM: u32 = 1 << 1;
32const RCR_AAP: u32 = 1 << 0;
33const RCR_RBLEN: u32 = 0 << 11;
34
35const TCR_IFG: u32 = 3 << 24;
36const TCR_MXDMA: u32 = 7 << 8;
37
38const ISR_ROK: u16 = 1 << 0;
39const ISR_TOK: u16 = 1 << 2;
40
41#[allow(dead_code)]
42const TOK: u32 = 1 << 15;
43const OWN: u32 = 1 << 13;
44
45struct Ports {
46    io_base: u16,
47}
48
49impl Ports {
50    /// Creates a new instance.
51    fn new(io_base: u16) -> Self {
52        Self { io_base }
53    }
54
55    /// Performs the read8 operation.
56    #[inline]
57    fn read8(&self, offset: u16) -> u8 {
58        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).read() }
59    }
60
61    /// Performs the write8 operation.
62    #[inline]
63    fn write8(&mut self, offset: u16, value: u8) {
64        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).write(value) }
65    }
66
67    /// Performs the read16 operation.
68    #[inline]
69    #[allow(dead_code)]
70    fn read16(&self, offset: u16) -> u16 {
71        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).read() }
72    }
73
74    /// Performs the write16 operation.
75    #[inline]
76    fn write16(&mut self, offset: u16, value: u16) {
77        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).write(value) }
78    }
79
80    /// Performs the read32 operation.
81    #[inline]
82    fn read32(&self, offset: u16) -> u32 {
83        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).read() }
84    }
85
86    /// Performs the write32 operation.
87    #[inline]
88    fn write32(&mut self, offset: u16, value: u32) {
89        unsafe { x86_64::instructions::port::Port::new(self.io_base + offset).write(value) }
90    }
91
92    /// Performs the mac operation.
93    fn mac(&mut self) -> [u8; 6] {
94        [
95            self.read8(0x00),
96            self.read8(0x01),
97            self.read8(0x02),
98            self.read8(0x03),
99            self.read8(0x04),
100            self.read8(0x05),
101        ]
102    }
103}
104
105pub struct Rtl8139Device {
106    ports: Mutex<Ports>,
107    rx_buffer: *mut u8,
108    rx_phys: u64,
109    rx_offset: AtomicUsize,
110    tx_buffers: [*mut u8; TX_BUFFERS_COUNT],
111    tx_phys: [u64; TX_BUFFERS_COUNT],
112    tx_id: AtomicUsize,
113    mac: [u8; 6],
114    name: String,
115}
116
117unsafe impl Send for Rtl8139Device {}
118unsafe impl Sync for Rtl8139Device {}
119
120impl Rtl8139Device {
121    /// Creates a new instance.
122    pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Self, &'static str> {
123        let io_base = match pci_dev.read_bar(0) {
124            Some(Bar::Io { port }) => port as u16,
125            _ => return Err("Invalid BAR"),
126        };
127
128        let mut ports = Ports::new(io_base);
129        let mac = ports.mac();
130        let name = format!("rtl8139_{:02x}{:02x}{:02x}", mac[3], mac[4], mac[5]);
131
132        let rx_frame = allocate_dma_frame().ok_or("Failed to allocate RX buffer")?;
133        let rx_phys = rx_frame.start_address.as_u64();
134        let rx_buffer = phys_to_virt(rx_phys) as *mut u8;
135        core::ptr::write_bytes(rx_buffer, 0, RX_BUFFER_SIZE + RX_BUFFER_PAD + MTU);
136
137        let mut tx_buffers = [core::ptr::null_mut(); TX_BUFFERS_COUNT];
138        let mut tx_phys = [0u64; TX_BUFFERS_COUNT];
139        for i in 0..TX_BUFFERS_COUNT {
140            let frame = allocate_dma_frame().ok_or("Failed to allocate TX buffer")?;
141            tx_phys[i] = frame.start_address.as_u64();
142            tx_buffers[i] = phys_to_virt(tx_phys[i]) as *mut u8;
143            core::ptr::write_bytes(tx_buffers[i], 0, TX_BUFFER_SIZE);
144        }
145
146        let mut device = Self {
147            ports: Mutex::new(ports),
148            rx_buffer,
149            rx_phys,
150            rx_offset: AtomicUsize::new(0),
151            tx_buffers,
152            tx_phys,
153            tx_id: AtomicUsize::new(TX_BUFFERS_COUNT - 1),
154            mac,
155            name,
156        };
157
158        device.init();
159        Ok(device)
160    }
161
162    /// Performs the init operation.
163    fn init(&mut self) {
164        let mut ports = self.ports.lock();
165
166        ports.write8(0x37, CR_RST);
167        core::hint::spin_loop();
168
169        for _ in 0..1000 {
170            if (ports.read8(0x37) & CR_RST) == 0 {
171                break;
172            }
173            core::hint::spin_loop();
174        }
175
176        ports.write32(
177            0x44,
178            RCR_WRAP | RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_RBLEN,
179        );
180        ports.write32(0x40, TCR_IFG | TCR_MXDMA);
181        ports.write32(0x30, self.rx_phys as u32);
182
183        for i in 0..TX_BUFFERS_COUNT {
184            ports.write32(0x20 + (i as u16) * 4, self.tx_phys[i] as u32);
185        }
186
187        ports.write16(0x3C, ISR_ROK | ISR_TOK);
188        ports.write8(0x37, CR_RE | CR_TE | CR_BUFE);
189
190        log::info!(
191            "RTL8139: MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
192            self.mac[0],
193            self.mac[1],
194            self.mac[2],
195            self.mac[3],
196            self.mac[4],
197            self.mac[5]
198        );
199    }
200
201    /// Performs the receive packet operation.
202    #[allow(dead_code)]
203    fn receive_packet(&self) -> Option<Vec<u8>> {
204        self.receive_inner()
205    }
206
207    /// Performs the transmit packet operation.
208    #[allow(dead_code)]
209    fn transmit_packet(&self, data: &[u8]) -> Result<(), NetError> {
210        self.transmit_inner(data)
211    }
212
213    /// Performs the receive inner operation.
214    fn receive_inner(&self) -> Option<Vec<u8>> {
215        let mut ports = self.ports.lock();
216        let rx_offset = self.rx_offset.load(Ordering::Relaxed);
217
218        let status = unsafe { (self.rx_buffer.add(rx_offset) as *const u32).read_volatile() };
219
220        if (status & OWN) != 0 {
221            return None;
222        }
223
224        if (status & 0x0001) != 0 {
225            let length = ((status >> 16) & 0x1FFF) as usize - 4;
226            if length <= MTU {
227                let packet_start = unsafe { self.rx_buffer.add(rx_offset + 4) };
228                let mut buf = Vec::with_capacity(length);
229                unsafe {
230                    core::ptr::copy_nonoverlapping(packet_start, buf.as_mut_ptr(), length);
231                    buf.set_len(length);
232                }
233
234                let new_offset = ((rx_offset + length + 4 + RX_BUFFER_PAD) & !(RX_BUFFER_PAD - 1))
235                    % RX_BUFFER_SIZE;
236                self.rx_offset.store(new_offset, Ordering::Relaxed);
237                ports.write16(0x38, (new_offset - RX_BUFFER_PAD) as u16);
238
239                return Some(buf);
240            }
241        }
242
243        ports.write8(0x37, CR_RE | CR_TE);
244        self.rx_offset.store(0, Ordering::Relaxed);
245        None
246    }
247
248    /// Performs the transmit inner operation.
249    fn transmit_inner(&self, data: &[u8]) -> Result<(), NetError> {
250        if data.len() > MTU {
251            return Err(NetError::BufferTooSmall);
252        }
253
254        let id = self.tx_id.fetch_add(1, Ordering::SeqCst) % TX_BUFFERS_COUNT;
255        let mut ports = self.ports.lock();
256
257        let tx_status = ports.read32(0x10 + (id as u16) * 4);
258        if (tx_status & OWN) == 0 {
259            let mut timeout = 10000;
260            while (ports.read32(0x10 + (id as u16) * 4) & OWN) == 0 {
261                core::hint::spin_loop();
262                timeout -= 1;
263                if timeout == 0 {
264                    return Err(NetError::NotReady);
265                }
266            }
267        }
268
269        unsafe {
270            core::ptr::copy_nonoverlapping(data.as_ptr(), self.tx_buffers[id], data.len());
271        }
272
273        ports.write32(0x10 + (id as u16) * 4, data.len() as u32);
274
275        Ok(())
276    }
277}
278
279impl NetworkDevice for Rtl8139Device {
280    /// Performs the name operation.
281    fn name(&self) -> &str {
282        &self.name
283    }
284
285    /// Performs the mac address operation.
286    fn mac_address(&self) -> [u8; 6] {
287        self.mac
288    }
289
290    /// Performs the link up operation.
291    fn link_up(&self) -> bool {
292        let ports = self.ports.lock();
293        (ports.read8(0x58) & 0x80) != 0
294    }
295
296    /// Performs the receive operation.
297    fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
298        if let Some(packet) = self.receive_inner() {
299            let len = core::cmp::min(packet.len(), buf.len());
300            buf[..len].copy_from_slice(&packet[..len]);
301            Ok(len)
302        } else {
303            Err(NetError::NoPacket)
304        }
305    }
306
307    /// Performs the transmit operation.
308    fn transmit(&self, data: &[u8]) -> Result<(), NetError> {
309        self.transmit_inner(data)
310    }
311}
312
313static RTL8139_DEVICES: Mutex<Vec<Arc<Rtl8139Device>>> = Mutex::new(Vec::new());
314
315/// Performs the init operation.
316pub fn init() {
317    log::info!("[RTL8139] Scanning for RTL8139 devices...");
318
319    let candidates = pci::probe_all(ProbeCriteria {
320        vendor_id: Some(0x10EC),
321        device_id: None,
322        class_code: Some(pci::class::NETWORK),
323        subclass: Some(pci::net_subclass::ETHERNET),
324        prog_if: None,
325    });
326
327    for pci_dev in candidates.into_iter() {
328        if pci_dev.device_id != 0x8139 {
329            continue;
330        }
331
332        log::info!(
333            "RTL8139: Found device at {:?} (VEN:{:04x} DEV:{:04x})",
334            pci_dev.address,
335            pci_dev.vendor_id,
336            pci_dev.device_id
337        );
338
339        pci_dev.enable_bus_master();
340
341        match unsafe { Rtl8139Device::new(pci_dev) } {
342            Ok(device) => {
343                let arc = Arc::new(device);
344                RTL8139_DEVICES.lock().push(arc.clone());
345                let _iface = crate::hardware::nic::register_device(arc);
346            }
347            Err(e) => {
348                log::warn!("RTL8139: Failed to initialize device: {}", e);
349            }
350        }
351    }
352
353    log::info!("[RTL8139] Found {} device(s)", RTL8139_DEVICES.lock().len());
354}