diff options
author | Zhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com> | 2019-12-02 15:50:28 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-05 13:12:23 +0000 |
commit | b9f4c9bca30e65eacfb055951fa994ad5127a8f0 (patch) | |
tree | 8c8c886824f819620cf6d5c8b39ee4571ed7fb9b /src/linux.rs | |
parent | 2f7dabbd6a0d8620e4b19b92cdae24c08e4c7ccc (diff) | |
download | crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.gz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.bz2 crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.lz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.xz crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.tar.zst crosvm-b9f4c9bca30e65eacfb055951fa994ad5127a8f0.zip |
crosvm: Add plumbing for split-irqchip interrupts
Devices use irqfd to inject interrupts, we listen to them in the main thread and activate userspace pic/ioapic accordingly. BUG=chromium:908689 TEST=lanuch linux guest with `--split-irqchip` flag Change-Id: If30d17ce7ec9e26dba782c89cc1b9b2ff897a70d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1945798 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Stephen Barber <smbarber@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Zhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com>
Diffstat (limited to 'src/linux.rs')
-rw-r--r-- | src/linux.rs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/linux.rs b/src/linux.rs index a181e52..97f691f 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1699,6 +1699,7 @@ fn run_control( Suspend, ChildSignal, CheckAvailableMemory, + IrqFd { gsi: usize }, LowMemory, LowmemTimer, VmControlServer, @@ -1749,6 +1750,16 @@ fn run_control( .add(&freemem_timer, Token::CheckAvailableMemory) .map_err(Error::PollContextAdd)?; + if let Some(gsi_relay) = &linux.gsi_relay { + for (gsi, evt) in gsi_relay.irqfd.into_iter().enumerate() { + if let Some(evt) = evt { + poll_ctx + .add(evt, Token::IrqFd { gsi }) + .map_err(Error::PollContextAdd)?; + } + } + } + // Used to add jitter to timer values so that we don't have a thundering herd problem when // multiple VMs are running. let mut simple_rng = SimpleRng::new( @@ -1787,6 +1798,7 @@ fn run_control( } vcpu_thread_barrier.wait(); + let mut ioapic_delayed = Vec::<usize>::default(); 'poll: loop { let events = { match poll_ctx.wait() { @@ -1798,6 +1810,26 @@ fn run_control( } }; + ioapic_delayed.retain(|&gsi| { + if let Some((_, ioapic)) = &linux.split_irqchip { + if let Ok(mut ioapic) = ioapic.try_lock() { + // The unwrap will never fail because gsi_relay is Some iff split_irqchip is + // Some. + if linux.gsi_relay.as_ref().unwrap().irqfd_resample[gsi].is_some() { + ioapic.service_irq(gsi, true); + } else { + ioapic.service_irq(gsi, true); + ioapic.service_irq(gsi, false); + } + false + } else { + true + } + } else { + true + } + }); + let mut vm_control_indices_to_remove = Vec::new(); for event in events.iter_readable() { match event.token() { @@ -1861,6 +1893,47 @@ fn run_control( } } } + Token::IrqFd { gsi } => { + if let Some((pic, ioapic)) = &linux.split_irqchip { + // This will never fail because gsi_relay is Some iff split_irqchip is + // Some. + let gsi_relay = linux.gsi_relay.as_ref().unwrap(); + if let Some(eventfd) = &gsi_relay.irqfd[gsi] { + eventfd.read().unwrap(); + } else { + warn!( + "irqfd {} not found in GSI relay, should be impossible.", + gsi + ); + } + + let mut pic = pic.lock(); + if gsi_relay.irqfd_resample[gsi].is_some() { + pic.service_irq(gsi as u8, true); + } else { + pic.service_irq(gsi as u8, true); + pic.service_irq(gsi as u8, false); + } + if let Err(e) = vcpu_handles[0].kill(SIGRTMIN() + 0) { + warn!("PIC: failed to kick vCPU0: {}", e); + } + + // When IOAPIC is configuring its redirection table, we should first + // process its AddMsiRoute request, otherwise we would deadlock. + if let Ok(mut ioapic) = ioapic.try_lock() { + if gsi_relay.irqfd_resample[gsi].is_some() { + ioapic.service_irq(gsi, true); + } else { + ioapic.service_irq(gsi, true); + ioapic.service_irq(gsi, false); + } + } else { + ioapic_delayed.push(gsi); + } + } else { + panic!("split irqchip not found, should be impossible."); + } + } Token::LowMemory => { if let Some(low_mem) = &low_mem { let old_balloon_memory = current_balloon_memory; @@ -2020,6 +2093,7 @@ fn run_control( Token::Suspend => {} Token::ChildSignal => {} Token::CheckAvailableMemory => {} + Token::IrqFd { gsi: _ } => {} Token::LowMemory => {} Token::LowmemTimer => {} Token::VmControlServer => {} |