diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2018-10-24 17:06:07 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-29 21:18:14 -0700 |
commit | 120d95e03123ede9cc3aa05a8ce976fd4678a890 (patch) | |
tree | 011d7e856f3085de6f024a08674b7ef499cfcf69 /devices/src | |
parent | 510c783c847b6d0c18516f31fbe3dbdc782f1252 (diff) | |
download | crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar.gz crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar.bz2 crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar.lz crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar.xz crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.tar.zst crosvm-120d95e03123ede9cc3aa05a8ce976fd4678a890.zip |
devices: pci: support level-triggered interrupts
Register the irqfd with resample support so that we can correctly emulate level-triggered interrupts. This requires each PciDevice to listen for interrupt_resample events and re-assert the IRQ eventfd if it should still be active. BUG=None TEST=Boot crosvm on x86-64 and arm devices Change-Id: I5cf8d1d1705cf675b453962c00d2d606801fee91 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1298654 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'devices/src')
-rw-r--r-- | devices/src/pci/pci_device.rs | 21 | ||||
-rw-r--r-- | devices/src/virtio/balloon.rs | 13 | ||||
-rw-r--r-- | devices/src/virtio/block.rs | 15 | ||||
-rw-r--r-- | devices/src/virtio/gpu/mod.rs | 13 | ||||
-rw-r--r-- | devices/src/virtio/mmio.rs | 23 | ||||
-rw-r--r-- | devices/src/virtio/net.rs | 16 | ||||
-rw-r--r-- | devices/src/virtio/p9.rs | 16 | ||||
-rw-r--r-- | devices/src/virtio/rng.rs | 15 | ||||
-rw-r--r-- | devices/src/virtio/vhost/net.rs | 3 | ||||
-rw-r--r-- | devices/src/virtio/vhost/vsock.rs | 2 | ||||
-rw-r--r-- | devices/src/virtio/vhost/worker.rs | 15 | ||||
-rw-r--r-- | devices/src/virtio/virtio_device.rs | 1 | ||||
-rw-r--r-- | devices/src/virtio/virtio_pci_common_config.rs | 1 | ||||
-rw-r--r-- | devices/src/virtio/virtio_pci_device.rs | 35 | ||||
-rw-r--r-- | devices/src/virtio/wl.rs | 17 |
15 files changed, 178 insertions, 28 deletions
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs index 395caf1..275d8d3 100644 --- a/devices/src/pci/pci_device.rs +++ b/devices/src/pci/pci_device.rs @@ -29,7 +29,16 @@ pub trait PciDevice: Send { /// after jailing. Must be called before the process is jailed. fn keep_fds(&self) -> Vec<RawFd>; /// Assign a legacy PCI IRQ to this device. - fn assign_irq(&mut self, _irq_evt: EventFd, _irq_num: u32, _irq_pin: PciInterruptPin) {} + /// The device may write to `irq_evt` to trigger an interrupt. + /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary. + fn assign_irq( + &mut self, + _irq_evt: EventFd, + _irq_resample_evt: EventFd, + _irq_num: u32, + _irq_pin: PciInterruptPin, + ) { + } /// Allocates the needed IO BAR space using the `allocate` function which takes a size and /// returns an address. Returns a Vec of (address, length) tuples. fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { @@ -90,8 +99,14 @@ impl<T: PciDevice + ?Sized> PciDevice for Box<T> { fn keep_fds(&self) -> Vec<RawFd> { (**self).keep_fds() } - fn assign_irq(&mut self, irq_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin) { - (**self).assign_irq(irq_evt, irq_num, irq_pin) + fn assign_irq( + &mut self, + irq_evt: EventFd, + irq_resample_evt: EventFd, + irq_num: u32, + irq_pin: PciInterruptPin, + ) { + (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin) } /// Allocates the needed IO BAR space using the `allocate` function which takes a size and /// returns an address. Returns a Vec of (address, length) tuples. diff --git a/devices/src/virtio/balloon.rs b/devices/src/virtio/balloon.rs index 76cbc33..2bd1ba3 100644 --- a/devices/src/virtio/balloon.rs +++ b/devices/src/virtio/balloon.rs @@ -53,6 +53,7 @@ struct Worker { deflate_queue: Queue, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, config: Arc<BalloonConfig>, command_socket: UnixDatagram, } @@ -127,6 +128,7 @@ impl Worker { Inflate, Deflate, CommandSocket, + InterruptResample, Kill, } @@ -139,6 +141,9 @@ impl Worker { .and_then(|pc| { pc.add(&self.command_socket, Token::CommandSocket) .and(Ok(pc)) + }).and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) { Ok(pc) => pc, @@ -188,6 +193,12 @@ impl Worker { } } } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => break 'poll, } } @@ -302,6 +313,7 @@ impl VirtioDevice for Balloon { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, mut queues: Vec<Queue>, queue_evts: Vec<EventFd>, @@ -330,6 +342,7 @@ impl VirtioDevice for Balloon { deflate_queue: queues.remove(0), interrupt_status: status, interrupt_evt, + interrupt_resample_evt, command_socket, config, }; diff --git a/devices/src/virtio/block.rs b/devices/src/virtio/block.rs index 9e0fc7e..c1e7be8 100644 --- a/devices/src/virtio/block.rs +++ b/devices/src/virtio/block.rs @@ -469,6 +469,7 @@ struct Worker<T: DiskFile> { read_only: bool, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, } impl<T: DiskFile> Worker<T> { @@ -535,6 +536,7 @@ impl<T: DiskFile> Worker<T> { enum Token { FlushTimer, QueueAvailable, + InterruptResample, Kill, } @@ -550,7 +552,10 @@ impl<T: DiskFile> Worker<T> { let poll_ctx: PollContext<Token> = match PollContext::new() .and_then(|pc| pc.add(&flush_timer, Token::FlushTimer).and(Ok(pc))) .and_then(|pc| pc.add(&queue_evt, Token::QueueAvailable).and(Ok(pc))) - .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) { Ok(pc) => pc, Err(e) => { @@ -589,6 +594,12 @@ impl<T: DiskFile> Worker<T> { needs_interrupt |= self.process_queue(0, &mut flush_timer, &mut flush_timer_armed); } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => break 'poll, } } @@ -709,6 +720,7 @@ impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, queues: Vec<Queue>, mut queue_evts: Vec<EventFd>, @@ -739,6 +751,7 @@ impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> { read_only, interrupt_status: status, interrupt_evt, + interrupt_resample_evt, }; worker.run(queue_evts.remove(0), kill_evt); }); diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs index ec60634..5ef90c9 100644 --- a/devices/src/virtio/gpu/mod.rs +++ b/devices/src/virtio/gpu/mod.rs @@ -456,6 +456,7 @@ struct Worker { exit_evt: EventFd, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, interrupt_status: Arc<AtomicUsize>, ctrl_queue: Queue, ctrl_evt: EventFd, @@ -478,6 +479,7 @@ impl Worker { CtrlQueue, CursorQueue, Display, + InterruptResample, Kill, } @@ -487,6 +489,9 @@ impl Worker { .and_then(|pc| { pc.add(&*self.state.display().borrow(), Token::Display) .and(Ok(pc)) + }).and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) }).and_then(|pc| pc.add(&self.kill_evt, Token::Kill).and(Ok(pc))) { Ok(pc) => pc, @@ -530,6 +535,12 @@ impl Worker { let _ = self.exit_evt.write(1); } } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => { break 'poll; } @@ -664,6 +675,7 @@ impl VirtioDevice for Gpu { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, interrupt_status: Arc<AtomicUsize>, mut queues: Vec<Queue>, mut queue_evts: Vec<EventFd>, @@ -732,6 +744,7 @@ impl VirtioDevice for Gpu { exit_evt, mem, interrupt_evt, + interrupt_resample_evt, interrupt_status, ctrl_queue, ctrl_evt, diff --git a/devices/src/virtio/mmio.rs b/devices/src/virtio/mmio.rs index 400afd9..bca6de0 100644 --- a/devices/src/virtio/mmio.rs +++ b/devices/src/virtio/mmio.rs @@ -39,6 +39,7 @@ pub struct MmioDevice { queue_select: u32, interrupt_status: Arc<AtomicUsize>, interrupt_evt: Option<EventFd>, + interrupt_resample_evt: Option<EventFd>, driver_status: u32, config_generation: u32, queues: Vec<Queue>, @@ -66,6 +67,7 @@ impl MmioDevice { queue_select: 0, interrupt_status: Arc::new(AtomicUsize::new(0)), interrupt_evt: Some(EventFd::new()?), + interrupt_resample_evt: Some(EventFd::new()?), driver_status: 0, config_generation: 0, queues, @@ -209,15 +211,18 @@ impl BusDevice for MmioDevice { if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() { if let Some(interrupt_evt) = self.interrupt_evt.take() { - if let Some(mem) = self.mem.take() { - self.device.activate( - mem, - interrupt_evt, - self.interrupt_status.clone(), - self.queues.clone(), - self.queue_evts.split_off(0), - ); - self.device_activated = true; + if let Some(interrupt_resample_evt) = self.interrupt_resample_evt.take() { + if let Some(mem) = self.mem.take() { + self.device.activate( + mem, + interrupt_evt, + interrupt_resample_evt, + self.interrupt_status.clone(), + self.queues.clone(), + self.queue_evts.split_off(0), + ); + self.device_activated = true; + } } } } diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs index e5b9650..97feb4c 100644 --- a/devices/src/virtio/net.rs +++ b/devices/src/virtio/net.rs @@ -60,6 +60,7 @@ struct Worker<T: TapT> { tap: T, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, rx_buf: [u8; MAX_BUFFER_SIZE], rx_count: usize, deferred_rx: bool, @@ -234,6 +235,8 @@ where RxQueue, // The transmit queue has a frame that is ready to send from the guest. TxQueue, + // Check if any interrupts need to be re-asserted. + InterruptResample, // crosvm has requested the device to shut down. Kill, } @@ -242,7 +245,10 @@ where .and_then(|pc| pc.add(&self.tap, Token::RxTap).and(Ok(pc))) .and_then(|pc| pc.add(&rx_queue_evt, Token::RxQueue).and(Ok(pc))) .and_then(|pc| pc.add(&tx_queue_evt, Token::TxQueue).and(Ok(pc))) - .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) .map_err(NetError::CreatePollContext)?; 'poll: loop { @@ -278,6 +284,12 @@ where } self.process_tx(); } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => break 'poll, } } @@ -426,6 +438,7 @@ where &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, mut queues: Vec<Queue>, mut queue_evts: Vec<EventFd>, @@ -452,6 +465,7 @@ where tap, interrupt_status: status, interrupt_evt, + interrupt_resample_evt, rx_buf: [0u8; MAX_BUFFER_SIZE], rx_count: 0, deferred_rx: false, diff --git a/devices/src/virtio/p9.rs b/devices/src/virtio/p9.rs index 12e4911..2237b0d 100644 --- a/devices/src/virtio/p9.rs +++ b/devices/src/virtio/p9.rs @@ -222,6 +222,7 @@ struct Worker { server: p9::Server, irq_status: Arc<AtomicUsize>, irq_evt: EventFd, + interrupt_resample_evt: EventFd, } impl Worker { @@ -270,13 +271,18 @@ impl Worker { enum Token { // A request is ready on the queue. QueueReady, + // Check if any interrupts need to be re-asserted. + InterruptResample, // The parent thread requested an exit. Kill, } let poll_ctx: PollContext<Token> = PollContext::new() .and_then(|pc| pc.add(&queue_evt, Token::QueueReady).and(Ok(pc))) - .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) .map_err(P9Error::CreatePollContext)?; loop { @@ -287,6 +293,12 @@ impl Worker { queue_evt.read().map_err(P9Error::ReadQueueEventFd)?; self.process_queue()?; } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.irq_status.load(Ordering::SeqCst) != 0 { + self.irq_evt.write(1).unwrap(); + } + } Token::Kill => return Ok(()), } } @@ -398,6 +410,7 @@ impl VirtioDevice for P9 { &mut self, guest_mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, mut queues: Vec<Queue>, mut queue_evts: Vec<EventFd>, @@ -426,6 +439,7 @@ impl VirtioDevice for P9 { server, irq_status: status, irq_evt: interrupt_evt, + interrupt_resample_evt, }; worker.run(queue_evts.remove(0), kill_evt) diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs index 0c0dd13..2aec07e 100644 --- a/devices/src/virtio/rng.rs +++ b/devices/src/virtio/rng.rs @@ -30,6 +30,7 @@ struct Worker { random_file: File, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, } impl Worker { @@ -76,12 +77,16 @@ impl Worker { #[derive(PollToken)] enum Token { QueueAvailable, + InterruptResample, Kill, } let poll_ctx: PollContext<Token> = match PollContext::new() .and_then(|pc| pc.add(&queue_evt, Token::QueueAvailable).and(Ok(pc))) - .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) { Ok(pc) => pc, Err(e) => { @@ -109,6 +114,12 @@ impl Worker { } needs_interrupt |= self.process_queue(); } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => break 'poll, } } @@ -168,6 +179,7 @@ impl VirtioDevice for Rng { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, mut queues: Vec<Queue>, mut queue_evts: Vec<EventFd>, @@ -198,6 +210,7 @@ impl VirtioDevice for Rng { random_file, interrupt_status: status, interrupt_evt, + interrupt_resample_evt, }; worker.run(queue_evts.remove(0), kill_evt); }); diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs index 1f73863..96c8a27 100644 --- a/devices/src/virtio/vhost/net.rs +++ b/devices/src/virtio/vhost/net.rs @@ -180,6 +180,7 @@ where &mut self, _: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, queues: Vec<Queue>, queue_evts: Vec<EventFd>, @@ -203,6 +204,7 @@ where vhost_interrupt, status, interrupt_evt, + interrupt_resample_evt, acked_features, ); let activate_vqs = |handle: &U| -> Result<()> { @@ -291,6 +293,7 @@ pub mod tests { net.activate( guest_memory, EventFd::new().unwrap(), + EventFd::new().unwrap(), Arc::new(AtomicUsize::new(0)), vec![Queue::new(1)], vec![EventFd::new().unwrap()], diff --git a/devices/src/virtio/vhost/vsock.rs b/devices/src/virtio/vhost/vsock.rs index 694ea25..31dd61e 100644 --- a/devices/src/virtio/vhost/vsock.rs +++ b/devices/src/virtio/vhost/vsock.rs @@ -170,6 +170,7 @@ impl VirtioDevice for Vsock { &mut self, _: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, queues: Vec<Queue>, queue_evts: Vec<EventFd>, @@ -196,6 +197,7 @@ impl VirtioDevice for Vsock { interrupt, status, interrupt_evt, + interrupt_resample_evt, acked_features, ); let activate_vqs = |handle: &VhostVsockHandle| -> Result<()> { diff --git a/devices/src/virtio/vhost/worker.rs b/devices/src/virtio/vhost/worker.rs index 529ebc0..abd063b 100644 --- a/devices/src/virtio/vhost/worker.rs +++ b/devices/src/virtio/vhost/worker.rs @@ -22,6 +22,7 @@ pub struct Worker<T: Vhost> { vhost_interrupt: EventFd, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, acked_features: u64, } @@ -32,6 +33,7 @@ impl<T: Vhost> Worker<T> { vhost_interrupt: EventFd, interrupt_status: Arc<AtomicUsize>, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, acked_features: u64, ) -> Worker<T> { Worker { @@ -40,6 +42,7 @@ impl<T: Vhost> Worker<T> { vhost_interrupt, interrupt_status, interrupt_evt, + interrupt_resample_evt, acked_features, } } @@ -111,12 +114,16 @@ impl<T: Vhost> Worker<T> { #[derive(PollToken)] enum Token { VhostIrq, + InterruptResample, Kill, } let poll_ctx: PollContext<Token> = PollContext::new() .and_then(|pc| pc.add(&self.vhost_interrupt, Token::VhostIrq).and(Ok(pc))) - .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }).and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) .map_err(Error::CreatePollContext)?; 'poll: loop { @@ -129,6 +136,12 @@ impl<T: Vhost> Worker<T> { needs_interrupt = true; self.vhost_interrupt.read().map_err(Error::VhostIrqRead)?; } + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } Token::Kill => break 'poll, } } diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs index 3c6d868..8f790d9 100644 --- a/devices/src/virtio/virtio_device.rs +++ b/devices/src/virtio/virtio_device.rs @@ -56,6 +56,7 @@ pub trait VirtioDevice: Send { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, queues: Vec<Queue>, queue_evts: Vec<EventFd>, diff --git a/devices/src/virtio/virtio_pci_common_config.rs b/devices/src/virtio/virtio_pci_common_config.rs index 2793052..8596563 100644 --- a/devices/src/virtio/virtio_pci_common_config.rs +++ b/devices/src/virtio/virtio_pci_common_config.rs @@ -236,6 +236,7 @@ mod tests { &mut self, _mem: GuestMemory, _interrupt_evt: EventFd, + _interrupt_resample_evt: EventFd, _status: Arc<AtomicUsize>, _queues: Vec<Queue>, _queue_evts: Vec<EventFd>, diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs index 43d2b53..c362477 100644 --- a/devices/src/virtio/virtio_pci_device.rs +++ b/devices/src/virtio/virtio_pci_device.rs @@ -148,6 +148,7 @@ pub struct VirtioPciDevice { interrupt_status: Arc<AtomicUsize>, interrupt_evt: Option<EventFd>, + interrupt_resample_evt: Option<EventFd>, queues: Vec<Queue>, queue_evts: Vec<EventFd>, mem: Option<GuestMemory>, @@ -188,6 +189,7 @@ impl VirtioPciDevice { device_activated: false, interrupt_status: Arc::new(AtomicUsize::new(0)), interrupt_evt: None, + interrupt_resample_evt: None, queues, queue_evts, mem: Some(mem), @@ -279,12 +281,22 @@ impl PciDevice for VirtioPciDevice { if let Some(ref interrupt_evt) = self.interrupt_evt { fds.push(interrupt_evt.as_raw_fd()); } + if let Some(ref interrupt_resample_evt) = self.interrupt_resample_evt { + fds.push(interrupt_resample_evt.as_raw_fd()); + } fds } - fn assign_irq(&mut self, irq_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin) { + fn assign_irq( + &mut self, + irq_evt: EventFd, + irq_resample_evt: EventFd, + irq_num: u32, + irq_pin: PciInterruptPin, + ) { self.config_regs.set_irq(irq_num as u8, irq_pin); self.interrupt_evt = Some(irq_evt); + self.interrupt_resample_evt = Some(irq_resample_evt); } fn allocate_io_bars( @@ -402,15 +414,18 @@ impl PciDevice for VirtioPciDevice { if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() { if let Some(interrupt_evt) = self.interrupt_evt.take() { - if let Some(mem) = self.mem.take() { - self.device.activate( - mem, - interrupt_evt, - self.interrupt_status.clone(), - self.queues.clone(), - self.queue_evts.split_off(0), - ); - self.device_activated = true; + if let Some(interrupt_resample_evt) = self.interrupt_resample_evt.take() { + if let Some(mem) = self.mem.take() { + self.device.activate( + mem, + interrupt_evt, + interrupt_resample_evt, + self.interrupt_status.clone(), + self.queues.clone(), + self.queue_evts.split_off(0), + ); + self.device_activated = true; + } } } } diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs index e1a9025..1933be5 100644 --- a/devices/src/virtio/wl.rs +++ b/devices/src/virtio/wl.rs @@ -1352,6 +1352,7 @@ impl WlState { struct Worker { mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, interrupt_status: Arc<AtomicUsize>, in_queue: Queue, out_queue: Queue, @@ -1363,6 +1364,7 @@ impl Worker { fn new( mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, interrupt_status: Arc<AtomicUsize>, in_queue: Queue, out_queue: Queue, @@ -1373,6 +1375,7 @@ impl Worker { Worker { mem, interrupt_evt, + interrupt_resample_evt, interrupt_status, in_queue, out_queue, @@ -1396,6 +1399,7 @@ impl Worker { OutQueue, Kill, State, + InterruptResample, } let poll_ctx: PollContext<Token> = match PollContext::new() @@ -1403,7 +1407,10 @@ impl Worker { .and_then(|pc| pc.add(&out_queue_evt, Token::OutQueue).and(Ok(pc))) .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc))) .and_then(|pc| pc.add(&self.state.poll_ctx, Token::State).and(Ok(pc))) - { + .and_then(|pc| { + pc.add(&self.interrupt_resample_evt, Token::InterruptResample) + .and(Ok(pc)) + }) { Ok(pc) => pc, Err(e) => { error!("failed creating PollContext: {:?}", e); @@ -1496,6 +1503,12 @@ impl Worker { } Token::Kill => break 'poll, Token::State => self.state.process_poll_context(), + Token::InterruptResample => { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } } } @@ -1602,6 +1615,7 @@ impl VirtioDevice for Wl { &mut self, mem: GuestMemory, interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, status: Arc<AtomicUsize>, mut queues: Vec<Queue>, queue_evts: Vec<EventFd>, @@ -1629,6 +1643,7 @@ impl VirtioDevice for Wl { Worker::new( mem, interrupt_evt, + interrupt_resample_evt, status, queues.remove(0), queues.remove(0), |