strat9_kernel/hardware/nic/
common.rs1use crate::{
8 hardware::pci_client::{self as pci, Bar, PciDevice},
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
18pub struct KernelDma;
20
21impl DmaAllocator for KernelDma {
22 fn alloc_dma(&self, size: usize) -> Result<DmaRegion, nic_buffers::DmaAllocError> {
24 let pages = (size + 4095) / 4096;
25 let order = pages.next_power_of_two().trailing_zeros() as u8;
26 let frame = crate::sync::with_irqs_disabled(|token| {
27 crate::memory::allocate_phys_contiguous(token, order)
28 })
29 .map_err(|_| nic_buffers::DmaAllocError)?;
30 let phys = frame.start_address.as_u64();
31 let virt = memory::phys_to_virt(phys) as *mut u8;
32 Ok(DmaRegion {
33 phys,
34 virt,
35 size: pages * 4096,
36 })
37 }
38
39 unsafe fn free_dma(&self, region: DmaRegion) {
46 let pages = (region.size + 4095) / 4096;
47 let order = pages.next_power_of_two().trailing_zeros() as u8;
48 let frame =
49 crate::memory::PhysFrame::containing_address(x86_64::PhysAddr::new(region.phys));
50 crate::sync::with_irqs_disabled(|token| {
51 crate::memory::free_phys_contiguous(token, frame, order);
52 });
53 }
54}
55
56pub struct ProbeResult {
58 pub pci_dev: PciDevice,
60 pub mmio_virt: u64,
62 pub mmio_phys: u64,
64}
65
66pub fn probe_e1000_pci(device_ids: &[u16]) -> Option<ProbeResult> {
75 if !memory::paging::is_initialized() {
76 log::warn!("e1000-family: paging not initialized, deferring probe");
77 return None;
78 }
79
80 let candidates = pci::probe_all(pci::ProbeCriteria {
81 vendor_id: Some(pci::vendor::INTEL),
82 device_id: None,
83 class_code: Some(pci::class::NETWORK),
84 subclass: None,
85 prog_if: None,
86 });
87
88 for pci_dev in candidates.into_iter() {
89 if pci_dev.subclass != pci::net_subclass::ETHERNET
90 && pci_dev.subclass != pci::net_subclass::OTHER
91 {
92 continue;
93 }
94 if !device_ids.contains(&pci_dev.device_id) {
95 continue;
96 }
97
98 log::info!(
99 "e1000-family: PCI {:04x}:{:04x} at {:?}",
100 pci_dev.vendor_id,
101 pci_dev.device_id,
102 pci_dev.address
103 );
104
105 pci_dev.enable_bus_master();
106 pci_dev.enable_memory_space();
107 let mut cmd = pci_dev.read_config_u16(pci::config::COMMAND);
108 cmd &= !pci::command::INTERRUPT_DISABLE;
109 pci_dev.write_config_u16(pci::config::COMMAND, cmd);
110
111 let mmio_phys = match pci_dev.read_bar(0).or_else(|| pci_dev.read_bar(1)) {
112 Some(Bar::Memory32 { addr, .. }) => addr as u64,
113 Some(Bar::Memory64 { addr, .. }) => addr,
114 _ => {
115 log::error!(
116 "e1000-family: no MMIO BAR (BAR0/BAR1) for {:04x}:{:04x}",
117 pci_dev.vendor_id,
118 pci_dev.device_id
119 );
120 continue;
121 }
122 };
123
124 memory::paging::ensure_identity_map_range(mmio_phys, 0x2_0000);
125 let mmio_virt = memory::phys_to_virt(mmio_phys);
126 let mmio_page_phys = mmio_phys & !0xFFF;
127 let mmio_page_virt = mmio_virt & !0xFFF;
128 let mapped = memory::paging::translate(VirtAddr::new(mmio_page_virt))
129 .map(|p| p.as_u64())
130 .unwrap_or(0);
131 if mapped != mmio_page_phys {
132 log::error!(
133 "e1000-family: MMIO not mapped for {:04x}:{:04x} phys={:#x} virt={:#x} mapped={:#x}",
134 pci_dev.vendor_id,
135 pci_dev.device_id,
136 mmio_phys,
137 mmio_virt,
138 mapped
139 );
140 continue;
141 }
142
143 return Some(ProbeResult {
144 pci_dev,
145 mmio_virt,
146 mmio_phys,
147 });
148 }
149
150 None
151}
152
153pub struct KernelE1000Adapter {
163 inner: SpinLock<E1000Nic>,
164 mac: [u8; 6],
165 name: &'static str,
166}
167
168impl KernelE1000Adapter {
169 pub fn new(nic: E1000Nic, driver_name: &'static str) -> Arc<Self> {
171 let mac = nic.mac_address();
172 Arc::new(Self {
173 inner: SpinLock::new(nic),
174 mac,
175 name: driver_name,
176 })
177 }
178}
179
180impl NetworkDevice for KernelE1000Adapter {
181 fn name(&self) -> &str {
182 self.name
183 }
184
185 fn mac_address(&self) -> [u8; 6] {
186 self.mac
187 }
188
189 fn link_up(&self) -> bool {
190 self.inner.lock().link_up()
191 }
192
193 fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
194 self.inner.lock().receive(buf)
195 }
196
197 fn transmit(&self, buf: &[u8]) -> Result<(), NetError> {
198 self.inner.lock().transmit(buf)
199 }
200
201 fn handle_interrupt(&self) {
202 let _icr = self.inner.lock().handle_interrupt();
203 }
204
205 fn poll(&self) {
206 let mut nic = self.inner.lock();
207 nic.watchdog_tick(&KernelDma);
208 }
209}