diff --git a/drivers/audio/ihdad/src/main.rs b/drivers/audio/ihdad/src/main.rs index 11d80133a0..e4c92d729f 100755 --- a/drivers/audio/ihdad/src/main.rs +++ b/drivers/audio/ihdad/src/main.rs @@ -120,10 +120,16 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { let mut irq = [0; 8]; irq_file.irq_handle().read(&mut irq).unwrap(); - if !device.irq() { + let ours = device.irq(); + // The kernel masks the IRQ line on delivery and only + // re-arms it on write-back; on a shared line a foreign + // interrupt must still be acked or the line stays masked + // forever. + irq_file.irq_handle().write(&mut irq).unwrap(); + + if !ours { continue; } - irq_file.irq_handle().write(&mut irq).unwrap(); readiness_based .poll_all_requests(&mut device) diff --git a/drivers/net/e1000d/src/main.rs b/drivers/net/e1000d/src/main.rs index f62eaad7e9..01f32a0d6f 100644 --- a/drivers/net/e1000d/src/main.rs +++ b/drivers/net/e1000d/src/main.rs @@ -79,9 +79,14 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).expect("e1000d: IRQ read failed"); - if unsafe { scheme.adapter().irq() } { - irq_file.write(&mut irq).expect("e1000d: IRQ ack failed"); - + // Reading ICR clears it, so this is also the device-level + // status clear required before re-arming the line. + let ours = unsafe { scheme.adapter().irq() }; + // The kernel masks the IRQ line on delivery and only re-arms + // it on write-back; on a shared line a foreign interrupt must + // still be acked or the line stays masked forever. + irq_file.write(&mut irq).expect("e1000d: IRQ ack failed"); + if ours { scheme.tick().expect("e1000d: failed to handle IRQ") } } diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs index 2079caa493..c89efd04d8 100644 --- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs +++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs @@ -218,19 +218,31 @@ impl IrqReactor { .read(&mut buffer) .expect("xhcid irq_reactor: failed to read from /scheme/irq"); - if !self.hci.received_irq() { - // continue only when an IRQ to this device was received + let ours = self.hci.received_irq(); + + if ours { + self.mask_interrupts(); + + trace!("IRQ reactor received an IRQ"); + } + + // The kernel masks the IRQ line when it delivers the interrupt and + // only re-arms it on the write-back (acknowledge() -> pic/ioapic + // unmask). On a shared INTx line a foreign device's interrupt + // arrives here with IMAN.IP clear; skipping the ack then leaves + // the line masked forever and every later xHC interrupt is lost. + // Always re-arm, whether or not the interrupt turned out to be + // ours. When it was ours, received_irq() already cleared IMAN.IP + // (RW1C) and interrupts are device-masked above, so this cannot + // re-trigger a storm. + let _ = self.irq_file.as_mut().unwrap_or_else(|| unreachable!( + "xhcid irq_reactor: irq_file went None during IRQ loop; impossible by construction")).write(&buffer); + + if !ours { trace!("no interrupt pending"); continue 'trb_loop; } - self.mask_interrupts(); - - trace!("IRQ reactor received an IRQ"); - - let _ = self.irq_file.as_mut().unwrap_or_else(|| unreachable!( - "xhcid irq_reactor: irq_file went None during IRQ loop; impossible by construction")).write(&buffer); - // TODO: More event rings, probably even with different IRQs. let mut event_ring = hci_clone.primary_event_ring.lock().unwrap_or_else(|e| e.into_inner()); diff --git a/drivers/vboxd/src/main.rs b/drivers/vboxd/src/main.rs index b9e42d4aa8..0fbdf3e76d 100644 --- a/drivers/vboxd/src/main.rs +++ b/drivers/vboxd/src/main.rs @@ -368,11 +368,16 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { let host_events = vmmdev.host_events.read(); if host_events != 0 { port.write(ack_events.physical() as u32); - if let Err(err) = irq_file.write(&irq) { - eprintln!("vboxd: failed to acknowledge IRQ: {err}"); - std::process::exit(1); - } + } + // The kernel masks the IRQ line on delivery and only re-arms + // it on write-back; ack unconditionally or a foreign interrupt + // on a shared line leaves the line masked forever. + if let Err(err) = irq_file.write(&irq) { + eprintln!("vboxd: failed to acknowledge IRQ: {err}"); + std::process::exit(1); + } + if host_events != 0 { if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { port.write(display_change.physical() as u32); if let Some(ref mut display) = display_opt {