interrupt: Use a single closure to describe pin based and MSI-X

In order to factorize the complexity brought by closures, this commit
merges IrqClosure and MsixClosure into a generic InterruptDelivery one.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-06-05 09:53:24 -07:00 committed by Rob Bradford
parent 8df05b72dc
commit 47a4065aaf
4 changed files with 58 additions and 33 deletions

View File

@ -13,9 +13,12 @@ use vm_allocator::SystemAllocator;
use vm_memory::{GuestAddress, GuestUsize}; use vm_memory::{GuestAddress, GuestUsize};
use vmm_sys_util::EventFd; use vmm_sys_util::EventFd;
pub type IrqClosure = Box<Fn() -> std::result::Result<(), std::io::Error> + Send + Sync>; pub struct InterruptParameters {
pub type MsixClosure = pub msix: Option<MsixTableEntry>,
Box<Fn(MsixTableEntry) -> std::result::Result<(), std::io::Error> + Send + Sync>; }
pub type InterruptDelivery =
Box<Fn(InterruptParameters) -> std::result::Result<(), std::io::Error> + Send + Sync>;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -49,14 +52,14 @@ pub trait PciDevice: BusDevice {
/// The device may write to `irq_evt` to trigger an interrupt. /// The device may write to `irq_evt` to trigger an interrupt.
fn assign_pin_irq( fn assign_pin_irq(
&mut self, &mut self,
_irq_cb: Arc<IrqClosure>, _irq_cb: Arc<InterruptDelivery>,
_irq_num: u32, _irq_num: u32,
_irq_pin: PciInterruptPin, _irq_pin: PciInterruptPin,
) { ) {
} }
/// Assign MSI-X to this device. /// Assign MSI-X to this device.
fn assign_msix(&mut self, _msi_cb: Arc<MsixClosure>) {} fn assign_msix(&mut self, _msi_cb: Arc<InterruptDelivery>) {}
/// Allocates the needed PCI BARs space using the `allocate` function which takes a size and /// Allocates the needed PCI BARs space using the `allocate` function which takes a size and
/// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples. /// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples.

View File

@ -21,7 +21,7 @@ pub use self::configuration::{
PciSubclass, PciSubclass,
}; };
pub use self::device::Error as PciDeviceError; pub use self::device::Error as PciDeviceError;
pub use self::device::{IrqClosure, MsixClosure, PciDevice}; pub use self::device::{InterruptDelivery, InterruptParameters, PciDevice};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry}; pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry};
pub use self::root::{PciConfigIo, PciConfigMmio, PciRoot, PciRootError}; pub use self::root::{PciConfigIo, PciConfigMmio, PciRoot, PciRootError};

View File

@ -20,9 +20,9 @@ use std::sync::Mutex;
use devices::BusDevice; use devices::BusDevice;
use pci::{ use pci::{
IrqClosure, MsixCap, MsixClosure, MsixConfig, PciBarConfiguration, PciCapability, InterruptDelivery, InterruptParameters, MsixCap, MsixConfig, PciBarConfiguration,
PciCapabilityID, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice, PciDeviceError,
PciInterruptPin, PciSubclass, PciHeaderType, PciInterruptPin, PciSubclass,
}; };
use vm_allocator::SystemAllocator; use vm_allocator::SystemAllocator;
use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryMmap, GuestUsize, Le32}; use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryMmap, GuestUsize, Le32};
@ -333,20 +333,33 @@ impl VirtioPciDevice {
} }
impl PciDevice for VirtioPciDevice { impl PciDevice for VirtioPciDevice {
fn assign_pin_irq(&mut self, irq_cb: Arc<IrqClosure>, irq_num: u32, irq_pin: PciInterruptPin) { fn assign_pin_irq(
&mut self,
irq_cb: Arc<InterruptDelivery>,
irq_num: u32,
irq_pin: PciInterruptPin,
) {
self.configuration.set_irq(irq_num as u8, irq_pin); self.configuration.set_irq(irq_num as u8, irq_pin);
let cb = Arc::new(Box::new(move |_queue: &Queue| (irq_cb)()) as VirtioInterrupt); let cb = Arc::new(Box::new(move |_queue: &Queue| {
let param = InterruptParameters { msix: None };
(irq_cb)(param)
}) as VirtioInterrupt);
self.interrupt_cb = Some(cb); self.interrupt_cb = Some(cb);
} }
fn assign_msix(&mut self, msi_cb: Arc<MsixClosure>) { fn assign_msix(&mut self, msi_cb: Arc<InterruptDelivery>) {
let msix_config = self.msix_config.clone(); let msix_config = self.msix_config.clone();
let cb = Arc::new(Box::new(move |queue: &Queue| { let cb = Arc::new(Box::new(move |queue: &Queue| {
(msi_cb)(msix_config.lock().unwrap().table_entries[queue.vector as usize].clone()) let param = InterruptParameters {
}) as VirtioInterruptClosure); msix: Some(
msix_config.lock().unwrap().table_entries[queue.vector as usize].clone(),
),
};
(msi_cb)(param)
}) as VirtioInterrupt);
self.interrupt_cb = Some(cb); self.interrupt_cb = Some(cb);
} }

View File

@ -28,7 +28,7 @@ use libc::{c_void, siginfo_t, EFD_NONBLOCK};
use linux_loader::loader::KernelLoader; use linux_loader::loader::KernelLoader;
use net_util::Tap; use net_util::Tap;
use pci::{ use pci::{
IrqClosure, MsixClosure, MsixTableEntry, PciConfigIo, PciDevice, PciInterruptPin, PciRoot, InterruptDelivery, InterruptParameters, PciConfigIo, PciDevice, PciInterruptPin, PciRoot,
}; };
use qcow::{self, ImageType, QcowFile}; use qcow::{self, ImageType, QcowFile};
use std::ffi::CString; use std::ffi::CString;
@ -447,24 +447,31 @@ impl DeviceManager {
if msi_capable { if msi_capable {
let vm_fd_clone = vm_fd.clone(); let vm_fd_clone = vm_fd.clone();
let msi_cb = Arc::new(Box::new(move |entry: MsixTableEntry| { let msi_cb = Arc::new(Box::new(move |p: InterruptParameters| {
let msi_queue = kvm_msi { if let Some(entry) = p.msix {
address_lo: entry.msg_addr_lo, let msi_queue = kvm_msi {
address_hi: entry.msg_addr_hi, address_lo: entry.msg_addr_lo,
data: entry.msg_data, address_hi: entry.msg_addr_hi,
flags: 0u32, data: entry.msg_data,
devid: 0u32, flags: 0u32,
pad: [0u8; 12], devid: 0u32,
}; pad: [0u8; 12],
};
vm_fd_clone.signal_msi(msi_queue).map(|ret| { return vm_fd_clone.signal_msi(msi_queue).map(|ret| {
if ret > 0 { if ret > 0 {
debug!("MSI message successfully delivered"); debug!("MSI message successfully delivered");
} else if ret == 0 { } else if ret == 0 {
warn!("failed to deliver MSI message, blocked by guest"); warn!("failed to deliver MSI message, blocked by guest");
} }
}) });
}) as MsixClosure); }
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"missing MSI-X entry",
))
}) as InterruptDelivery);
virtio_pci_device.assign_msix(msi_cb); virtio_pci_device.assign_msix(msi_cb);
} else { } else {
@ -477,7 +484,9 @@ impl DeviceManager {
.register_irqfd(irqfd.as_raw_fd(), irq_num) .register_irqfd(irqfd.as_raw_fd(), irq_num)
.map_err(DeviceManagerError::Irq)?; .map_err(DeviceManagerError::Irq)?;
let irq_cb = Arc::new(Box::new(move || irqfd.write(1)) as IrqClosure); let irq_cb = Arc::new(
Box::new(move |_p: InterruptParameters| irqfd.write(1)) as InterruptDelivery
);
virtio_pci_device.assign_pin_irq(irq_cb, irq_num as u32, PciInterruptPin::IntA); virtio_pci_device.assign_pin_irq(irq_cb, irq_num as u32, PciInterruptPin::IntA);
} }