strat9_kernel/hardware/nic/
e1000e_drv.rs1use super::register_device;
2use crate::{
3 hardware::pci_client::{self as pci, Bar},
4 memory::{self},
5 sync::SpinLock,
6};
7use alloc::sync::Arc;
8use e1000::E1000Nic;
9use net_core::{NetError, NetworkDevice};
10use nic_buffers::{DmaAllocator, DmaRegion};
11use x86_64::VirtAddr;
12
13const E1000E_IDS: &[u16] = &[
14 pci::intel_eth::E1000E_82574L,
15 pci::intel_eth::I217_LM,
16 pci::intel_eth::I219_LM,
17 pci::intel_eth::I219_V,
18];
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_phys_contiguous(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_phys_contiguous(token, frame, order);
48 });
49 }
50}
51
52pub struct KernelE1000e {
53 inner: SpinLock<E1000Nic>,
54 mac: [u8; 6],
55}
56
57impl NetworkDevice for KernelE1000e {
58 fn name(&self) -> &str {
60 "e1000e"
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 fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
72 self.inner.lock().receive(buf)
73 }
74 fn transmit(&self, buf: &[u8]) -> Result<(), NetError> {
76 self.inner.lock().transmit(buf, &KernelDma)
77 }
78 fn handle_interrupt(&self) {
80 self.inner.lock().handle_interrupt();
81 }
82}
83
84fn is_e1000e_id(device_id: u16) -> bool {
86 E1000E_IDS.contains(&device_id)
87}
88
89pub fn init() {
91 if !memory::paging::is_initialized() {
92 log::warn!("E1000e: paging not initialized, deferring probe");
93 return;
94 }
95
96 let candidates = pci::probe_all(pci::ProbeCriteria {
97 vendor_id: Some(pci::vendor::INTEL),
98 device_id: None,
99 class_code: Some(pci::class::NETWORK),
100 subclass: None,
101 prog_if: None,
102 });
103
104 for pci_dev in candidates.into_iter() {
105 if pci_dev.subclass != pci::net_subclass::ETHERNET
106 && pci_dev.subclass != pci::net_subclass::OTHER
107 {
108 continue;
109 }
110 if !is_e1000e_id(pci_dev.device_id) {
111 continue;
112 }
113
114 log::info!(
115 "E1000e: PCI {:04x}:{:04x} at {:?}",
116 pci_dev.vendor_id,
117 pci_dev.device_id,
118 pci_dev.address
119 );
120
121 pci_dev.enable_bus_master();
122 pci_dev.enable_memory_space();
123 let mut cmd = pci_dev.read_config_u16(pci::config::COMMAND);
124 cmd &= !pci::command::INTERRUPT_DISABLE;
125 pci_dev.write_config_u16(pci::config::COMMAND, cmd);
126
127 let mmio_phys = match pci_dev.read_bar(0).or_else(|| pci_dev.read_bar(1)) {
128 Some(Bar::Memory32 { addr, .. }) => addr as u64,
129 Some(Bar::Memory64 { addr, .. }) => addr,
130 _ => {
131 log::error!("E1000e: no MMIO BAR (BAR0/BAR1)");
132 continue;
133 }
134 };
135
136 memory::paging::ensure_identity_map_range(mmio_phys, 0x2_0000);
137 let mmio_virt = memory::phys_to_virt(mmio_phys);
138 let mmio_page_phys = mmio_phys & !0xFFF;
139 let mmio_page_virt = mmio_virt & !0xFFF;
140 let mapped = memory::paging::translate(VirtAddr::new(mmio_page_virt))
141 .map(|p| p.as_u64())
142 .unwrap_or(0);
143 if mapped != mmio_page_phys {
144 log::error!(
145 "E1000e: MMIO map mismatch phys={:#x} virt={:#x} mapped={:#x}",
146 mmio_phys,
147 mmio_virt,
148 mapped
149 );
150 continue;
151 }
152
153 let mut init_ok = None;
154 for attempt in 0..3 {
155 log::info!(
156 "E1000e: init attempt {} mmio_phys={:#x} mmio_virt={:#x}",
157 attempt + 1,
158 mmio_phys,
159 mmio_virt
160 );
161 if let Ok(nic) = E1000Nic::init(mmio_virt, &KernelDma) {
162 log::info!("E1000e: core init ok on attempt {}", attempt + 1);
163 init_ok = Some(nic);
164 break;
165 }
166 log::warn!("E1000e: core init attempt {} failed", attempt + 1);
167 let mut cmd_retry = pci_dev.read_config_u16(pci::config::COMMAND);
168 cmd_retry |= pci::command::BUS_MASTER | pci::command::MEMORY_SPACE;
169 cmd_retry &= !pci::command::INTERRUPT_DISABLE;
170 pci_dev.write_config_u16(pci::config::COMMAND, cmd_retry);
171 core::hint::spin_loop();
172 }
173
174 match init_ok {
175 Some(nic) => {
176 let mac = nic.mac_address();
177 let dev = Arc::new(KernelE1000e {
178 mac,
179 inner: SpinLock::new(nic),
180 });
181 register_device(dev);
182 return;
183 }
184 None => {
185 log::error!("E1000e: init failed");
186 }
187 }
188 }
189}