diff options
author | Zide Chen <zide.chen@intel.corp-partner.google.com> | 2019-10-15 14:32:23 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-25 23:59:45 +0000 |
commit | 8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb (patch) | |
tree | 67764e974ad0e28021f7e7352ab6e1e759e650cc /devices/src/virtio/interrupt.rs | |
parent | 3185ae95dd58f556a836f9e146dfe7b8450749b2 (diff) | |
download | crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar.gz crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar.bz2 crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar.lz crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar.xz crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.tar.zst crosvm-8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb.zip |
devices: implement dedicated Interrupt struct for virtio Worker
The code to inject interrupt to the guest can be generic to all virtio devices. This patch: - move those guest interrupt related fields out of Worker structure and put in a separate file, making the worker code cleaner. - remove redandant functions across virtio devices: signal_used_queue(), signal_config_changed(), etc. BUG=chromium:854765 TEST=sanity test on eve and Linux TEST=cargo test -p devices Change-Id: I8e9f760f2057f192fdc74d16a59fea2e6b08c194 Signed-off-by: Zide Chen <zide.chen@intel.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1869553 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/virtio/interrupt.rs')
-rw-r--r-- | devices/src/virtio/interrupt.rs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/devices/src/virtio/interrupt.rs b/devices/src/virtio/interrupt.rs new file mode 100644 index 0000000..3a3d7e2 --- /dev/null +++ b/devices/src/virtio/interrupt.rs @@ -0,0 +1,83 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use super::{INTERRUPT_STATUS_CONFIG_CHANGED, INTERRUPT_STATUS_USED_RING}; +use crate::pci::MsixConfig; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use sync::Mutex; +use sys_util::EventFd; + +pub struct Interrupt { + interrupt_status: Arc<AtomicUsize>, + interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, + msix_config: Option<Arc<Mutex<MsixConfig>>>, +} + +impl Interrupt { + pub fn new( + interrupt_status: Arc<AtomicUsize>, + interrupt_evt: EventFd, + interrupt_resample_evt: EventFd, + msix_config: Option<Arc<Mutex<MsixConfig>>>, + ) -> Interrupt { + Interrupt { + interrupt_status, + interrupt_evt, + interrupt_resample_evt, + msix_config, + } + } + + /// Virtqueue Interrupts From The Device + /// + /// If MSI-X is enabled in this device, MSI-X interrupt is preferred. + /// Write to the irqfd to VMM to deliver virtual interrupt to the guest + pub fn signal_used_queue(&self, vector: u16) { + // Don't need to set ISR for MSI-X interrupts + if let Some(msix_config) = &self.msix_config { + let mut msix_config = msix_config.lock(); + if msix_config.enabled() { + msix_config.trigger(vector); + return; + } + } + + // Don't need to inject the interrupt if the guest hasn't processed it. + if self + .interrupt_status + .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst) + & INTERRUPT_STATUS_USED_RING as usize + == 0 + { + // Set BIT0 in ISR and write to irqfd to inject INTx interrupt + self.interrupt_status + .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst); + self.interrupt_evt.write(1).unwrap(); + } + } + + /// Notification of Device Configuration Changes + /// Set BIT1 in ISR and write to irqfd + pub fn signal_config_changed(&self) { + self.interrupt_status + .fetch_or(INTERRUPT_STATUS_CONFIG_CHANGED as usize, Ordering::SeqCst); + self.interrupt_evt.write(1).unwrap(); + } + + /// Handle interrupt resampling event + pub fn interrupt_resample(&self) { + let _ = self.interrupt_resample_evt.read(); + if self.interrupt_status.load(Ordering::SeqCst) != 0 { + self.interrupt_evt.write(1).unwrap(); + } + } + + /// Return the reference of interrupt_resample_evt + /// To keep the interface clean, this member is private. + pub fn get_resample_evt(&self) -> &EventFd { + &self.interrupt_resample_evt + } +} |