diff --git a/kernel/src/arch/riscv32/interrupt.rs b/kernel/src/arch/riscv32/interrupt.rs index bb33d856..e19fdae0 100644 --- a/kernel/src/arch/riscv32/interrupt.rs +++ b/kernel/src/arch/riscv32/interrupt.rs @@ -139,7 +139,7 @@ fn try_process_serial() -> bool { fn try_process_drivers() -> bool { for driver in DRIVERS.read().iter() { - if driver.try_handle_interrupt() == true { + if driver.try_handle_interrupt(None) == true { return true } } diff --git a/kernel/src/arch/x86_64/interrupt/handler.rs b/kernel/src/arch/x86_64/interrupt/handler.rs index 2c908094..434f0c6e 100644 --- a/kernel/src/arch/x86_64/interrupt/handler.rs +++ b/kernel/src/arch/x86_64/interrupt/handler.rs @@ -93,7 +93,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { IDE => ide(), _ => { for driver in DRIVERS.read().iter() { - if driver.try_handle_interrupt() == true { + if driver.try_handle_interrupt(Some(irq.into())) == true { debug!("driver processed interrupt"); return; } diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index b17b9682..eef098a2 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -90,7 +90,7 @@ bitflags! { } impl Driver for VirtIOBlkDriver { - fn try_handle_interrupt(&self) -> bool { + fn try_handle_interrupt(&self, _irq: Option) -> bool { let mut driver = self.0.lock(); // ensure header page is mapped diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 4b616062..b0810d01 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -161,18 +161,21 @@ impl PciTag { // returns a tuple of (vid, did, next) pub fn probe(&self) -> Option<(u32, u32, bool)> { unsafe { + // To lookup vendor and device, please see https://pci-ids.ucw.cz/read/PC/ let v = self.read(PCI_VENDOR, 2); if v == 0xffff { return None; } let d = self.read(PCI_DEVICE, 2); let mf = self.read(PCI_HEADER, 1); + + // To lookup class and subclass, please see https://pci-ids.ucw.cz/read/PD/ let cl = self.read(PCI_CLASS, 1); let scl = self.read(PCI_SUBCLASS, 1); let line = self.read(PCI_INTERRUPT_LINE, 1); let pin = self.read(PCI_INTERRUPT_PIN, 1); info!( - "{}: {}: {}: {:#X} {:#X} ({} {}) at {}:{}", + "{:02x}:{:02x}.{}: {:#x} {:#x} ({} {}) irq {}:{}", self.bus(), self.dev(), self.func(), @@ -188,7 +191,13 @@ impl PciTag { } } - pub unsafe fn enable(&self) { + + /// Enable the pci tag and its interrupt + /// Return assigned MSI interrupt number when applicable + pub unsafe fn enable(&self) -> Option { + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + let orig = self.read(PCI_COMMAND, 2); // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable self.write(PCI_COMMAND, orig | 0x40f); @@ -196,14 +205,17 @@ impl PciTag { // find MSI cap let mut msi_found = false; let mut cap_ptr = self.read(PCI_CAP_PTR, 1); + let mut assigned_irq = None; while cap_ptr > 0 { let cap_id = self.read(cap_ptr, 1); if cap_id == PCI_CAP_ID_MSI { self.write(cap_ptr + PCI_MSI_ADDR, 0xfee00000); - // irq 23 means no 23, should be allocated from a pool - // 23 + 32 = 55 + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq); + // irq number + 32 = MSI data // 0 is (usually) the apic id of the bsp. - self.write(cap_ptr + PCI_MSI_DATA, 55 | 0 << 12); + self.write(cap_ptr + PCI_MSI_DATA, (irq + 32) | 0 << 12); // enable MSI interrupt let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4); @@ -224,6 +236,8 @@ impl PciTag { let pin = self.read(PCI_INTERRUPT_PIN, 1); debug!("MSI not found, using PCI interrupt line {} pin {}", line, pin); } + + assigned_irq } } @@ -249,10 +263,10 @@ pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { } else if did == 0x10fb { // 82599ES 10-Gigabit SFI/SFP+ Network Connection if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { - unsafe { - tag.enable(); - } - ixgbe::ixgbe_init(name, addr, len); + let irq = unsafe { + tag.enable() + }; + ixgbe::ixgbe_init(name, irq, addr, len); } } } diff --git a/kernel/src/drivers/gpu/virtio_gpu.rs b/kernel/src/drivers/gpu/virtio_gpu.rs index f1f283cc..7eb0f19a 100644 --- a/kernel/src/drivers/gpu/virtio_gpu.rs +++ b/kernel/src/drivers/gpu/virtio_gpu.rs @@ -189,7 +189,7 @@ const VIRTIO_GPU_RESOURCE_ID: u32 = 0xbabe; pub struct VirtIOGpuDriver(Mutex); impl Driver for VirtIOGpuDriver { - fn try_handle_interrupt(&self) -> bool { + fn try_handle_interrupt(&self, _irq: Option) -> bool { // for simplicity if cpu::id() > 0 { return false diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index ccfa9eb9..2c47328d 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -27,7 +27,9 @@ pub enum DeviceType { pub trait Driver : Send + Sync { // if interrupt belongs to this driver, handle it and return true // return false otherwise - fn try_handle_interrupt(&self) -> bool; + // irq number is provided when available + // driver should skip handling when irq number is mismatched + fn try_handle_interrupt(&self, irq: Option) -> bool; // return the correspondent device type, see DeviceType fn device_type(&self) -> DeviceType; diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index e4007392..6f68d34d 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -76,7 +76,7 @@ pub struct E1000Interface { } impl Driver for E1000Interface { - fn try_handle_interrupt(&self) -> bool { + fn try_handle_interrupt(&self, _irq: Option) -> bool { let irq = { let driver = self.driver.0.lock(); diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index a844a22d..c6471ba7 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -141,10 +141,16 @@ pub struct IXGBEInterface { driver: IXGBEDriver, sockets: Mutex>, name: String, + irq: Option, } impl Driver for IXGBEInterface { - fn try_handle_interrupt(&self) -> bool { + fn try_handle_interrupt(&self, irq: Option) -> bool { + if irq.is_some() && self.irq.is_some() && irq != self.irq { + // not ours, skip it + return false; + } + let (handled, rx) = { let driver = self.driver.0.lock(); @@ -436,7 +442,7 @@ bitflags! { } } -pub fn ixgbe_init(name: String, header: usize, size: usize) { +pub fn ixgbe_init(name: String, irq: Option, header: usize, size: usize) { assert_eq!(size_of::(), 16); assert_eq!(size_of::(), 16); @@ -786,6 +792,7 @@ pub fn ixgbe_init(name: String, header: usize, size: usize) { sockets: Mutex::new(SocketSet::new(vec![])), driver: net_driver.clone(), name, + irq, }; let driver = Arc::new(ixgbe_iface); diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index a015f04e..91f1cf8c 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -42,7 +42,7 @@ const VIRTIO_QUEUE_RECEIVE: usize = 0; const VIRTIO_QUEUE_TRANSMIT: usize = 1; impl Driver for VirtIONetDriver { - fn try_handle_interrupt(&self) -> bool { + fn try_handle_interrupt(&self, _irq: Option) -> bool { let driver = self.0.lock(); // ensure header page is mapped