Skip to main content

strat9_kernel/hardware/nic/
igc_drv.rs

1use super::{
2    common::{probe_e1000_pci, KernelDma},
3    register_device,
4};
5use crate::{hardware::pci_client as pci, sync::SpinLock};
6use alloc::sync::Arc;
7use e1000::E1000Nic;
8use net_core::{NetError, NetworkDevice};
9
10const IGC_IDS: &[u16] = &[
11    pci::intel_eth::I225_LM,
12    pci::intel_eth::I225_V,
13    pci::intel_eth::I226_LM,
14    pci::intel_eth::I226_V,
15];
16
17pub struct KernelIgc {
18    inner: SpinLock<E1000Nic>,
19    mac: [u8; 6],
20}
21
22impl NetworkDevice for KernelIgc {
23    fn name(&self) -> &str {
24        "igc"
25    }
26    fn mac_address(&self) -> [u8; 6] {
27        self.mac
28    }
29    fn link_up(&self) -> bool {
30        self.inner.lock().link_up()
31    }
32    fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
33        self.inner.lock().receive(buf)
34    }
35    fn transmit(&self, buf: &[u8]) -> Result<(), NetError> {
36        self.inner.lock().transmit(buf)
37    }
38    fn handle_interrupt(&self) {
39        self.inner.lock().handle_interrupt();
40    }
41    fn poll(&self) {
42        let mut nic = self.inner.lock();
43        nic.watchdog_tick(&KernelDma);
44    }
45}
46
47pub fn init() {
48    let Some(probe) = probe_e1000_pci(IGC_IDS) else {
49        return;
50    };
51
52    log::info!(
53        "IGC: PCI {:04x}:{:04x} at {:?}",
54        probe.pci_dev.vendor_id,
55        probe.pci_dev.device_id,
56        probe.pci_dev.address
57    );
58
59    let mut init_ok = None;
60    for attempt in 0..3 {
61        log::info!(
62            "IGC: init attempt {} mmio_phys={:#x} mmio_virt={:#x}",
63            attempt + 1,
64            probe.mmio_phys,
65            probe.mmio_virt
66        );
67        if let Ok(nic) = E1000Nic::init(probe.mmio_virt, &KernelDma) {
68            log::info!("IGC: core init ok on attempt {}", attempt + 1);
69            init_ok = Some(nic);
70            break;
71        }
72        log::warn!("IGC: core init attempt {} failed", attempt + 1);
73        let mut cmd_retry = probe.pci_dev.read_config_u16(pci::config::COMMAND);
74        cmd_retry |= pci::command::BUS_MASTER | pci::command::MEMORY_SPACE;
75        cmd_retry &= !pci::command::INTERRUPT_DISABLE;
76        probe
77            .pci_dev
78            .write_config_u16(pci::config::COMMAND, cmd_retry);
79        core::hint::spin_loop();
80    }
81
82    match init_ok {
83        Some(nic) => {
84            let mac = nic.mac_address();
85            let dev = Arc::new(KernelIgc {
86                mac,
87                inner: SpinLock::new(nic),
88            });
89            register_device(dev);
90        }
91        None => {
92            log::warn!("IGC: core init failed (likely requires dedicated igc register path)");
93        }
94    }
95}