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