mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
interrupt: Reorganize all interrupt management with InterruptManager
Based on all the previous changes, we can at this point replace the entire interrupt management with the implementation of InterruptManager and InterruptSourceGroup traits. By using KvmInterruptManager from the DeviceManager, we can provide both VirtioPciDevice and VfioPciDevice a way to pick the kind of InterruptSourceGroup they want to create. Because they choose the type of interrupt to be MSI/MSI-X, they will be given a MsiInterruptGroup. Both MsixConfig and MsiConfig are responsible for the update of the GSI routes, which is why, by passing the MsiInterruptGroup to them, they can still perform the GSI route management without knowing implementation details. That's where the InterruptSourceGroup is powerful, as it provides a generic way to manage interrupt, no matter the type of interrupt and no matter which hypervisor might be in use. Once the full replacement has been achieved, both SystemAllocator and KVM specific dependencies can be removed. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
committed by
Samuel Ortiz
parent
92082ad439
commit
4bb12a2d8d
@@ -25,7 +25,7 @@ pub use self::device::{
|
||||
BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, InterruptDelivery,
|
||||
InterruptParameters, PciDevice,
|
||||
};
|
||||
pub use self::msi::{MsiCap, MsiConfig};
|
||||
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||
use kvm_bindings::{kvm_irq_routing, kvm_irq_routing_entry};
|
||||
use kvm_ioctls::*;
|
||||
|
||||
110
pci/src/msi.rs
110
pci/src/msi.rs
@@ -6,13 +6,11 @@
|
||||
extern crate byteorder;
|
||||
extern crate vm_memory;
|
||||
|
||||
use crate::{set_kvm_routes, InterruptRoute};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use kvm_bindings::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
||||
use kvm_ioctls::VmFd;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_allocator::SystemAllocator;
|
||||
use std::sync::Arc;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
|
||||
};
|
||||
|
||||
// MSI control masks
|
||||
const MSI_CTL_ENABLE: u16 = 0x1;
|
||||
@@ -27,6 +25,16 @@ const MSI_MSG_ADDR_LO_OFFSET: u64 = 0x4;
|
||||
// MSI message masks
|
||||
const MSI_MSG_ADDR_LO_MASK: u32 = 0xffff_fffc;
|
||||
|
||||
pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
|
||||
let field = (msg_ctl >> 4) & 0x7;
|
||||
|
||||
if field > 5 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
1 << field
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct MsiCap {
|
||||
// Message Control Register
|
||||
@@ -69,13 +77,7 @@ impl MsiCap {
|
||||
}
|
||||
|
||||
fn num_enabled_vectors(&self) -> usize {
|
||||
let field = (self.msg_ctl >> 4) & 0x7;
|
||||
|
||||
if field > 5 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
1 << field
|
||||
msi_num_enabled_vectors(self.msg_ctl)
|
||||
}
|
||||
|
||||
fn vector_masked(&self, vector: usize) -> bool {
|
||||
@@ -160,33 +162,19 @@ impl MsiCap {
|
||||
|
||||
pub struct MsiConfig {
|
||||
cap: MsiCap,
|
||||
pub irq_routes: Vec<InterruptRoute>,
|
||||
vm_fd: Arc<VmFd>,
|
||||
gsi_msi_routes: Arc<Mutex<HashMap<u32, kvm_irq_routing_entry>>>,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
}
|
||||
|
||||
impl MsiConfig {
|
||||
pub fn new(
|
||||
msg_ctl: u16,
|
||||
allocator: &mut SystemAllocator,
|
||||
vm_fd: Arc<VmFd>,
|
||||
gsi_msi_routes: Arc<Mutex<HashMap<u32, kvm_irq_routing_entry>>>,
|
||||
) -> Self {
|
||||
pub fn new(msg_ctl: u16, interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
||||
let cap = MsiCap {
|
||||
msg_ctl,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut irq_routes: Vec<InterruptRoute> = Vec::new();
|
||||
for _ in 0..cap.num_enabled_vectors() {
|
||||
irq_routes.push(InterruptRoute::new(allocator).unwrap());
|
||||
}
|
||||
|
||||
MsiConfig {
|
||||
cap,
|
||||
irq_routes,
|
||||
vm_fd,
|
||||
gsi_msi_routes,
|
||||
interrupt_source_group,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,52 +186,46 @@ impl MsiConfig {
|
||||
self.cap.size()
|
||||
}
|
||||
|
||||
pub fn num_enabled_vectors(&self) -> usize {
|
||||
self.cap.num_enabled_vectors()
|
||||
}
|
||||
|
||||
pub fn update(&mut self, offset: u64, data: &[u8]) {
|
||||
let old_enabled = self.cap.enabled();
|
||||
|
||||
self.cap.update(offset, data);
|
||||
|
||||
let mut gsi_msi_routes = self.gsi_msi_routes.lock().unwrap();
|
||||
|
||||
if self.cap.enabled() {
|
||||
for (idx, route) in self.irq_routes.iter().enumerate() {
|
||||
if !old_enabled {
|
||||
if let Err(e) = self.irq_routes[idx].enable(&self.vm_fd) {
|
||||
error!("Failed enabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore MSI vector if masked.
|
||||
if self.cap.vector_masked(idx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut entry = kvm_irq_routing_entry {
|
||||
gsi: route.gsi,
|
||||
type_: KVM_IRQ_ROUTING_MSI,
|
||||
..Default::default()
|
||||
for idx in 0..self.num_enabled_vectors() {
|
||||
let config = MsiIrqSourceConfig {
|
||||
high_addr: self.cap.msg_addr_hi,
|
||||
low_addr: self.cap.msg_addr_lo,
|
||||
data: self.cap.msg_data as u32,
|
||||
};
|
||||
|
||||
entry.u.msi.address_lo = self.cap.msg_addr_lo;
|
||||
entry.u.msi.address_hi = self.cap.msg_addr_hi;
|
||||
entry.u.msi.data = u32::from(self.cap.msg_data) | (idx as u32);
|
||||
|
||||
gsi_msi_routes.insert(route.gsi, entry);
|
||||
}
|
||||
} else {
|
||||
for route in self.irq_routes.iter() {
|
||||
if old_enabled {
|
||||
if let Err(e) = route.disable(&self.vm_fd) {
|
||||
error!("Failed disabling irq_fd: {:?}", e);
|
||||
}
|
||||
if let Err(e) = self
|
||||
.interrupt_source_group
|
||||
.update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
|
||||
{
|
||||
error!("Failed updating vector: {:?}", e);
|
||||
}
|
||||
|
||||
gsi_msi_routes.remove(&route.gsi);
|
||||
if self.cap.vector_masked(idx) {
|
||||
if let Err(e) = self.interrupt_source_group.mask(idx as InterruptIndex) {
|
||||
error!("Failed masking vector: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = set_kvm_routes(&self.vm_fd, &gsi_msi_routes) {
|
||||
error!("Failed updating KVM routes: {:?}", e);
|
||||
if !old_enabled {
|
||||
if let Err(e) = self.interrupt_source_group.enable() {
|
||||
error!("Failed enabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
} else if old_enabled {
|
||||
if let Err(e) = self.interrupt_source_group.disable() {
|
||||
error!("Failed disabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
pci/src/msix.rs
123
pci/src/msix.rs
@@ -8,13 +8,11 @@ extern crate vm_memory;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{set_kvm_routes, InterruptRoute, PciCapability, PciCapabilityID};
|
||||
use crate::{PciCapability, PciCapabilityID};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use kvm_bindings::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
||||
use kvm_ioctls::VmFd;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
use vm_allocator::SystemAllocator;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
|
||||
};
|
||||
use vm_memory::ByteValued;
|
||||
|
||||
const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
|
||||
@@ -55,9 +53,7 @@ impl Default for MsixTableEntry {
|
||||
pub struct MsixConfig {
|
||||
pub table_entries: Vec<MsixTableEntry>,
|
||||
pub pba_entries: Vec<u64>,
|
||||
pub irq_routes: Vec<InterruptRoute>,
|
||||
vm_fd: Arc<VmFd>,
|
||||
gsi_msi_routes: Arc<Mutex<HashMap<u32, kvm_irq_routing_entry>>>,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
masked: bool,
|
||||
enabled: bool,
|
||||
}
|
||||
@@ -65,9 +61,7 @@ pub struct MsixConfig {
|
||||
impl MsixConfig {
|
||||
pub fn new(
|
||||
msix_vectors: u16,
|
||||
allocator: &mut SystemAllocator,
|
||||
vm_fd: Arc<VmFd>,
|
||||
gsi_msi_routes: Arc<Mutex<HashMap<u32, kvm_irq_routing_entry>>>,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
) -> Self {
|
||||
assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
|
||||
|
||||
@@ -77,17 +71,10 @@ impl MsixConfig {
|
||||
let num_pba_entries: usize = ((msix_vectors as usize) / BITS_PER_PBA_ENTRY) + 1;
|
||||
pba_entries.resize_with(num_pba_entries, Default::default);
|
||||
|
||||
let mut irq_routes: Vec<InterruptRoute> = Vec::new();
|
||||
for _ in 0..msix_vectors {
|
||||
irq_routes.push(InterruptRoute::new(allocator).unwrap());
|
||||
}
|
||||
|
||||
MsixConfig {
|
||||
table_entries,
|
||||
pba_entries,
|
||||
irq_routes,
|
||||
vm_fd,
|
||||
gsi_msi_routes,
|
||||
interrupt_source_group,
|
||||
masked: false,
|
||||
enabled: false,
|
||||
}
|
||||
@@ -110,47 +97,37 @@ impl MsixConfig {
|
||||
|
||||
// Update KVM routes
|
||||
if old_masked != self.masked || old_enabled != self.enabled {
|
||||
let mut gsi_msi_routes = self.gsi_msi_routes.lock().unwrap();
|
||||
if self.enabled && !self.masked {
|
||||
for (idx, table_entry) in self.table_entries.iter().enumerate() {
|
||||
if !old_enabled || old_masked {
|
||||
if let Err(e) = self.irq_routes[idx].enable(&self.vm_fd) {
|
||||
error!("Failed enabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore MSI-X vector if masked.
|
||||
if table_entry.masked() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let gsi = self.irq_routes[idx].gsi;
|
||||
|
||||
let mut entry = kvm_irq_routing_entry {
|
||||
gsi,
|
||||
type_: KVM_IRQ_ROUTING_MSI,
|
||||
..Default::default()
|
||||
let config = MsiIrqSourceConfig {
|
||||
high_addr: table_entry.msg_addr_hi,
|
||||
low_addr: table_entry.msg_addr_lo,
|
||||
data: table_entry.msg_data,
|
||||
};
|
||||
|
||||
entry.u.msi.address_lo = table_entry.msg_addr_lo;
|
||||
entry.u.msi.address_hi = table_entry.msg_addr_hi;
|
||||
entry.u.msi.data = table_entry.msg_data;
|
||||
|
||||
gsi_msi_routes.insert(gsi, entry);
|
||||
}
|
||||
} else {
|
||||
for route in self.irq_routes.iter() {
|
||||
if old_enabled || !old_masked {
|
||||
if let Err(e) = route.disable(&self.vm_fd) {
|
||||
error!("Failed disabling irq_fd: {:?}", e);
|
||||
}
|
||||
if let Err(e) = self
|
||||
.interrupt_source_group
|
||||
.update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
|
||||
{
|
||||
error!("Failed updating vector: {:?}", e);
|
||||
}
|
||||
|
||||
gsi_msi_routes.remove(&route.gsi);
|
||||
if table_entry.masked() {
|
||||
if let Err(e) = self.interrupt_source_group.mask(idx as InterruptIndex) {
|
||||
error!("Failed masking vector: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !old_enabled || old_masked {
|
||||
if let Err(e) = self.interrupt_source_group.enable() {
|
||||
error!("Failed enabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
} else if old_enabled || !old_masked {
|
||||
if let Err(e) = self.interrupt_source_group.disable() {
|
||||
error!("Failed disabling irq_fd: {:?}", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) = set_kvm_routes(&self.vm_fd, &gsi_msi_routes) {
|
||||
error!("Failed updating KVM routes: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,26 +238,27 @@ impl MsixConfig {
|
||||
|
||||
// Update interrupt routes
|
||||
if self.enabled && !self.masked {
|
||||
let mut gsi_msi_routes = self.gsi_msi_routes.lock().unwrap();
|
||||
let table_entry = &self.table_entries[index];
|
||||
let gsi = self.irq_routes[index].gsi;
|
||||
if !table_entry.masked() {
|
||||
let mut entry = kvm_irq_routing_entry {
|
||||
gsi,
|
||||
type_: KVM_IRQ_ROUTING_MSI,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
entry.u.msi.address_lo = table_entry.msg_addr_lo;
|
||||
entry.u.msi.address_hi = table_entry.msg_addr_hi;
|
||||
entry.u.msi.data = table_entry.msg_data;
|
||||
let config = MsiIrqSourceConfig {
|
||||
high_addr: table_entry.msg_addr_hi,
|
||||
low_addr: table_entry.msg_addr_lo,
|
||||
data: table_entry.msg_data,
|
||||
};
|
||||
|
||||
gsi_msi_routes.insert(gsi, entry);
|
||||
} else {
|
||||
gsi_msi_routes.remove(&gsi);
|
||||
if let Err(e) = self.interrupt_source_group.update(
|
||||
index as InterruptIndex,
|
||||
InterruptSourceConfig::MsiIrq(config),
|
||||
) {
|
||||
error!("Failed updating vector: {:?}", e);
|
||||
}
|
||||
if let Err(e) = set_kvm_routes(&self.vm_fd, &gsi_msi_routes) {
|
||||
error!("Failed updating KVM routes: {:?}", e);
|
||||
|
||||
if table_entry.masked() {
|
||||
if let Err(e) = self.interrupt_source_group.mask(index as InterruptIndex) {
|
||||
error!("Failed masking vector: {:?}", e);
|
||||
}
|
||||
} else if let Err(e) = self.interrupt_source_group.unmask(index as InterruptIndex) {
|
||||
error!("Failed unmasking vector: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +349,10 @@ impl MsixConfig {
|
||||
|
||||
fn inject_msix_and_clear_pba(&mut self, vector: usize) {
|
||||
// Inject the MSI message
|
||||
match self.irq_routes[vector].irq_fd.write(1) {
|
||||
match self
|
||||
.interrupt_source_group
|
||||
.trigger(vector as InterruptIndex)
|
||||
{
|
||||
Ok(_) => debug!("MSI-X injected on vector control flip"),
|
||||
Err(e) => error!("failed to inject MSI-X: {}", e),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user