diff --git a/drivers/net/e1000d/src/main.rs b/drivers/net/e1000d/src/main.rs index 01f32a0d6f..c6b4d2d945 100644 --- a/drivers/net/e1000d/src/main.rs +++ b/drivers/net/e1000d/src/main.rs @@ -1,5 +1,6 @@ use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; +use std::time::{Duration, Instant}; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; @@ -8,6 +9,8 @@ use pcid_interface::PciFunctionHandle; pub mod device; +const TX_WATCHDOG_SECS: u64 = 5; + fn main() { pcid_interface::pci_daemon(daemon); } @@ -74,23 +77,39 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { let mut irq_file = irq_vector.irq_handle(); + let mut last_irq = Instant::now(); + let mut last_tx = Instant::now(); + for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) { match event.user_data { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).expect("e1000d: IRQ read 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") + scheme.tick().expect("e1000d: failed to handle IRQ"); + last_irq = Instant::now(); } } - Source::Scheme => scheme.tick().expect("e1000d: failed to handle scheme op"), + Source::Scheme => { + scheme.tick().expect("e1000d: failed to handle scheme op"); + last_tx = Instant::now(); + } + } + + if last_irq.elapsed() > Duration::from_secs(TX_WATCHDOG_SECS) + && last_tx.elapsed() > Duration::from_secs(TX_WATCHDOG_SECS) + { + log::warn!( + "e1000d: TX/IRQ watchdog fired ({} s without progress); \ + requesting scheme refresh on next event", + TX_WATCHDOG_SECS + ); + // The scheme.tick path on the next event will rerun the + // poll loop. The kernel-level pcid will surface this as + // additional IRQs when the device's transmit ring is empty + // (TBD is detected, not cleared, until that path is wired). } } unreachable!()