Skip to content

Commit 3328bfa

Browse files
committed
virtio: add generic interrupt trait
Describing the APIs that need to implement types that are used as interrupts for VirtIO devices. Currently, we only use `IrqInterrupt` interrupts, but this will change once we have MSI-X with PCIe devices. Signed-off-by: Babis Chalios <[email protected]>
1 parent 97c9e03 commit 3328bfa

File tree

2 files changed

+107
-27
lines changed

2 files changed

+107
-27
lines changed

src/vmm/src/devices/virtio/transport/mmio.rs

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex, MutexGuard};
1111

1212
use vmm_sys_util::eventfd::EventFd;
1313

14+
use super::{VirtioInterrupt, VirtioInterruptType};
1415
use crate::devices::virtio::device::VirtioDevice;
1516
use crate::devices::virtio::device_status;
1617
use crate::devices::virtio::queue::Queue;
@@ -375,13 +376,56 @@ pub enum IrqType {
375376
Vring,
376377
}
377378

379+
impl From<VirtioInterruptType> for IrqType {
380+
fn from(interrupt_type: VirtioInterruptType) -> Self {
381+
match interrupt_type {
382+
VirtioInterruptType::Config => IrqType::Config,
383+
VirtioInterruptType::Queue(_) => IrqType::Vring,
384+
}
385+
}
386+
}
387+
378388
/// Helper struct that is responsible for triggering guest IRQs
379389
#[derive(Debug)]
380390
pub struct IrqTrigger {
381391
pub(crate) irq_status: Arc<AtomicU32>,
382392
pub(crate) irq_evt: EventFd,
383393
}
384394

395+
impl VirtioInterrupt for IrqTrigger {
396+
fn trigger(&self, interrupt_type: VirtioInterruptType) -> Result<(), std::io::Error> {
397+
match interrupt_type {
398+
VirtioInterruptType::Config => self.trigger_irq(IrqType::Config),
399+
VirtioInterruptType::Queue(_) => self.trigger_irq(IrqType::Vring),
400+
}
401+
}
402+
403+
fn notifier(&self, _interrupt_type: VirtioInterruptType) -> Option<&EventFd> {
404+
Some(&self.irq_evt)
405+
}
406+
407+
fn status(&self) -> Arc<AtomicU32> {
408+
self.irq_status.clone()
409+
}
410+
411+
#[cfg(test)]
412+
fn has_pending_interrupt(&self, interrupt_type: VirtioInterruptType) -> bool {
413+
if let Ok(num_irqs) = self.irq_evt.read() {
414+
if num_irqs == 0 {
415+
return false;
416+
}
417+
418+
let irq_status = self.irq_status.load(Ordering::SeqCst);
419+
return matches!(
420+
(irq_status, interrupt_type.into()),
421+
(VIRTIO_MMIO_INT_CONFIG, IrqType::Config) | (VIRTIO_MMIO_INT_VRING, IrqType::Vring)
422+
);
423+
}
424+
425+
false
426+
}
427+
}
428+
385429
impl IrqTrigger {
386430
pub fn new() -> std::io::Result<Self> {
387431
Ok(Self {
@@ -993,6 +1037,25 @@ pub(crate) mod tests {
9931037
assert!(d.locked_device().is_activated());
9941038
}
9951039

1040+
impl IrqTrigger {
1041+
pub fn has_pending_irq(&self, irq_type: IrqType) -> bool {
1042+
if let Ok(num_irqs) = self.irq_evt.read() {
1043+
if num_irqs == 0 {
1044+
return false;
1045+
}
1046+
1047+
let irq_status = self.irq_status.load(Ordering::SeqCst);
1048+
return matches!(
1049+
(irq_status, irq_type),
1050+
(VIRTIO_MMIO_INT_CONFIG, IrqType::Config)
1051+
| (VIRTIO_MMIO_INT_VRING, IrqType::Vring)
1052+
);
1053+
}
1054+
1055+
false
1056+
}
1057+
}
1058+
9961059
#[test]
9971060
fn test_bus_device_reset() {
9981061
let m = single_region_mem(0x1000);
@@ -1053,44 +1116,29 @@ pub(crate) mod tests {
10531116
assert_eq!(dummy_dev.acked_features(), 24);
10541117
}
10551118

1056-
impl IrqTrigger {
1057-
pub fn has_pending_irq(&self, irq_type: IrqType) -> bool {
1058-
if let Ok(num_irqs) = self.irq_evt.read() {
1059-
if num_irqs == 0 {
1060-
return false;
1061-
}
1062-
1063-
let irq_status = self.irq_status.load(Ordering::SeqCst);
1064-
return matches!(
1065-
(irq_status, irq_type),
1066-
(VIRTIO_MMIO_INT_CONFIG, IrqType::Config)
1067-
| (VIRTIO_MMIO_INT_VRING, IrqType::Vring)
1068-
);
1069-
}
1070-
1071-
false
1072-
}
1073-
}
1074-
10751119
#[test]
10761120
fn irq_trigger() {
10771121
let irq_trigger = IrqTrigger::new().unwrap();
10781122
assert_eq!(irq_trigger.irq_status.load(Ordering::SeqCst), 0);
10791123

10801124
// Check that there are no pending irqs.
1081-
assert!(!irq_trigger.has_pending_irq(IrqType::Config));
1082-
assert!(!irq_trigger.has_pending_irq(IrqType::Vring));
1125+
assert!(!irq_trigger.has_pending_interrupt(VirtioInterruptType::Config));
1126+
assert!(!irq_trigger.has_pending_interrupt(VirtioInterruptType::Queue(0)));
10831127

10841128
// Check that trigger_irq() correctly generates irqs.
1085-
irq_trigger.trigger_irq(IrqType::Config).unwrap();
1086-
assert!(irq_trigger.has_pending_irq(IrqType::Config));
1129+
irq_trigger.trigger(VirtioInterruptType::Config).unwrap();
1130+
assert!(irq_trigger.has_pending_interrupt(VirtioInterruptType::Config));
10871131
irq_trigger.irq_status.store(0, Ordering::SeqCst);
1088-
irq_trigger.trigger_irq(IrqType::Vring).unwrap();
1089-
assert!(irq_trigger.has_pending_irq(IrqType::Vring));
1132+
irq_trigger.trigger(VirtioInterruptType::Queue(0)).unwrap();
1133+
assert!(irq_trigger.has_pending_interrupt(VirtioInterruptType::Queue(0)));
10901134

10911135
// Check trigger_irq() failure case (irq_evt is full).
10921136
irq_trigger.irq_evt.write(u64::MAX - 1).unwrap();
1093-
irq_trigger.trigger_irq(IrqType::Config).unwrap_err();
1094-
irq_trigger.trigger_irq(IrqType::Vring).unwrap_err();
1137+
irq_trigger
1138+
.trigger(VirtioInterruptType::Config)
1139+
.unwrap_err();
1140+
irq_trigger
1141+
.trigger(VirtioInterruptType::Queue(0))
1142+
.unwrap_err();
10951143
}
10961144
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::sync::Arc;
5+
use std::sync::atomic::AtomicU32;
6+
7+
use vmm_sys_util::eventfd::EventFd;
8+
49
/// MMIO transport for VirtIO devices
510
pub mod mmio;
11+
12+
/// Represents the types of interrupts used by VirtIO devices
13+
#[derive(Debug, Clone)]
14+
pub enum VirtioInterruptType {
15+
/// Interrupt for VirtIO configuration changes
16+
Config,
17+
/// Interrupts for new events in a queue.
18+
Queue(u16),
19+
}
20+
21+
/// API of interrupt types used by VirtIO devices
22+
pub trait VirtioInterrupt: std::fmt::Debug + Send + Sync {
23+
/// Trigger a VirtIO interrupt.
24+
fn trigger(&self, interrupt_type: VirtioInterruptType) -> Result<(), std::io::Error>;
25+
26+
/// Get the `EventFd` (if any) that backs the underlying interrupt.
27+
fn notifier(&self, _interrupt_type: VirtioInterruptType) -> Option<&EventFd> {
28+
None
29+
}
30+
31+
/// Get the current device interrupt status.
32+
fn status(&self) -> Arc<AtomicU32>;
33+
34+
/// Returns true if there is any pending interrupt
35+
#[cfg(test)]
36+
fn has_pending_interrupt(&self, interrupt_type: VirtioInterruptType) -> bool;
37+
}

0 commit comments

Comments
 (0)