Skip to main content

strat9_kernel/hardware/nic/
e1000e_drv.rs

1//! Kernel adapter for the `e1000` crate (e1000e / I217-I219 family).
2//!
3//! Thin shim around the shared `KernelE1000Adapter`; only the device-ID
4//! list, retry count, and driver name differ from the legacy e1000 variant.
5
6use super::{
7    common::{probe_e1000_pci, KernelDma, KernelE1000Adapter},
8    register_device, set_nic_device,
9};
10use crate::{
11    arch::x86_64::{ioapic, msi},
12    hardware::pci_client as pci,
13};
14use e1000::E1000Nic;
15
16const E1000E_IDS: &[u16] = &[
17    pci::intel_eth::E1000E_82574L,
18    pci::intel_eth::I217_LM,
19    pci::intel_eth::I219_LM,
20    pci::intel_eth::I219_V,
21];
22
23pub fn init() {
24    let Some(probe) = probe_e1000_pci(E1000E_IDS) else {
25        return;
26    };
27
28    log::info!(
29        "E1000e: PCI {:04x}:{:04x} at {:?}",
30        probe.pci_dev.vendor_id,
31        probe.pci_dev.device_id,
32        probe.pci_dev.address
33    );
34
35    let mut init_ok = None;
36    for attempt in 0..3 {
37        log::info!(
38            "E1000e: init attempt {} mmio_phys={:#x} mmio_virt={:#x}",
39            attempt + 1,
40            probe.mmio_phys,
41            probe.mmio_virt
42        );
43        if let Ok(nic) = E1000Nic::init(probe.mmio_virt, &KernelDma) {
44            log::info!("E1000e: core init ok on attempt {}", attempt + 1);
45            init_ok = Some(nic);
46            break;
47        }
48        log::warn!("E1000e: core init attempt {} failed", attempt + 1);
49        let mut cmd_retry = probe.pci_dev.read_config_u16(pci::config::COMMAND);
50        cmd_retry |= pci::command::BUS_MASTER | pci::command::MEMORY_SPACE;
51        cmd_retry &= !pci::command::INTERRUPT_DISABLE;
52        probe
53            .pci_dev
54            .write_config_u16(pci::config::COMMAND, cmd_retry);
55        core::hint::spin_loop();
56    }
57
58    match init_ok {
59        Some(nic) => {
60            let mac = nic.mac_address();
61            log::info!(
62                "E1000e: Device initialized: MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
63                mac[0],
64                mac[1],
65                mac[2],
66                mac[3],
67                mac[4],
68                mac[5]
69            );
70            let dev = KernelE1000Adapter::new(nic, "e1000e");
71            let iface = register_device(dev.clone());
72
73            // --- Wire up NIC interrupt: MSI-X → MSI → INTx fallback ---
74            // e1000e supports both MSI and MSI-X; prefer MSI-X for future
75            // multi-queue support.
76            let (irq, vector) = msi::probe_and_enable(&probe.pci_dev, true);
77
78            if irq == 0 || irq == 0xFF {
79                log::warn!(
80                    "[E1000e] {}: no valid IRQ line, running in polling mode",
81                    iface
82                );
83            } else {
84                let cmd = probe.pci_dev.read_config_u16(pci::config::COMMAND);
85                let msi_active = (cmd & pci::command::INTERRUPT_DISABLE) != 0;
86
87                if !msi_active {
88                    ioapic::route_nic_irq(irq, vector);
89                    log::info!(
90                        "[E1000e] {}: INTx IRQ {} → vector {:#x}",
91                        iface,
92                        irq,
93                        vector
94                    );
95                } else {
96                    log::info!(
97                        "[E1000e] {}: MSI/MSI-X active on vector {:#x}",
98                        iface,
99                        vector
100                    );
101                }
102
103                crate::arch::x86_64::idt::register_nic_irq(irq);
104                set_nic_device(dev, irq);
105            }
106        }
107        None => {
108            log::error!("E1000e: init failed");
109        }
110    }
111}