diff --git a/devices/src/virtio/interrupt.rs b/devices/src/virtio/interrupt.rs index 2100c45c07..6d80668edf 100644 --- a/devices/src/virtio/interrupt.rs +++ b/devices/src/virtio/interrupt.rs @@ -50,6 +50,7 @@ enum Transport { struct InterruptInner { interrupt_status: AtomicUsize, transport: Transport, + async_intr_status: bool, } #[derive(Clone)] @@ -78,12 +79,15 @@ impl SignalableInterrupt for Interrupt { // Set bit in ISR and inject the interrupt if it was not already pending. // Don't need to inject the interrupt if the guest hasn't processed it. + // In hypervisors where interrupt_status is updated asynchronously, inject the + // interrupt even if the previous interrupt appears to be already pending. if self .inner .as_ref() .interrupt_status .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst) == 0 + || self.inner.as_ref().async_intr_status { // Write to irqfd to inject PCI INTx or MMIO interrupt match &self.inner.as_ref().transport { @@ -127,6 +131,7 @@ impl Interrupt { Interrupt { inner: Arc::new(InterruptInner { interrupt_status: AtomicUsize::new(0), + async_intr_status: false, transport: Transport::Pci { pci: TransportPci { irq_evt_lvl, @@ -138,11 +143,12 @@ impl Interrupt { } } - pub fn new_mmio(irq_evt_edge: IrqEdgeEvent) -> Interrupt { + pub fn new_mmio(irq_evt_edge: IrqEdgeEvent, async_intr_status: bool) -> Interrupt { Interrupt { inner: Arc::new(InterruptInner { interrupt_status: AtomicUsize::new(0), transport: Transport::Mmio { irq_evt_edge }, + async_intr_status, }), } } diff --git a/devices/src/virtio/virtio_mmio_device.rs b/devices/src/virtio/virtio_mmio_device.rs index f18d9f4b14..02a7d7f3b4 100644 --- a/devices/src/virtio/virtio_mmio_device.rs +++ b/devices/src/virtio/virtio_mmio_device.rs @@ -54,6 +54,7 @@ pub struct VirtioMmioDevice { interrupt: Option, interrupt_evt: Option, + async_intr_status: bool, queues: Vec, queue_evts: Vec, mem: GuestMemory, @@ -70,7 +71,11 @@ pub struct VirtioMmioDevice { impl VirtioMmioDevice { /// Constructs a new MMIO transport for the given virtio device. - pub fn new(mem: GuestMemory, device: Box) -> Result { + pub fn new( + mem: GuestMemory, + device: Box, + async_intr_status: bool, + ) -> Result { let mut queue_evts = Vec::new(); for _ in device.queue_max_sizes() { queue_evts.push(Event::new()?) @@ -86,6 +91,7 @@ impl VirtioMmioDevice { device_activated: false, interrupt: None, interrupt_evt: None, + async_intr_status, queues, queue_evts, mem, @@ -152,7 +158,7 @@ impl VirtioMmioDevice { }; let mem = self.mem.clone(); - let interrupt = Interrupt::new_mmio(interrupt_evt); + let interrupt = Interrupt::new_mmio(interrupt_evt, self.async_intr_status); self.interrupt = Some(interrupt.clone()); match self.clone_queue_evts() { diff --git a/src/crosvm/sys/unix.rs b/src/crosvm/sys/unix.rs index 6520ab6f37..fa40ac3096 100644 --- a/src/crosvm/sys/unix.rs +++ b/src/crosvm/sys/unix.rs @@ -905,7 +905,7 @@ fn create_devices( devices.push((Box::new(dev) as Box, stub.jail)); } VirtioTransportType::Mmio => { - let dev = VirtioMmioDevice::new(vm.get_memory().clone(), stub.dev) + let dev = VirtioMmioDevice::new(vm.get_memory().clone(), stub.dev, false) .context("failed to create virtio mmio dev")?; devices.push((Box::new(dev) as Box, stub.jail)); }