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