Skip to main content

strat9_kernel/hardware/nic/
pcnet_drv.rs

1// PCnet-PCI II Ethernet Controller Driver (AMD AM79C970/AM79C972)
2// Reference: AMD PCnet-PCI II Data Sheet
3
4use crate::{
5    hardware::{
6        nic::NetworkDevice,
7        pci_client::{self as pci, Bar, ProbeCriteria},
8    },
9    memory::{allocate_zeroed_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 MTU: usize = 1536;
18const RX_BUFFERS_COUNT: usize = 32;
19const TX_BUFFERS_COUNT: usize = 8;
20const DESC_LEN: usize = 16;
21
22const CSR0_INIT: u32 = 0;
23const CSR0_STRT: u32 = 1;
24const CSR0_TDMD: u32 = 3;
25
26const DE_ENP: usize = 0;
27const DE_STP: usize = 1;
28const DE_OWN: usize = 7;
29
30/// Performs the log2 operation.
31fn log2(x: u8) -> u8 {
32    8 - 1 - x.leading_zeros() as u8
33}
34
35pub struct PcnetDevice {
36    ports: Mutex<Ports>,
37    rx_buffers: [*mut u8; RX_BUFFERS_COUNT],
38    rx_phys: [u64; RX_BUFFERS_COUNT],
39    tx_buffers: [*mut u8; TX_BUFFERS_COUNT],
40    tx_phys: [u64; TX_BUFFERS_COUNT],
41    rx_des: *mut u8,
42    rx_des_phys: u64,
43    tx_des: *mut u8,
44    tx_des_phys: u64,
45    rx_id: AtomicUsize,
46    tx_id: AtomicUsize,
47    mac: [u8; 6],
48    name: String,
49}
50
51unsafe impl Send for PcnetDevice {}
52unsafe impl Sync for PcnetDevice {}
53
54struct Ports {
55    io_base: u16,
56}
57
58impl Ports {
59    /// Creates a new instance.
60    fn new(io_base: u16) -> Self {
61        Self { io_base }
62    }
63
64    /// Performs the read8 operation.
65    #[inline]
66    fn read8(&self, offset: u16) -> u8 {
67        unsafe {
68            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
69        }
70    }
71
72    /// Performs the write8 operation.
73    #[inline]
74    #[allow(dead_code)]
75    fn write8(&mut self, offset: u16, value: u8) {
76        unsafe {
77            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
78        }
79    }
80
81    /// Performs the read32 operation.
82    #[inline]
83    fn read32(&self, offset: u16) -> u32 {
84        unsafe {
85            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
86        }
87    }
88
89    /// Performs the write32 operation.
90    #[inline]
91    #[allow(dead_code)]
92    fn write32(&mut self, offset: u16, value: u32) {
93        unsafe {
94            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
95        }
96    }
97
98    /// Writes rap.
99    fn write_rap(&mut self, val: u32) {
100        unsafe {
101            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x14).write(val)
102        }
103    }
104
105    /// Reads rdp.
106    fn read_rdp(&self) -> u32 {
107        unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x10).read() }
108    }
109
110    /// Writes rdp.
111    fn write_rdp(&mut self, val: u32) {
112        unsafe {
113            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x10).write(val)
114        }
115    }
116
117    /// Reads bdp.
118    fn read_bdp(&self) -> u32 {
119        unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x1C).read() }
120    }
121
122    /// Writes bdp.
123    fn write_bdp(&mut self, val: u32) {
124        unsafe {
125            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x1C).write(val)
126        }
127    }
128
129    /// Reads csr.
130    fn read_csr(&mut self, csr: u32) -> u32 {
131        self.write_rap(csr);
132        self.read_rdp()
133    }
134
135    /// Writes csr.
136    fn write_csr(&mut self, csr: u32, val: u32) {
137        self.write_rap(csr);
138        self.write_rdp(val);
139    }
140
141    /// Reads bcr.
142    fn read_bcr(&mut self, bcr: u32) -> u32 {
143        self.write_rap(bcr);
144        self.read_bdp()
145    }
146
147    /// Writes bcr.
148    fn write_bcr(&mut self, bcr: u32, val: u32) {
149        self.write_rap(bcr);
150        self.write_bdp(val);
151    }
152
153    /// Performs the mac operation.
154    fn mac(&mut self) -> [u8; 6] {
155        [
156            self.read8(0x00),
157            self.read8(0x01),
158            self.read8(0x02),
159            self.read8(0x03),
160            self.read8(0x04),
161            self.read8(0x05),
162        ]
163    }
164}
165
166impl PcnetDevice {
167    /// Creates a new instance.
168    pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Self, &'static str> {
169        let io_base = match pci_dev.read_bar(0) {
170            Some(Bar::Io { port }) => port as u16,
171            _ => return Err("Invalid BAR"),
172        };
173
174        let mut ports = Ports::new(io_base);
175        let mac = ports.mac();
176        let name = format!("pcnet_{:02x}{:02x}{:02x}", mac[3], mac[4], mac[5]);
177
178        let mut rx_buffers = [core::ptr::null_mut(); RX_BUFFERS_COUNT];
179        let mut rx_phys = [0u64; RX_BUFFERS_COUNT];
180        for i in 0..RX_BUFFERS_COUNT {
181            let frame = allocate_zeroed_frame().ok_or("Failed to allocate RX buffer")?;
182            rx_phys[i] = frame.start_address.as_u64();
183            rx_buffers[i] = phys_to_virt(rx_phys[i]) as *mut u8;
184        }
185
186        let mut tx_buffers = [core::ptr::null_mut(); TX_BUFFERS_COUNT];
187        let mut tx_phys = [0u64; TX_BUFFERS_COUNT];
188        for i in 0..TX_BUFFERS_COUNT {
189            let frame = allocate_zeroed_frame().ok_or("Failed to allocate TX buffer")?;
190            tx_phys[i] = frame.start_address.as_u64();
191            tx_buffers[i] = phys_to_virt(tx_phys[i]) as *mut u8;
192        }
193
194        let rx_des_frame = allocate_zeroed_frame().ok_or("Failed to allocate RX descriptors")?;
195        let rx_des_phys = rx_des_frame.start_address.as_u64();
196        let rx_des = phys_to_virt(rx_des_phys) as *mut u8;
197        unsafe {
198            core::ptr::write_bytes(rx_des, 0, RX_BUFFERS_COUNT * DESC_LEN);
199        }
200
201        let tx_des_frame = allocate_zeroed_frame().ok_or("Failed to allocate TX descriptors")?;
202        let tx_des_phys = tx_des_frame.start_address.as_u64();
203        let tx_des = phys_to_virt(tx_des_phys) as *mut u8;
204        unsafe {
205            core::ptr::write_bytes(tx_des, 0, TX_BUFFERS_COUNT * DESC_LEN);
206        }
207
208        let mut device = Self {
209            ports: Mutex::new(ports),
210            rx_buffers,
211            rx_phys,
212            tx_buffers,
213            tx_phys,
214            rx_des,
215            rx_des_phys,
216            tx_des,
217            tx_des_phys,
218            rx_id: AtomicUsize::new(0),
219            tx_id: AtomicUsize::new(0),
220            mac,
221            name,
222        };
223
224        device.init();
225        Ok(device)
226    }
227
228    /// Performs the init operation.
229    fn init(&mut self) {
230        let mut ports = self.ports.lock();
231
232        ports.read8(0x18);
233        let _ = ports.read32(0x18);
234
235        let mut csr_58 = ports.read_csr(58);
236        csr_58 &= 0xFF00;
237        csr_58 |= 2;
238        ports.write_csr(58, csr_58);
239
240        let mut bcr_2 = ports.read_bcr(2);
241        bcr_2 |= 2;
242        ports.write_bcr(2, bcr_2);
243
244        for i in 0..RX_BUFFERS_COUNT {
245            self.init_rx_descriptor(i);
246        }
247        for i in 0..TX_BUFFERS_COUNT {
248            self.init_tx_descriptor(i);
249        }
250
251        let init_struct_frame = allocate_zeroed_frame().unwrap();
252        let init_phys = init_struct_frame.start_address.as_u64();
253        let init_virt = phys_to_virt(init_phys) as *mut u8;
254        unsafe {
255            core::ptr::write_bytes(init_virt, 0, 28);
256        }
257
258        unsafe {
259            init_virt.write(0);
260            init_virt.add(1).write(0);
261            init_virt
262                .add(2)
263                .write((log2(RX_BUFFERS_COUNT as u8) as u8) << 4);
264            init_virt
265                .add(3)
266                .write((log2(TX_BUFFERS_COUNT as u8) as u8) << 4);
267
268            init_virt.add(4).write(self.mac[0]);
269            init_virt.add(5).write(self.mac[1]);
270            init_virt.add(6).write(self.mac[2]);
271            init_virt.add(7).write(self.mac[3]);
272            init_virt.add(8).write(self.mac[4]);
273            init_virt.add(9).write(self.mac[5]);
274
275            init_virt.add(20).write((self.rx_des_phys & 0xFF) as u8);
276            init_virt
277                .add(21)
278                .write(((self.rx_des_phys >> 8) & 0xFF) as u8);
279            init_virt
280                .add(22)
281                .write(((self.rx_des_phys >> 16) & 0xFF) as u8);
282            init_virt
283                .add(23)
284                .write(((self.rx_des_phys >> 24) & 0xFF) as u8);
285
286            init_virt.add(24).write((self.tx_des_phys & 0xFFFF) as u8);
287            init_virt
288                .add(25)
289                .write(((self.tx_des_phys >> 8) & 0xFF) as u8);
290            init_virt
291                .add(26)
292                .write(((self.tx_des_phys >> 16) & 0xFF) as u8);
293            init_virt
294                .add(27)
295                .write(((self.tx_des_phys >> 24) & 0xFF) as u8);
296        }
297
298        ports.write_csr(1, (init_phys & 0xFFFF) as u32);
299        ports.write_csr(2, ((init_phys >> 16) & 0xFFFF) as u32);
300
301        let mut csr_0 = ports.read_csr(0);
302        csr_0 |= 1 << CSR0_INIT;
303        ports.write_csr(0, csr_0);
304
305        core::hint::spin_loop();
306
307        let mut csr_0 = ports.read_csr(0);
308        csr_0 |= 1 << CSR0_STRT;
309        ports.write_csr(0, csr_0);
310
311        log::info!(
312            "PCnet: MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
313            self.mac[0],
314            self.mac[1],
315            self.mac[2],
316            self.mac[3],
317            self.mac[4],
318            self.mac[5]
319        );
320    }
321
322    /// Initializes rx descriptor.
323    fn init_rx_descriptor(&self, i: usize) {
324        unsafe {
325            let desc = self.rx_des.add(i * DESC_LEN);
326            desc.write_bytes(0, DESC_LEN);
327
328            let buf_addr = self.rx_phys[i];
329            desc.add(0).write((buf_addr & 0xFF) as u8);
330            desc.add(1).write(((buf_addr >> 8) & 0xFF) as u8);
331            desc.add(2).write(((buf_addr >> 16) & 0xFF) as u8);
332            desc.add(3).write(((buf_addr >> 24) & 0xFF) as u8);
333            let bcnt = (!(MTU as u16)).wrapping_add(1) & 0x0FFF;
334            desc.add(4).write((bcnt & 0xFF) as u8);
335            desc.add(5).write(((bcnt >> 8) as u8) | 0xF0);
336            desc.add(7).write(0x80);
337        }
338    }
339
340    /// Initializes tx descriptor.
341    fn init_tx_descriptor(&self, i: usize) {
342        unsafe {
343            let desc = self.tx_des.add(i * DESC_LEN);
344            desc.write_bytes(0, DESC_LEN);
345
346            let buf_addr = self.tx_phys[i];
347            desc.add(0).write((buf_addr & 0xFF) as u8);
348            desc.add(1).write(((buf_addr >> 8) & 0xFF) as u8);
349            desc.add(2).write(((buf_addr >> 16) & 0xFF) as u8);
350            desc.add(3).write(((buf_addr >> 24) & 0xFF) as u8);
351        }
352    }
353
354    /// Performs the receive inner operation.
355    fn receive_inner(&self) -> Option<Vec<u8>> {
356        let rx_id = self.rx_id.load(Ordering::Relaxed);
357
358        unsafe {
359            let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
360            let status = desc.read_volatile();
361
362            if (status & (1 << DE_OWN)) != 0 {
363                return None;
364            }
365
366            let stp = (status & (1 << DE_STP)) != 0;
367            let enp = (status & (1 << DE_ENP)) != 0;
368
369            if stp && enp {
370                let len_offset = rx_id * DESC_LEN + 8;
371                let len_lo = self.rx_des.add(len_offset).read() as usize;
372                let len_hi = self.rx_des.add(len_offset + 1).read() as usize & 0xF;
373                let len = ((len_hi << 8) | len_lo) & 0xFFF;
374
375                if len <= MTU {
376                    let mut buf = Vec::with_capacity(len);
377                    core::ptr::copy_nonoverlapping(self.rx_buffers[rx_id], buf.as_mut_ptr(), len);
378                    buf.set_len(len);
379
380                    let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
381                    desc.write_volatile(0x80);
382
383                    self.rx_id
384                        .store((rx_id + 1) % RX_BUFFERS_COUNT, Ordering::Relaxed);
385                    return Some(buf);
386                }
387            }
388
389            let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
390            desc.write_volatile(0x80);
391            self.rx_id
392                .store((rx_id + 1) % RX_BUFFERS_COUNT, Ordering::Relaxed);
393        }
394
395        None
396    }
397
398    /// Performs the transmit inner operation.
399    fn transmit_inner(&self, data: &[u8]) -> Result<(), NetError> {
400        if data.len() > MTU {
401            return Err(NetError::BufferTooSmall);
402        }
403
404        let tx_id = self.tx_id.load(Ordering::Relaxed);
405
406        unsafe {
407            let desc = self.tx_des.add(tx_id * DESC_LEN + 7);
408            let status = desc.read_volatile();
409
410            if (status & (1 << DE_OWN)) != 0 {
411                let mut timeout = 10000;
412                while (self.tx_des.add(tx_id * DESC_LEN + 7).read_volatile() & (1 << DE_OWN)) != 0 {
413                    core::hint::spin_loop();
414                    timeout -= 1;
415                    if timeout == 0 {
416                        return Err(NetError::NotReady);
417                    }
418                }
419            }
420
421            core::ptr::copy_nonoverlapping(data.as_ptr(), self.tx_buffers[tx_id], data.len());
422
423            let desc = self.tx_des.add(tx_id * DESC_LEN);
424            let bcnt = (!(data.len() as u16)).wrapping_add(1) & 0x0FFF;
425            desc.add(4).write((bcnt & 0xFF) as u8);
426            desc.add(5).write(((bcnt >> 8) as u8) | 0xF0);
427            desc.add(6).write(0);
428            desc.add(7).write(0x83);
429
430            self.tx_id
431                .store((tx_id + 1) % TX_BUFFERS_COUNT, Ordering::Relaxed);
432
433            let mut ports = self.ports.lock();
434            let mut csr_0 = ports.read_csr(0);
435            csr_0 |= 1 << CSR0_TDMD;
436            ports.write_csr(0, csr_0);
437        }
438
439        Ok(())
440    }
441}
442
443impl NetworkDevice for PcnetDevice {
444    /// Performs the name operation.
445    fn name(&self) -> &str {
446        &self.name
447    }
448
449    /// Performs the mac address operation.
450    fn mac_address(&self) -> [u8; 6] {
451        self.mac
452    }
453
454    /// Performs the link up operation.
455    fn link_up(&self) -> bool {
456        let mut ports = self.ports.lock();
457        let csr_4 = ports.read_csr(4);
458        (csr_4 & 0x20) != 0
459    }
460
461    /// Performs the receive operation.
462    fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
463        if let Some(packet) = self.receive_inner() {
464            let len = core::cmp::min(packet.len(), buf.len());
465            buf[..len].copy_from_slice(&packet[..len]);
466            Ok(len)
467        } else {
468            Err(NetError::NoPacket)
469        }
470    }
471
472    /// Performs the transmit operation.
473    fn transmit(&self, data: &[u8]) -> Result<(), NetError> {
474        self.transmit_inner(data)
475    }
476}
477
478static PCNET_DEVICES: Mutex<Vec<Arc<PcnetDevice>>> = Mutex::new(Vec::new());
479
480/// Performs the init operation.
481pub fn init() {
482    log::info!("[PCnet] Scanning for PCnet devices...");
483
484    let candidates = pci::probe_all(ProbeCriteria {
485        vendor_id: Some(0x1022),
486        device_id: None,
487        class_code: Some(pci::class::NETWORK),
488        subclass: Some(pci::net_subclass::ETHERNET),
489        prog_if: None,
490    });
491
492    for pci_dev in candidates.into_iter() {
493        if pci_dev.device_id != 0x2000 && pci_dev.device_id != 0x2001 {
494            continue;
495        }
496
497        log::info!(
498            "PCnet: Found device at {:?} (VEN:{:04x} DEV:{:04x})",
499            pci_dev.address,
500            pci_dev.vendor_id,
501            pci_dev.device_id
502        );
503
504        pci_dev.enable_bus_master();
505
506        match unsafe { PcnetDevice::new(pci_dev) } {
507            Ok(device) => {
508                let arc = Arc::new(device);
509                PCNET_DEVICES.lock().push(arc.clone());
510                let _iface = crate::hardware::nic::register_device(arc);
511            }
512            Err(e) => {
513                log::warn!("PCnet: Failed to initialize device: {}", e);
514            }
515        }
516    }
517
518    log::info!("[PCnet] Found {} device(s)", PCNET_DEVICES.lock().len());
519}