From 28afc1fefdd1cd90dc117be735c7103b1fa1e56d Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Mon, 20 Jul 2026 18:48:30 +0900 Subject: [PATCH] drivers: complete shared-IRQ re-arm sweep (audio, net, graphics) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continuation of 92924224 — the same conditional-ack bug class found in six more drivers: a foreign interrupt on a shared INTx line skipped the write-back ack, leaving the kernel-masked IRQ line dead forever. - sb16d, ac97d: ack before the not-ours continue - rtl8139d, rtl8168d, ixgbed: ack unconditionally, tick only when ours (the stale 'TODO: spurious interrupts' comments removed — the spurious-interrupt confusion was this bug) - ihdgd: ack unconditionally, handle_events/tick only when ours Verified: cargo check -Z build-std --target x86_64-unknown-redox for sb16d, ac97d, rtl8139d, rtl8168d, ixgbed, ihdgd — clean, no new warnings. nvmed audited: not affected (per-queue MSI pattern, no conditional ack). --- drivers/audio/ac97d/src/main.rs | 11 ++++++++--- drivers/audio/sb16d/src/main.rs | 9 +++++++-- drivers/graphics/ihdgd/src/main.rs | 8 ++++++-- drivers/net/ixgbed/src/main.rs | 8 ++++++-- drivers/net/rtl8139d/src/main.rs | 9 ++++++--- drivers/net/rtl8168d/src/main.rs | 9 ++++++--- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/drivers/audio/ac97d/src/main.rs b/drivers/audio/ac97d/src/main.rs index ccfa03e33e..c006bce282 100644 --- a/drivers/audio/ac97d/src/main.rs +++ b/drivers/audio/ac97d/src/main.rs @@ -149,14 +149,19 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { std::process::exit(1); } - if !device.irq() { - continue; - } + let ours = device.irq(); + // 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(&mut irq) { error!("ac97d: failed to acknowledge IRQ: {err}"); std::process::exit(1); } + if !ours { + continue; + } + readiness_based .poll_all_requests(&mut device) .unwrap_or_else(|err| { diff --git a/drivers/audio/sb16d/src/main.rs b/drivers/audio/sb16d/src/main.rs index 66348596c5..dd11c379a6 100644 --- a/drivers/audio/sb16d/src/main.rs +++ b/drivers/audio/sb16d/src/main.rs @@ -79,10 +79,15 @@ fn daemon(daemon: daemon::Daemon) -> ! { let mut irq = [0; 8]; irq_file.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; ack unconditionally or a foreign interrupt + // on a shared line leaves the line masked forever. + irq_file.write(&mut irq).unwrap(); + + if !ours { continue; } - irq_file.write(&mut irq).unwrap(); readiness_based .poll_all_requests(&mut device) diff --git a/drivers/graphics/ihdgd/src/main.rs b/drivers/graphics/ihdgd/src/main.rs index a8b6cc6038..42fa051c48 100644 --- a/drivers/graphics/ihdgd/src/main.rs +++ b/drivers/graphics/ihdgd/src/main.rs @@ -86,9 +86,13 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { Source::Irq => { let mut irq = [0; 8]; irq_file.irq_handle().read(&mut irq).unwrap(); - if scheme.adapter_mut().handle_irq() { - irq_file.irq_handle().write(&mut irq).unwrap(); + let ours = scheme.adapter_mut().handle_irq(); + // 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. + irq_file.irq_handle().write(&mut irq).unwrap(); + if ours { scheme.adapter_mut().handle_events(); scheme.tick().unwrap(); } diff --git a/drivers/net/ixgbed/src/main.rs b/drivers/net/ixgbed/src/main.rs index 4a6ce74dcd..f16c7f9077 100644 --- a/drivers/net/ixgbed/src/main.rs +++ b/drivers/net/ixgbed/src/main.rs @@ -73,9 +73,13 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); - if scheme.adapter().irq() { - irq_file.write(&mut irq).unwrap(); + let ours = scheme.adapter().irq(); + // 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. + irq_file.write(&mut irq).unwrap(); + if ours { scheme.tick().unwrap(); } } diff --git a/drivers/net/rtl8139d/src/main.rs b/drivers/net/rtl8139d/src/main.rs index d470e814df..c99ae8d8a6 100644 --- a/drivers/net/rtl8139d/src/main.rs +++ b/drivers/net/rtl8139d/src/main.rs @@ -99,10 +99,13 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { Source::Irq => { let mut irq = [0; 8]; irq_file.irq_handle().read(&mut irq).unwrap(); - //TODO: This may be causing spurious interrupts - if unsafe { scheme.adapter_mut().irq() } { - irq_file.irq_handle().write(&mut irq).unwrap(); + let ours = unsafe { scheme.adapter_mut().irq() }; + // 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. + irq_file.irq_handle().write(&mut irq).unwrap(); + if ours { scheme.tick().unwrap(); } } diff --git a/drivers/net/rtl8168d/src/main.rs b/drivers/net/rtl8168d/src/main.rs index 1d9963a3ad..f9a5982339 100644 --- a/drivers/net/rtl8168d/src/main.rs +++ b/drivers/net/rtl8168d/src/main.rs @@ -99,10 +99,13 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { Source::Irq => { let mut irq = [0; 8]; irq_file.irq_handle().read(&mut irq).unwrap(); - //TODO: This may be causing spurious interrupts - if unsafe { scheme.adapter_mut().irq() } { - irq_file.irq_handle().write(&mut irq).unwrap(); + let ours = unsafe { scheme.adapter_mut().irq() }; + // 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. + irq_file.irq_handle().write(&mut irq).unwrap(); + if ours { scheme.tick().unwrap(); } }