mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
pci, virtio-devices: Move VirtioPciDevice to the new restore design
The code for restoring a VirtioPciDevice has been updated, including the dependencies VirtioPciCommonConfig, MsixConfig and PciConfiguration. It's important to note that both PciConfiguration and MsixConfig still have restore() implementations because Vfio and VfioUser devices still rely on the old way for restore. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
committed by
Rob Bradford
parent
8868c9c950
commit
eae8043890
@@ -62,6 +62,7 @@ impl PciRoot {
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ const CAPABILITY_MAX_OFFSET: usize = 192;
|
||||
|
||||
const INTERRUPT_LINE_PIN_REG: usize = 15;
|
||||
|
||||
pub const PCI_CONFIGURATION_ID: &str = "pci_configuration";
|
||||
|
||||
/// Represents the types of PCI headers allowed in the configuration registers.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum PciHeaderType {
|
||||
@@ -394,7 +396,7 @@ fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Versionize)]
|
||||
#[derive(Debug, Default, Clone, Copy, Versionize)]
|
||||
struct PciBar {
|
||||
addr: u32,
|
||||
size: u32,
|
||||
@@ -403,7 +405,7 @@ struct PciBar {
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
struct PciConfigurationState {
|
||||
pub struct PciConfigurationState {
|
||||
registers: Vec<u32>,
|
||||
writable_bits: Vec<u32>,
|
||||
bars: Vec<PciBar>,
|
||||
@@ -553,46 +555,78 @@ impl PciConfiguration {
|
||||
subsystem_vendor_id: u16,
|
||||
subsystem_id: u16,
|
||||
msix_config: Option<Arc<Mutex<MsixConfig>>>,
|
||||
state: Option<PciConfigurationState>,
|
||||
) -> Self {
|
||||
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
|
||||
// TODO(dverkamp): Status should be write-1-to-clear
|
||||
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
|
||||
let pi = if let Some(pi) = programming_interface {
|
||||
pi.get_register_value()
|
||||
let (
|
||||
registers,
|
||||
writable_bits,
|
||||
bars,
|
||||
rom_bar_addr,
|
||||
rom_bar_size,
|
||||
rom_bar_used,
|
||||
last_capability,
|
||||
msix_cap_reg_idx,
|
||||
) = if let Some(state) = state {
|
||||
(
|
||||
state.registers.try_into().unwrap(),
|
||||
state.writable_bits.try_into().unwrap(),
|
||||
state.bars.try_into().unwrap(),
|
||||
state.rom_bar_addr,
|
||||
state.rom_bar_size,
|
||||
state.rom_bar_used,
|
||||
state.last_capability,
|
||||
state.msix_cap_reg_idx,
|
||||
)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
registers[2] = u32::from(class_code.get_register_value()) << 24
|
||||
| u32::from(subclass.get_register_value()) << 16
|
||||
| u32::from(pi) << 8
|
||||
| u32::from(revision_id);
|
||||
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
|
||||
match header_type {
|
||||
PciHeaderType::Device => {
|
||||
registers[3] = 0x0000_0000; // Header type 0 (device)
|
||||
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
|
||||
}
|
||||
PciHeaderType::Bridge => {
|
||||
registers[3] = 0x0001_0000; // Header type 1 (bridge)
|
||||
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
|
||||
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
|
||||
}
|
||||
};
|
||||
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
|
||||
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
|
||||
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
|
||||
// TODO(dverkamp): Status should be write-1-to-clear
|
||||
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
|
||||
let pi = if let Some(pi) = programming_interface {
|
||||
pi.get_register_value()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
registers[2] = u32::from(class_code.get_register_value()) << 24
|
||||
| u32::from(subclass.get_register_value()) << 16
|
||||
| u32::from(pi) << 8
|
||||
| u32::from(revision_id);
|
||||
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
|
||||
match header_type {
|
||||
PciHeaderType::Device => {
|
||||
registers[3] = 0x0000_0000; // Header type 0 (device)
|
||||
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
|
||||
}
|
||||
PciHeaderType::Bridge => {
|
||||
registers[3] = 0x0001_0000; // Header type 1 (bridge)
|
||||
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
|
||||
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
|
||||
}
|
||||
};
|
||||
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
|
||||
|
||||
let bars = [PciBar::default(); NUM_BAR_REGS];
|
||||
(
|
||||
registers,
|
||||
writable_bits,
|
||||
[PciBar::default(); NUM_BAR_REGS],
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
};
|
||||
|
||||
PciConfiguration {
|
||||
registers,
|
||||
writable_bits,
|
||||
bars,
|
||||
rom_bar_addr: 0,
|
||||
rom_bar_size: 0,
|
||||
rom_bar_used: false,
|
||||
last_capability: None,
|
||||
msix_cap_reg_idx: None,
|
||||
rom_bar_addr,
|
||||
rom_bar_size,
|
||||
rom_bar_used,
|
||||
last_capability,
|
||||
msix_cap_reg_idx,
|
||||
msix_config,
|
||||
}
|
||||
}
|
||||
@@ -1046,7 +1080,7 @@ impl Pausable for PciConfiguration {}
|
||||
|
||||
impl Snapshottable for PciConfiguration {
|
||||
fn id(&self) -> String {
|
||||
String::from("pci_configuration")
|
||||
String::from(PCI_CONFIGURATION_ID)
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
@@ -1178,6 +1212,7 @@ mod tests {
|
||||
0xABCD,
|
||||
0x2468,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
// Add two capabilities with different contents.
|
||||
@@ -1234,6 +1269,7 @@ mod tests {
|
||||
0xABCD,
|
||||
0x2468,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let class_reg = cfg.read_reg(2);
|
||||
|
||||
@@ -19,12 +19,13 @@ pub use self::configuration::{
|
||||
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityId,
|
||||
PciClassCode, PciConfiguration, PciExpressCapabilityId, PciHeaderType, PciMassStorageSubclass,
|
||||
PciNetworkControllerSubclass, PciProgrammingInterface, PciSerialBusSubClass, PciSubclass,
|
||||
PCI_CONFIGURATION_ID,
|
||||
};
|
||||
pub use self::device::{
|
||||
BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice,
|
||||
};
|
||||
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE};
|
||||
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
||||
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
||||
use serde::de::Visitor;
|
||||
|
||||
@@ -26,9 +26,10 @@ const MSIX_ENABLE_BIT: u8 = 15;
|
||||
const FUNCTION_MASK_MASK: u16 = (1 << FUNCTION_MASK_BIT) as u16;
|
||||
const MSIX_ENABLE_MASK: u16 = (1 << MSIX_ENABLE_BIT) as u16;
|
||||
pub const MSIX_TABLE_ENTRY_SIZE: usize = 16;
|
||||
pub const MSIX_CONFIG_ID: &str = "msix_config";
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
pub enum Error {
|
||||
/// Failed enabling the interrupt route.
|
||||
EnableInterruptRoute(io::Error),
|
||||
/// Failed updating the interrupt route.
|
||||
@@ -61,7 +62,7 @@ impl Default for MsixTableEntry {
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
struct MsixConfigState {
|
||||
pub struct MsixConfigState {
|
||||
table_entries: Vec<MsixTableEntry>,
|
||||
pba_entries: Vec<u64>,
|
||||
masked: bool,
|
||||
@@ -84,23 +85,62 @@ impl MsixConfig {
|
||||
msix_vectors: u16,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
devid: u32,
|
||||
) -> Self {
|
||||
state: Option<MsixConfigState>,
|
||||
) -> result::Result<Self, Error> {
|
||||
assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
|
||||
|
||||
let mut table_entries: Vec<MsixTableEntry> = Vec::new();
|
||||
table_entries.resize_with(msix_vectors as usize, Default::default);
|
||||
let mut pba_entries: Vec<u64> = Vec::new();
|
||||
let num_pba_entries: usize = ((msix_vectors as usize) / BITS_PER_PBA_ENTRY) + 1;
|
||||
pba_entries.resize_with(num_pba_entries, Default::default);
|
||||
let (table_entries, pba_entries, masked, enabled) = if let Some(state) = state {
|
||||
if state.enabled && !state.masked {
|
||||
for (idx, table_entry) in state.table_entries.iter().enumerate() {
|
||||
if table_entry.masked() {
|
||||
continue;
|
||||
}
|
||||
|
||||
MsixConfig {
|
||||
let config = MsiIrqSourceConfig {
|
||||
high_addr: table_entry.msg_addr_hi,
|
||||
low_addr: table_entry.msg_addr_lo,
|
||||
data: table_entry.msg_data,
|
||||
devid,
|
||||
};
|
||||
|
||||
interrupt_source_group
|
||||
.update(
|
||||
idx as InterruptIndex,
|
||||
InterruptSourceConfig::MsiIrq(config),
|
||||
state.masked,
|
||||
)
|
||||
.map_err(Error::UpdateInterruptRoute)?;
|
||||
|
||||
interrupt_source_group
|
||||
.enable()
|
||||
.map_err(Error::EnableInterruptRoute)?;
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
state.table_entries,
|
||||
state.pba_entries,
|
||||
state.masked,
|
||||
state.enabled,
|
||||
)
|
||||
} else {
|
||||
let mut table_entries: Vec<MsixTableEntry> = Vec::new();
|
||||
table_entries.resize_with(msix_vectors as usize, Default::default);
|
||||
let mut pba_entries: Vec<u64> = Vec::new();
|
||||
let num_pba_entries: usize = ((msix_vectors as usize) / BITS_PER_PBA_ENTRY) + 1;
|
||||
pba_entries.resize_with(num_pba_entries, Default::default);
|
||||
|
||||
(table_entries, pba_entries, true, false)
|
||||
};
|
||||
|
||||
Ok(MsixConfig {
|
||||
table_entries,
|
||||
pba_entries,
|
||||
devid,
|
||||
interrupt_source_group,
|
||||
masked: true,
|
||||
enabled: false,
|
||||
}
|
||||
masked,
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
fn state(&self) -> MsixConfigState {
|
||||
@@ -426,7 +466,7 @@ impl Pausable for MsixConfig {}
|
||||
|
||||
impl Snapshottable for MsixConfig {
|
||||
fn id(&self) -> String {
|
||||
String::from("msix_config")
|
||||
String::from(MSIX_CONFIG_ID)
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
|
||||
@@ -663,7 +663,9 @@ impl VfioCommon {
|
||||
msix_cap.table_size(),
|
||||
interrupt_source_group.clone(),
|
||||
bdf.into(),
|
||||
);
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.interrupt.msix = Some(VfioMsix {
|
||||
bar: msix_config,
|
||||
@@ -1235,6 +1237,7 @@ impl VfioPciDevice {
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let vfio_wrapper = VfioDeviceWrapper::new(Arc::clone(&device));
|
||||
|
||||
@@ -88,6 +88,7 @@ impl VfioUserPciDevice {
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let resettable = client.lock().unwrap().resettable();
|
||||
if resettable {
|
||||
|
||||
Reference in New Issue
Block a user