strat9_kernel/hardware/nic/
e1000e_drv.rs1use 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 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}