summary refs log tree commit diff
path: root/devices/src/virtio/interrupt.rs
diff options
context:
space:
mode:
authorZide Chen <zide.chen@intel.corp-partner.google.com>2019-10-15 14:32:23 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-25 23:59:45 +0000
commit8a7e4e902a4950b060ea23b40c0dfce7bfa1b2cb (patch)
tree67764e974ad0e28021f7e7352ab6e1e759e650cc /devices/src/virtio/interrupt.rs
parent3185ae95dd58f556a836f9e146dfe7b8450749b2 (diff)
downloadcrosvm-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.rs83
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
+    }
+}