strat9_kernel/hardware/nic/
e1000_drv.rs1use super::register_device;
7use crate::{
8 hardware::pci_client::{self as pci, Bar},
9 memory::{self},
10 sync::SpinLock,
11};
12use alloc::sync::Arc;
13use e1000::E1000Nic;
14use net_core::{NetError, NetworkDevice};
15use nic_buffers::{DmaAllocator, DmaRegion};
16use x86_64::VirtAddr;
17
18const LEGACY_E1000_IDS: &[u16] = &[pci::intel_eth::E1000_82540EM, pci::intel_eth::E1000_82545EM];
19
20struct KernelDma;
21
22impl DmaAllocator for KernelDma {
23 fn alloc_dma(&self, size: usize) -> Result<DmaRegion, nic_buffers::DmaAllocError> {
25 let pages = (size + 4095) / 4096;
26 let order = pages.next_power_of_two().trailing_zeros() as u8;
27 let frame = crate::sync::with_irqs_disabled(|token| {
28 crate::memory::allocate_frames(token, order)
29 })
30 .map_err(|_| nic_buffers::DmaAllocError)?;
31 let phys = frame.start_address.as_u64();
32 let virt = memory::phys_to_virt(phys) as *mut u8;
33 Ok(DmaRegion {
34 phys,
35 virt,
36 size: pages * 4096,
37 })
38 }
39
40 unsafe fn free_dma(&self, region: DmaRegion) {
42 let pages = (region.size + 4095) / 4096;
43 let order = pages.next_power_of_two().trailing_zeros() as u8;
44 let frame =
45 crate::memory::PhysFrame::containing_address(x86_64::PhysAddr::new(region.phys));
46 crate::sync::with_irqs_disabled(|token| {
47 crate::memory::free_frames(token, frame, order);
48 });
49 }
50}
51
52pub struct KernelE1000 {
53 inner: SpinLock<E1000Nic>,
54 mac: [u8; 6],
55}
56
57impl NetworkDevice for KernelE1000 {
58 fn name(&self) -> &str {
60 "e1000"
61 }
62 fn mac_address(&self) -> [u8; 6] {
64 self.mac
65 }
66 fn link_up(&self) -> bool {
68 self.inner.lock().link_up()
69 }
70
71 fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
73 self.inner.lock().receive(buf)
74 }
75
76 fn transmit(&self, buf: &[u8]) -> Result<(), NetError> {
78 self.inner.lock().transmit(buf, &KernelDma)
79 }
80
81 fn handle_interrupt(&self) {
83 self.inner.lock().handle_interrupt();
84 }
85}
86
87pub fn init() {
89 if !memory::paging::is_initialized() {
90 log::warn!("E1000: paging not initialized, deferring probe");
91 return;
92 }
93
94 let candidates = pci::probe_all(pci::ProbeCriteria {
95 vendor_id: Some(pci::vendor::INTEL),
96 device_id: None,
97 class_code: Some(pci::class::NETWORK),
98 subclass: None,
99 prog_if: None,
100 });
101 let mut found_intel_nic = false;
102 let mut warned_modern_intel = false;
103 for pci_dev in candidates.into_iter() {
104 if pci_dev.subclass != pci::net_subclass::ETHERNET
106 && pci_dev.subclass != pci::net_subclass::OTHER
107 {
108 continue;
109 }
110 found_intel_nic = true;
111 if !LEGACY_E1000_IDS.contains(&pci_dev.device_id) {
112 if matches!(
113 pci_dev.device_id,
114 pci::intel_eth::I219_LM
115 | pci::intel_eth::I219_V
116 | pci::intel_eth::I225_LM
117 | pci::intel_eth::I225_V
118 | pci::intel_eth::I226_LM
119 | pci::intel_eth::I226_V
120 ) {
121 if !warned_modern_intel {
122 log::warn!(
123 "E1000: modern Intel NIC detected; add e1000e/igc for full laptop support"
124 );
125 warned_modern_intel = true;
126 }
127 }
128 continue;
129 }
130
131 log::info!(
132 "E1000: PCI {:04x}:{:04x} at {:?}",
133 pci_dev.vendor_id,
134 pci_dev.device_id,
135 pci_dev.address
136 );
137 pci_dev.enable_bus_master();
138 pci_dev.enable_memory_space();
139 let mut cmd = pci_dev.read_config_u16(pci::config::COMMAND);
141 cmd &= !pci::command::INTERRUPT_DISABLE;
142 pci_dev.write_config_u16(pci::config::COMMAND, cmd);
143
144 let mmio_phys = match pci_dev.read_bar(0).or_else(|| pci_dev.read_bar(1)) {
145 Some(Bar::Memory32 { addr, .. }) => addr as u64,
146 Some(Bar::Memory64 { addr, .. }) => addr,
147 _ => {
148 log::error!("E1000: no MMIO BAR (BAR0/BAR1)");
149 continue;
150 }
151 };
152
153 memory::paging::ensure_identity_map_range(mmio_phys, 0x2_0000);
154 let mmio_virt = memory::phys_to_virt(mmio_phys);
155 let mmio_page_phys = mmio_phys & !0xFFF;
156 let mmio_page_virt = mmio_virt & !0xFFF;
157 let mapped = memory::paging::translate(VirtAddr::new(mmio_page_virt))
158 .map(|p| p.as_u64())
159 .unwrap_or(0);
160 if mapped != mmio_page_phys {
161 log::error!(
162 "E1000: MMIO not mapped after ensure_identity_map_range phys={:#x} virt={:#x} mapped={:#x}; skipping device",
163 mmio_phys,
164 mmio_virt,
165 mapped
166 );
167 continue;
168 }
169
170 let mut init_ok = None;
172 for attempt in 0..2 {
173 match E1000Nic::init(mmio_virt, &KernelDma) {
174 Ok(nic) => {
175 init_ok = Some(nic);
176 break;
177 }
178 Err(e) => {
179 if attempt == 0 {
180 let mut cmd_retry = pci_dev.read_config_u16(pci::config::COMMAND);
181 cmd_retry |= pci::command::BUS_MASTER | pci::command::MEMORY_SPACE;
182 cmd_retry &= !pci::command::INTERRUPT_DISABLE;
183 pci_dev.write_config_u16(pci::config::COMMAND, cmd_retry);
184 continue;
185 }
186 log::error!("E1000: init failed: {}", e);
187 }
188 }
189 }
190
191 if let Some(nic) = init_ok {
192 let mac = nic.mac_address();
193 let dev = Arc::new(KernelE1000 {
194 mac,
195 inner: SpinLock::new(nic),
196 });
197 register_device(dev);
198 return;
199 }
200 }
201 if found_intel_nic {
202 log::warn!("E1000: Intel NIC(s) found but no supported e1000 device initialized");
203 }
204 log::info!("E1000: no compatible device found");
205}