فهرست منبع

feat(e1000e): adapt e1000e driver to the new kernel

greatbridf 8 ماه پیش
والد
کامیت
49e32c3462
5فایلهای تغییر یافته به همراه491 افزوده شده و 448 حذف شده
  1. 474 431
      src/driver/e1000e.rs
  2. 1 0
      src/kernel/constants.rs
  3. 9 7
      src/kernel/interrupt.rs
  4. 2 5
      src/kernel/pcie/driver.rs
  5. 5 5
      src/net/netdev.rs

+ 474 - 431
src/driver/e1000e.rs

@@ -1,435 +1,478 @@
-// use crate::prelude::*;
-//
-// use crate::kernel::interrupt::register_irq_handler;
-// use crate::kernel::mem::{paging, phys};
-// use crate::net::netdev;
-// use alloc::boxed::Box;
-// use alloc::vec::Vec;
-// use paging::Page;
-// use phys::{NoCachePP, PhysPtr};
-//
-// mod defs;
-//
-// #[repr(C)]
-// struct RxDescriptor {
-//     buffer: u64,
-//     length: u16,
-//     checksum: u16,
-//     status: u8,
-//     errors: u8,
-//     vlan: u16,
-// }
-//
-// #[repr(C)]
-// struct TxDescriptor {
-//     buffer: u64,
-//     length: u16,
-//     cso: u8, // Checksum offset
-//     cmd: u8,
-//     status: u8,
-//     css: u8, // Checksum start
-//     vlan: u16,
-// }
-//
-// const RX_DESC_SIZE: usize = 32;
-// const TX_DESC_SIZE: usize = 32;
-//
-// struct E1000eDev {
-//     mac: netdev::Mac,
-//     status: netdev::LinkStatus,
-//     speed: netdev::LinkSpeed,
-//     id: u32,
-//
-//     base: NoCachePP,
-//     rt_desc_page: Page,
-//     rx_head: Option<u32>,
-//     rx_tail: Option<u32>,
-//     tx_tail: Option<u32>,
-//
-//     rx_buffers: Option<Box<Vec<Page>>>,
-//     tx_buffers: Option<Box<Vec<Page>>>,
-// }
-//
-// fn test(val: u32, bit: u32) -> bool {
-//     (val & bit) == bit
-// }
-//
-// struct PrintableBytes<'a>(&'a [u8]);
-//
-// impl core::fmt::Debug for PrintableBytes<'_> {
-//     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
-//         write!(f, "PrintableBytes {{")?;
-//         for chunk in self.0.chunks(16) {
-//             for &byte in chunk {
-//                 write!(f, "{byte} ")?;
-//             }
-//             write!(f, "\n")?;
-//         }
-//         write!(f, "}}")?;
-//
-//         Ok(())
-//     }
-// }
-//
-// impl netdev::Netdev for E1000eDev {
-//     fn mac(&self) -> netdev::Mac {
-//         self.mac
-//     }
-//
-//     fn link_status(&self) -> netdev::LinkStatus {
-//         self.status
-//     }
-//
-//     fn link_speed(&self) -> netdev::LinkSpeed {
-//         self.speed
-//     }
-//
-//     fn id(&self) -> u32 {
-//         self.id
-//     }
-//
-//     fn up(&mut self) -> Result<(), u32> {
-//         let ctrl = self.read(defs::REG_CTRL);
-//         let status = self.read(defs::REG_STAT);
-//
-//         // check link up
-//         if !test(ctrl, defs::CTRL_SLU) || !test(status, defs::STAT_LU) {
-//             return Err(EIO);
-//         }
-//
-//         // auto negotiation of speed
-//         match status & defs::STAT_SPEED_MASK {
-//             defs::STAT_SPEED_10M => self.speed = netdev::LinkSpeed::Speed10M,
-//             defs::STAT_SPEED_100M => self.speed = netdev::LinkSpeed::Speed100M,
-//             defs::STAT_SPEED_1000M => self.speed = netdev::LinkSpeed::Speed1000M,
-//             _ => return Err(EINVAL),
-//         }
-//
-//         // clear multicast table
-//         for i in (0..128).step_by(4) {
-//             self.write(defs::REG_MTA + i, 0);
-//         }
-//
-//         self.clear_stats()?;
-//
-//         // setup interrupt handler
-//         let device = netdev::get_netdev(self.id).unwrap();
-//         let handler = move || {
-//             eonix_runtime::task::Task::block_on(device.lock())
-//                 .fire()
-//                 .unwrap();
-//         };
-//
-//         register_irq_handler(0xb, handler)?;
-//
-//         // enable interrupts
-//         self.write(defs::REG_IMS, defs::ICR_NORMAL | defs::ICR_UP);
-//
-//         // read to clear any pending interrupts
-//         self.read(defs::REG_ICR);
-//
-//         self.setup_rx()?;
-//         self.setup_tx()?;
-//
-//         self.status = netdev::LinkStatus::Up;
-//
-//         Ok(())
-//     }
-//
-//     fn fire(&mut self) -> Result<(), u32> {
-//         let cause = self.read(defs::REG_ICR);
-//         if !test(cause, defs::ICR_INT) {
-//             return Ok(());
-//         }
-//
-//         loop {
-//             let tail = self.rx_tail.ok_or(EIO)?;
-//             let next_tail = (tail + 1) % RX_DESC_SIZE as u32;
-//
-//             if next_tail == self.read(defs::REG_RDH) {
-//                 break;
-//             }
-//
-//             let ref mut desc = self.rx_desc_table()[next_tail as usize];
-//             if !test(desc.status as u32, defs::RXD_STAT_DD as u32) {
-//                 Err(EIO)?;
-//             }
-//
-//             desc.status = 0;
-//             let len = desc.length as usize;
-//
-//             let buffers = self.rx_buffers.as_mut().ok_or(EIO)?;
-//             let data = &buffers[next_tail as usize].as_slice()[..len];
-//
-//             println_debug!("e1000e: received {len} bytes, {:?}", PrintableBytes(data));
-//             self.rx_tail = Some(next_tail);
-//         }
-//
-//         Ok(())
-//     }
-//
-//     fn send(&mut self, buf: &[u8]) -> Result<(), u32> {
-//         let tail = self.tx_tail.ok_or(EIO)?;
-//         let head = self.read(defs::REG_TDH);
-//         let next_tail = (tail + 1) % TX_DESC_SIZE as u32;
-//
-//         if next_tail == head {
-//             return Err(EAGAIN);
-//         }
-//
-//         let ref mut desc = self.tx_desc_table()[tail as usize];
-//         if !test(desc.status as u32, defs::TXD_STAT_DD as u32) {
-//             return Err(EIO);
-//         }
-//
-//         let buffer_page = Page::alloc_one();
-//         if buf.len() > buffer_page.len() {
-//             return Err(EFAULT);
-//         }
-//         buffer_page.as_mut_slice()[..buf.len()].copy_from_slice(buf);
-//
-//         desc.buffer = buffer_page.as_phys() as u64;
-//         desc.length = buf.len() as u16;
-//         desc.cmd = defs::TXD_CMD_EOP | defs::TXD_CMD_IFCS | defs::TXD_CMD_RS;
-//         desc.status = 0;
-//
-//         self.tx_tail = Some(next_tail);
-//         self.write(defs::REG_TDT, next_tail);
-//
-//         // TODO: check if the packets are sent and update self.tx_head state
-//
-//         Ok(())
-//     }
-// }
-//
-// impl E1000eDev {
-//     fn setup_rx(&mut self) -> Result<(), u32> {
-//         if !self.rx_head.is_none() || !self.rx_tail.is_none() {
-//             return Err(EINVAL);
-//         }
-//
-//         let addr = self.rt_desc_page.as_phys();
-//
-//         self.write(defs::REG_RDBAL, addr as u32);
-//         self.write(defs::REG_RDBAH, (addr >> 32) as u32);
-//
-//         self.write(
-//             defs::REG_RDLEN,
-//             (RX_DESC_SIZE * size_of::<RxDescriptor>()) as u32,
-//         );
-//
-//         self.write(defs::REG_RDH, 0);
-//         self.write(defs::REG_RDT, RX_DESC_SIZE as u32 - 1);
-//
-//         self.rx_head = Some(0);
-//         self.rx_tail = Some(RX_DESC_SIZE as u32 - 1);
-//
-//         self.write(
-//             defs::REG_RCTL,
-//             defs::RCTL_EN
-//                 | defs::RCTL_MPE
-//                 | defs::RCTL_LPE
-//                 | defs::RCTL_LBM_NO
-//                 | defs::RCTL_DTYP_LEGACY
-//                 | defs::RCTL_BAM
-//                 | defs::RCTL_BSIZE_8192
-//                 | defs::RCTL_SECRC,
-//         );
-//
-//         Ok(())
-//     }
-//
-//     fn setup_tx(&mut self) -> Result<(), u32> {
-//         if !self.tx_tail.is_none() {
-//             return Err(EINVAL);
-//         }
-//
-//         let addr = self.rt_desc_page.as_phys() + 0x200;
-//
-//         self.write(defs::REG_TDBAL, addr as u32);
-//         self.write(defs::REG_TDBAH, (addr >> 32) as u32);
-//
-//         self.write(
-//             defs::REG_TDLEN,
-//             (TX_DESC_SIZE * size_of::<TxDescriptor>()) as u32,
-//         );
-//
-//         self.write(defs::REG_TDH, 0);
-//         self.write(defs::REG_TDT, 0);
-//
-//         self.tx_tail = Some(0);
-//
-//         self.write(
-//             defs::REG_TCTL,
-//             defs::TCTL_EN
-//                 | defs::TCTL_PSP
-//                 | (15 << defs::TCTL_CT_SHIFT)
-//                 | (64 << defs::TCTL_COLD_SHIFT)
-//                 | defs::TCTL_RTLC,
-//         );
-//
-//         Ok(())
-//     }
-//
-//     fn reset(&self) -> Result<(), u32> {
-//         // disable interrupts so we won't mess things up
-//         self.write(defs::REG_IMC, 0xffffffff);
-//
-//         let ctrl = self.read(defs::REG_CTRL);
-//         self.write(defs::REG_CTRL, ctrl | defs::CTRL_GIOD);
-//
-//         while self.read(defs::REG_STAT) & defs::STAT_GIOE != 0 {
-//             // wait for link up
-//         }
-//
-//         let ctrl = self.read(defs::REG_CTRL);
-//         self.write(defs::REG_CTRL, ctrl | defs::CTRL_RST);
-//
-//         while self.read(defs::REG_CTRL) & defs::CTRL_RST != 0 {
-//             // wait for reset
-//         }
-//
-//         // disable interrupts again
-//         self.write(defs::REG_IMC, 0xffffffff);
-//
-//         Ok(())
-//     }
-//
-//     fn clear_stats(&self) -> Result<(), u32> {
-//         self.write(defs::REG_COLC, 0);
-//         self.write(defs::REG_GPRC, 0);
-//         self.write(defs::REG_MPRC, 0);
-//         self.write(defs::REG_GPTC, 0);
-//         self.write(defs::REG_GORCL, 0);
-//         self.write(defs::REG_GORCH, 0);
-//         self.write(defs::REG_GOTCL, 0);
-//         self.write(defs::REG_GOTCH, 0);
-//         Ok(())
-//     }
-//
-//     pub fn new(base: NoCachePP) -> Result<Self, u32> {
-//         let page = Page::alloc_one();
-//
-//         page.zero();
-//
-//         let mut dev = Self {
-//             mac: [0; 6],
-//             status: netdev::LinkStatus::Down,
-//             speed: netdev::LinkSpeed::SpeedUnknown,
-//             id: netdev::alloc_id(),
-//             base,
-//             rt_desc_page: page,
-//             rx_head: None,
-//             rx_tail: None,
-//             tx_tail: None,
-//             rx_buffers: None,
-//             tx_buffers: None,
-//         };
-//
-//         dev.reset()?;
-//
-//         dev.mac = unsafe { dev.base.offset(0x5400).as_ptr::<[u8; 6]>().read() };
-//         dev.tx_buffers = Some(Box::new(Vec::with_capacity(TX_DESC_SIZE)));
-//
-//         let mut rx_buffers = Box::new(Vec::with_capacity(RX_DESC_SIZE));
-//
-//         for index in 0..RX_DESC_SIZE {
-//             let page = Page::alloc_many(2);
-//
-//             let ref mut desc = dev.rx_desc_table()[index];
-//             desc.buffer = page.as_phys() as u64;
-//             desc.status = 0;
-//
-//             rx_buffers.push(page);
-//         }
-//
-//         for index in 0..TX_DESC_SIZE {
-//             let ref mut desc = dev.tx_desc_table()[index];
-//             desc.status = defs::TXD_STAT_DD;
-//         }
-//
-//         dev.rx_buffers = Some(rx_buffers);
-//
-//         Ok(dev)
-//     }
-//
-//     fn read(&self, offset: u32) -> u32 {
-//         unsafe {
-//             self.base
-//                 .offset(offset as isize)
-//                 .as_ptr::<u32>()
-//                 .read_volatile()
-//         }
-//     }
-//
-//     fn write(&self, offset: u32, value: u32) {
-//         unsafe {
-//             self.base
-//                 .offset(offset as isize)
-//                 .as_ptr::<u32>()
-//                 .write_volatile(value)
-//         }
-//     }
-//
-//     fn rx_desc_table<'lt>(&'lt self) -> &'lt mut [RxDescriptor; RX_DESC_SIZE] {
-//         self.rt_desc_page.as_cached().as_mut()
-//     }
-//
-//     fn tx_desc_table<'lt>(&'lt self) -> &'lt mut [TxDescriptor; TX_DESC_SIZE] {
-//         self.rt_desc_page.as_cached().offset(0x200).as_mut()
-//     }
-// }
-//
-// impl Drop for E1000eDev {
-//     fn drop(&mut self) {
-//         assert_eq!(self.status, netdev::LinkStatus::Down);
-//
-//         if let Some(_) = self.rx_buffers.take() {}
-//
-//         // TODO: we should wait until all packets are sent
-//         if let Some(_) = self.tx_buffers.take() {}
-//
-//         let _ = self.rt_desc_page;
-//     }
-// }
-//
-// impl pci::pci_device {
-//     fn header0(&self) -> &pci::device_header_type0 {
-//         unsafe { self.header_type0().as_ref() }.unwrap()
-//     }
-// }
-//
-// fn do_probe_device(dev: &mut pci::pci_device) -> Result<(), u32> {
-//     let bar0 = dev.header0().bars[0];
-//
-//     if bar0 & 0xf != 0 {
-//         return Err(EINVAL);
-//     }
-//
-//     unsafe { dev.enableBusMastering() };
-//
-//     let base = NoCachePP::new((bar0 & !0xf) as usize);
-//     let e1000e = E1000eDev::new(base)?;
-//
-//     netdev::register_netdev(e1000e)?;
-//
-//     Ok(())
-// }
-//
-// unsafe extern "C" fn probe_device(dev: *mut pci::pci_device) -> i32 {
-//     let dev = dev.as_mut().unwrap();
-//     match do_probe_device(dev) {
-//         Ok(_) => 0,
-//         Err(e) => -(e as i32),
-//     }
-// }
+use crate::kernel::constants::{EAGAIN, EFAULT, EINVAL, EIO};
+use crate::kernel::interrupt::register_irq_handler;
+use crate::kernel::mem::paging::{self, AllocZeroed};
+use crate::kernel::mem::{AsMemoryBlock, PhysAccess};
+use crate::kernel::pcie::{self, Header, PCIDevice, PCIDriver, PciError};
+use crate::net::netdev;
+use crate::prelude::*;
+use crate::sync::fence::memory_barrier;
+use alloc::boxed::Box;
+use alloc::sync::Arc;
+use alloc::vec::Vec;
+use core::ptr::NonNull;
+use eonix_mm::address::{Addr, PAddr};
+use eonix_sync::SpinIrq;
+use paging::Page;
 
-pub fn register_e1000e_driver() {
-    // let dev_ids = [0x100e, 0x10d3, 0x10ea, 0x153a];
+mod defs;
+
+#[repr(C)]
+struct RxDescriptor {
+    buffer: u64,
+    length: u16,
+    checksum: u16,
+    status: u8,
+    errors: u8,
+    vlan: u16,
+}
+
+#[repr(C)]
+struct TxDescriptor {
+    buffer: u64,
+    length: u16,
+    cso: u8, // Checksum offset
+    cmd: u8,
+    status: u8,
+    css: u8, // Checksum start
+    vlan: u16,
+}
+
+const RX_DESC_SIZE: usize = 32;
+const TX_DESC_SIZE: usize = 32;
+
+struct Registers(NonNull<()>);
+
+unsafe impl Send for Registers {}
+unsafe impl Sync for Registers {}
+
+struct E1000eDev {
+    irq_no: usize,
+
+    mac: netdev::Mac,
+    status: netdev::LinkStatus,
+    speed: netdev::LinkSpeed,
+    id: u32,
+
+    regs: Registers,
+    rt_desc_page: Page,
+    rx_head: Option<u32>,
+    rx_tail: Option<u32>,
+    tx_tail: Option<u32>,
+
+    rx_buffers: Option<Box<Vec<Page>>>,
+    tx_buffers: Option<Box<Vec<Page>>>,
+}
+
+fn test(val: u32, bit: u32) -> bool {
+    (val & bit) == bit
+}
+
+struct PrintableBytes<'a>(&'a [u8]);
+
+impl core::fmt::Debug for PrintableBytes<'_> {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(f, "PrintableBytes {{")?;
+        for chunk in self.0.chunks(16) {
+            for &byte in chunk {
+                write!(f, "{byte:#2x} ")?;
+            }
+            write!(f, "\n")?;
+        }
+        write!(f, "}}")?;
+
+        Ok(())
+    }
+}
+
+impl Registers {
+    fn new(base: PAddr) -> Self {
+        Self(unsafe { base.as_ptr() })
+    }
+
+    fn read(&self, offset: u32) -> u32 {
+        let retval = unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0.byte_offset(offset as isize).cast().read_volatile()
+        };
+        memory_barrier();
+        retval
+    }
+
+    fn write(&self, offset: u32, value: u32) {
+        unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0
+                .byte_offset(offset as isize)
+                .cast()
+                .write_volatile(value);
+        }
+        memory_barrier();
+    }
+
+    fn read_as<T: Copy>(&self, offset: u32) -> T {
+        let retval = unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0.byte_offset(offset as isize).cast().read_volatile()
+        };
+        memory_barrier();
+        retval
+    }
+}
+
+impl netdev::Netdev for E1000eDev {
+    fn mac(&self) -> netdev::Mac {
+        self.mac
+    }
+
+    fn link_status(&self) -> netdev::LinkStatus {
+        self.status
+    }
+
+    fn link_speed(&self) -> netdev::LinkSpeed {
+        self.speed
+    }
+
+    fn id(&self) -> u32 {
+        self.id
+    }
+
+    fn up(&mut self) -> Result<(), u32> {
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        let status = self.regs.read(defs::REG_STAT);
+
+        // check link up
+        if !test(ctrl, defs::CTRL_SLU) || !test(status, defs::STAT_LU) {
+            return Err(EIO);
+        }
+
+        // auto negotiation of speed
+        match status & defs::STAT_SPEED_MASK {
+            defs::STAT_SPEED_10M => self.speed = netdev::LinkSpeed::Speed10M,
+            defs::STAT_SPEED_100M => self.speed = netdev::LinkSpeed::Speed100M,
+            defs::STAT_SPEED_1000M => self.speed = netdev::LinkSpeed::Speed1000M,
+            _ => return Err(EINVAL),
+        }
+
+        // clear multicast table
+        for i in (0..128).step_by(4) {
+            self.regs.write(defs::REG_MTA + i, 0);
+        }
+
+        self.clear_stats()?;
+
+        // setup interrupt handler
+        let device = netdev::get_netdev(self.id).unwrap();
+        register_irq_handler(self.irq_no as _, move || {
+            device.lock().fire().unwrap();
+        })?;
+
+        // enable interrupts
+        self.regs
+            .write(defs::REG_IMS, defs::ICR_NORMAL | defs::ICR_UP);
+
+        // read to clear any pending interrupts
+        self.regs.read(defs::REG_ICR);
+
+        self.setup_rx()?;
+        self.setup_tx()?;
+
+        self.status = netdev::LinkStatus::Up;
+
+        Ok(())
+    }
+
+    fn fire(&mut self) -> Result<(), u32> {
+        let cause = self.regs.read(defs::REG_ICR);
+        if !test(cause, defs::ICR_INT) {
+            return Ok(());
+        }
+
+        loop {
+            let tail = self.rx_tail.ok_or(EIO)?;
+            let next_tail = (tail + 1) % RX_DESC_SIZE as u32;
+
+            if next_tail == self.regs.read(defs::REG_RDH) {
+                break;
+            }
+
+            let ref mut desc = self.rx_desc_table()[next_tail as usize];
+            if !test(desc.status as u32, defs::RXD_STAT_DD as u32) {
+                Err(EIO)?;
+            }
+
+            desc.status = 0;
+            let len = desc.length as usize;
+
+            let buffers = self.rx_buffers.as_mut().ok_or(EIO)?;
+            let data = unsafe {
+                // SAFETY: No one could be writing to the buffer at this point.
+                &buffers[next_tail as usize].as_memblk().as_bytes()[..len]
+            };
+
+            println_debug!("e1000e: received {len} bytes, {:?}", PrintableBytes(data));
+            self.rx_tail = Some(next_tail);
+        }
+
+        Ok(())
+    }
+
+    fn send(&mut self, buf: &[u8]) -> Result<(), u32> {
+        let tail = self.tx_tail.ok_or(EIO)?;
+        let head = self.regs.read(defs::REG_TDH);
+        let next_tail = (tail + 1) % TX_DESC_SIZE as u32;
+
+        if next_tail == head {
+            return Err(EAGAIN);
+        }
+
+        let ref mut desc = self.tx_desc_table()[tail as usize];
+        if !test(desc.status as u32, defs::TXD_STAT_DD as u32) {
+            return Err(EIO);
+        }
+
+        let buffer_page = Page::alloc();
+        if buf.len() > buffer_page.len() {
+            return Err(EFAULT);
+        }
+
+        unsafe {
+            // SAFETY: We are the only one writing to this memory block.
+            buffer_page.as_memblk().as_bytes_mut()[..buf.len()].copy_from_slice(buf);
+        }
+
+        desc.buffer = PAddr::from(buffer_page.pfn()).addr() as u64;
+        desc.length = buf.len() as u16;
+        desc.cmd = defs::TXD_CMD_EOP | defs::TXD_CMD_IFCS | defs::TXD_CMD_RS;
+        desc.status = 0;
+
+        self.tx_tail = Some(next_tail);
+        self.regs.write(defs::REG_TDT, next_tail);
+
+        // TODO: check if the packets are sent and update self.tx_head state
+
+        Ok(())
+    }
+}
 
-    // for id in dev_ids.into_iter() {
-    //     let ret = unsafe { pci::register_driver_r(0x8086, id, Some(probe_device)) };
+impl E1000eDev {
+    fn setup_rx(&mut self) -> Result<(), u32> {
+        if !self.rx_head.is_none() || !self.rx_tail.is_none() {
+            return Err(EINVAL);
+        }
+
+        let addr = PAddr::from(self.rt_desc_page.pfn()).addr();
+
+        self.regs.write(defs::REG_RDBAL, addr as u32);
+        self.regs.write(defs::REG_RDBAH, (addr >> 32) as u32);
+
+        self.regs.write(
+            defs::REG_RDLEN,
+            (RX_DESC_SIZE * size_of::<RxDescriptor>()) as u32,
+        );
+
+        self.regs.write(defs::REG_RDH, 0);
+        self.regs.write(defs::REG_RDT, RX_DESC_SIZE as u32 - 1);
+
+        self.rx_head = Some(0);
+        self.rx_tail = Some(RX_DESC_SIZE as u32 - 1);
+
+        self.regs.write(
+            defs::REG_RCTL,
+            defs::RCTL_EN
+                | defs::RCTL_MPE
+                | defs::RCTL_LPE
+                | defs::RCTL_LBM_NO
+                | defs::RCTL_DTYP_LEGACY
+                | defs::RCTL_BAM
+                | defs::RCTL_BSIZE_8192
+                | defs::RCTL_SECRC,
+        );
+
+        Ok(())
+    }
+
+    fn setup_tx(&mut self) -> Result<(), u32> {
+        if !self.tx_tail.is_none() {
+            return Err(EINVAL);
+        }
+
+        let addr = PAddr::from(self.rt_desc_page.pfn()).addr() + 0x200;
+
+        self.regs.write(defs::REG_TDBAL, addr as u32);
+        self.regs.write(defs::REG_TDBAH, (addr >> 32) as u32);
+
+        self.regs.write(
+            defs::REG_TDLEN,
+            (TX_DESC_SIZE * size_of::<TxDescriptor>()) as u32,
+        );
+
+        self.regs.write(defs::REG_TDH, 0);
+        self.regs.write(defs::REG_TDT, 0);
+
+        self.tx_tail = Some(0);
+
+        self.regs.write(
+            defs::REG_TCTL,
+            defs::TCTL_EN
+                | defs::TCTL_PSP
+                | (15 << defs::TCTL_CT_SHIFT)
+                | (64 << defs::TCTL_COLD_SHIFT)
+                | defs::TCTL_RTLC,
+        );
+
+        Ok(())
+    }
+
+    fn reset(&self) -> Result<(), u32> {
+        // disable interrupts so we won't mess things up
+        self.regs.write(defs::REG_IMC, 0xffffffff);
+
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_GIOD);
+
+        while self.regs.read(defs::REG_STAT) & defs::STAT_GIOE != 0 {
+            // wait for link up
+        }
+
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_RST);
+
+        while self.regs.read(defs::REG_CTRL) & defs::CTRL_RST != 0 {
+            // wait for reset
+        }
+
+        // disable interrupts again
+        self.regs.write(defs::REG_IMC, 0xffffffff);
+
+        Ok(())
+    }
+
+    fn clear_stats(&self) -> Result<(), u32> {
+        self.regs.write(defs::REG_COLC, 0);
+        self.regs.write(defs::REG_GPRC, 0);
+        self.regs.write(defs::REG_MPRC, 0);
+        self.regs.write(defs::REG_GPTC, 0);
+        self.regs.write(defs::REG_GORCL, 0);
+        self.regs.write(defs::REG_GORCH, 0);
+        self.regs.write(defs::REG_GOTCL, 0);
+        self.regs.write(defs::REG_GOTCH, 0);
+        Ok(())
+    }
+
+    pub fn new(base: PAddr, irq_no: usize) -> Result<Self, u32> {
+        let page = Page::zeroed();
+
+        let mut dev = Self {
+            irq_no,
+            mac: [0; 6],
+            status: netdev::LinkStatus::Down,
+            speed: netdev::LinkSpeed::SpeedUnknown,
+            id: netdev::alloc_id(),
+            regs: Registers::new(base),
+            rt_desc_page: page,
+            rx_head: None,
+            rx_tail: None,
+            tx_tail: None,
+            rx_buffers: None,
+            tx_buffers: None,
+        };
+
+        dev.reset()?;
+
+        dev.mac = dev.regs.read_as(0x5400);
+        dev.tx_buffers = Some(Box::new(Vec::with_capacity(TX_DESC_SIZE)));
+
+        let mut rx_buffers = Box::new(Vec::with_capacity(RX_DESC_SIZE));
+
+        for index in 0..RX_DESC_SIZE {
+            let page = Page::alloc_order(2);
+
+            let ref mut desc = dev.rx_desc_table()[index];
+            desc.buffer = PAddr::from(page.pfn()).addr() as u64;
+            desc.status = 0;
+
+            rx_buffers.push(page);
+        }
+
+        for index in 0..TX_DESC_SIZE {
+            let ref mut desc = dev.tx_desc_table()[index];
+            desc.status = defs::TXD_STAT_DD;
+        }
+
+        dev.rx_buffers = Some(rx_buffers);
+
+        Ok(dev)
+    }
+
+    fn rx_desc_table(&self) -> &mut [RxDescriptor; RX_DESC_SIZE] {
+        unsafe {
+            // SAFETY: TODO
+            self.rt_desc_page.as_memblk().as_ptr().as_mut()
+        }
+    }
+
+    fn tx_desc_table(&self) -> &mut [TxDescriptor; TX_DESC_SIZE] {
+        let (_, right) = self.rt_desc_page.as_memblk().split_at(0x200);
+        unsafe {
+            // SAFETY: TODO
+            right.as_ptr().as_mut()
+        }
+    }
+}
+
+impl Drop for E1000eDev {
+    fn drop(&mut self) {
+        assert_eq!(self.status, netdev::LinkStatus::Down);
+
+        if let Some(_) = self.rx_buffers.take() {}
+
+        // TODO: we should wait until all packets are sent
+        if let Some(_) = self.tx_buffers.take() {}
+
+        let _ = self.rt_desc_page;
+    }
+}
+
+struct Driver {
+    dev_id: u16,
+}
+
+impl PCIDriver for Driver {
+    fn vendor_id(&self) -> u16 {
+        0x8086
+    }
+
+    fn device_id(&self) -> u16 {
+        self.dev_id
+    }
+
+    fn handle_device(&self, device: Arc<PCIDevice<'static>>) -> Result<(), PciError> {
+        let Header::Endpoint(header) = device.header else {
+            Err(EINVAL)?
+        };
+
+        let bar0 = header.bars[0];
+
+        if bar0 & 0xf != 0 {
+            Err(EINVAL)?;
+        }
+
+        device.enable_bus_mastering();
+
+        let base = PAddr::from(bar0 as usize);
+        let e1000e = E1000eDev::new(base, header.interrupt_line as usize)?;
+
+        let dev = netdev::register_netdev(e1000e)?;
+        dev.lock_irq().up()?;
+
+        Ok(())
+    }
+}
+
+pub fn register_e1000e_driver() {
+    let dev_ids = [0x100e, 0x10d3, 0x10ea, 0x153a];
 
-    //     assert_eq!(ret, 0);
-    // }
+    for id in dev_ids.into_iter() {
+        pcie::register_driver(Driver { dev_id: id }).unwrap();
+    }
 }

+ 1 - 0
src/kernel/constants.rs

@@ -25,6 +25,7 @@ pub const ENXIO: u32 = 6;
 pub const ENOEXEC: u32 = 8;
 pub const EBADF: u32 = 9;
 pub const ECHILD: u32 = 10;
+pub const EAGAIN: u32 = 11;
 pub const ENOMEM: u32 = 12;
 pub const EACCES: u32 = 13;
 pub const EFAULT: u32 = 14;

+ 9 - 7
src/kernel/interrupt.rs

@@ -11,15 +11,18 @@ use eonix_mm::address::{Addr as _, VAddr};
 use eonix_runtime::scheduler::Scheduler;
 use eonix_sync::SpinIrq as _;
 
-static IRQ_HANDLERS: Spin<[Option<Arc<dyn Fn() + Send + Sync>>; 16]> =
-    Spin::new([const { None }; 16]);
+static IRQ_HANDLERS: Spin<[Vec<Arc<dyn Fn() + Send + Sync>>; 16]> =
+    Spin::new([const { Vec::new() }; 16]);
 
 pub fn default_irq_handler(irqno: usize) {
     assert!(irqno < 16);
 
-    let handler = IRQ_HANDLERS.lock()[irqno as usize].as_ref().cloned();
-    if let Some(handler) = handler {
-        handler();
+    {
+        let handlers = IRQ_HANDLERS.lock();
+
+        for handler in handlers[irqno].iter() {
+            handler();
+        }
     }
 
     const PIC1_COMMAND: Port8 = Port8::new(0x20);
@@ -75,8 +78,7 @@ where
         return Err(EINVAL);
     }
 
-    let old = IRQ_HANDLERS.lock_irq()[irqno as usize].replace(Arc::new(handler));
-    assert!(old.is_none(), "IRQ handler already registered");
+    IRQ_HANDLERS.lock_irq()[irqno as usize].push(Arc::new(handler));
     Ok(())
 }
 

+ 2 - 5
src/kernel/pcie/driver.rs

@@ -2,10 +2,7 @@ use super::{
     device::{PCIDevice, PCIE_DEVICES},
     error::PciError,
 };
-use crate::{
-    kernel::constants::{EEXIST, ENOENT},
-    KResult,
-};
+use crate::{kernel::constants::EEXIST, KResult};
 use alloc::{
     collections::btree_map::{self, BTreeMap},
     sync::Arc,
@@ -32,7 +29,7 @@ pub fn register_driver(driver: impl PCIDriver + 'static) -> KResult<()> {
     };
 
     let Some(device) = PCIE_DEVICES.lock().find(&index).clone_pointer() else {
-        Err(ENOENT)?
+        return Ok(());
     };
 
     driver.handle_device(device)?;

+ 5 - 5
src/net/netdev.rs

@@ -5,7 +5,7 @@ use alloc::{
     collections::btree_map::{BTreeMap, Entry},
     sync::Arc,
 };
-use eonix_sync::{Mutex, Spin};
+use eonix_sync::Spin;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum LinkStatus {
@@ -57,16 +57,16 @@ impl Ord for dyn Netdev {
 }
 
 static NETDEVS_ID: AtomicU32 = AtomicU32::new(0);
-static NETDEVS: Spin<BTreeMap<u32, Arc<Mutex<dyn Netdev>>>> = Spin::new(BTreeMap::new());
+static NETDEVS: Spin<BTreeMap<u32, Arc<Spin<dyn Netdev>>>> = Spin::new(BTreeMap::new());
 
 pub fn alloc_id() -> u32 {
     NETDEVS_ID.fetch_add(1, Ordering::SeqCst)
 }
 
-pub fn register_netdev(netdev: impl Netdev + 'static) -> Result<Arc<Mutex<dyn Netdev>>, u32> {
+pub fn register_netdev(netdev: impl Netdev + 'static) -> Result<Arc<Spin<dyn Netdev>>, u32> {
     match NETDEVS.lock().entry(netdev.id()) {
         Entry::Vacant(entry) => {
-            let netdev = Arc::new(Mutex::new(netdev));
+            let netdev = Arc::new(Spin::new(netdev));
             entry.insert(netdev.clone());
             Ok(netdev)
         }
@@ -74,6 +74,6 @@ pub fn register_netdev(netdev: impl Netdev + 'static) -> Result<Arc<Mutex<dyn Ne
     }
 }
 
-pub fn get_netdev(id: u32) -> Option<Arc<Mutex<dyn Netdev>>> {
+pub fn get_netdev(id: u32) -> Option<Arc<Spin<dyn Netdev>>> {
     NETDEVS.lock().get(&id).map(|netdev| netdev.clone())
 }