Skip to main content

strat9_kernel/hardware/nic/
e1000e_drv.rs

1use 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    /// Allocates dma.
24    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    /// Releases dma.
41    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 KernelE1000e {
53    inner: SpinLock<E1000Nic>,
54    mac: [u8; 6],
55}
56
57impl NetworkDevice for KernelE1000e {
58    /// Performs the name operation.
59    fn name(&self) -> &str {
60        "e1000e"
61    }
62    /// Performs the mac address operation.
63    fn mac_address(&self) -> [u8; 6] {
64        self.mac
65    }
66    /// Performs the link up operation.
67    fn link_up(&self) -> bool {
68        self.inner.lock().link_up()
69    }
70    /// Performs the receive operation.
71    fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
72        self.inner.lock().receive(buf)
73    }
74    /// Performs the transmit operation.
75    fn transmit(&self, buf: &[u8]) -> Result<(), NetError> {
76        self.inner.lock().transmit(buf, &KernelDma)
77    }
78    /// Handles interrupt.
79    fn handle_interrupt(&self) {
80        self.inner.lock().handle_interrupt();
81    }
82}
83
84/// Returns whether e1000e id.
85fn is_e1000e_id(device_id: u16) -> bool {
86    E1000E_IDS.contains(&device_id)
87}
88
89/// Performs the init operation.
90pub 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 _ in 0..3 {
155            if let Ok(nic) = E1000Nic::init(mmio_virt, &KernelDma) {
156                init_ok = Some(nic);
157                break;
158            }
159            let mut cmd_retry = pci_dev.read_config_u16(pci::config::COMMAND);
160            cmd_retry |= pci::command::BUS_MASTER | pci::command::MEMORY_SPACE;
161            cmd_retry &= !pci::command::INTERRUPT_DISABLE;
162            pci_dev.write_config_u16(pci::config::COMMAND, cmd_retry);
163            core::hint::spin_loop();
164        }
165
166        match init_ok {
167            Some(nic) => {
168                let mac = nic.mac_address();
169                let dev = Arc::new(KernelE1000e {
170                    mac,
171                    inner: SpinLock::new(nic),
172                });
173                register_device(dev);
174                return;
175            }
176            None => {
177                log::error!("E1000e: init failed");
178            }
179        }
180    }
181}