pci: vfio: Split common data into VfioCommon struct

Split data that will need to be common between VfioPciDevice and
VfioUserPciDevice into a common struct. Currently this has no methods
but they will be added soon.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-07-06 13:46:18 +00:00 committed by Sebastien Boeuf
parent a0e48a87b8
commit d27ea34a2d

View File

@ -300,6 +300,12 @@ impl VfioPciConfig for VfioPciDeviceConfig {
} }
} }
struct VfioCommon {
configuration: PciConfiguration,
mmio_regions: Vec<MmioRegion>,
interrupt: Interrupt,
}
/// VfioPciDevice represents a VFIO PCI device. /// VfioPciDevice represents a VFIO PCI device.
/// This structure implements the BusDevice and PciDevice traits. /// This structure implements the BusDevice and PciDevice traits.
/// ///
@ -311,9 +317,7 @@ pub struct VfioPciDevice {
device: Arc<VfioDevice>, device: Arc<VfioDevice>,
container: Arc<VfioContainer>, container: Arc<VfioContainer>,
vfio_pci_configuration: VfioPciDeviceConfig, vfio_pci_configuration: VfioPciDeviceConfig,
configuration: PciConfiguration, common: VfioCommon,
mmio_regions: Vec<MmioRegion>,
interrupt: Interrupt,
iommu_attached: bool, iommu_attached: bool,
} }
@ -349,13 +353,15 @@ impl VfioPciDevice {
vm: vm.clone(), vm: vm.clone(),
device, device,
container, container,
configuration,
vfio_pci_configuration, vfio_pci_configuration,
mmio_regions: Vec::new(), common: VfioCommon {
interrupt: Interrupt { mmio_regions: Vec::new(),
intx: None, configuration,
msi: None, interrupt: Interrupt {
msix: None, intx: None,
msi: None,
msix: None,
},
}, },
iommu_attached, iommu_attached,
}; };
@ -372,7 +378,7 @@ impl VfioPciDevice {
} }
fn enable_intx(&mut self) -> Result<()> { fn enable_intx(&mut self) -> Result<()> {
if let Some(intx) = &mut self.interrupt.intx { if let Some(intx) = &mut self.common.interrupt.intx {
if !intx.enabled { if !intx.enabled {
if let Some(eventfd) = intx.interrupt_source_group.notifier(0) { if let Some(eventfd) = intx.interrupt_source_group.notifier(0) {
self.device self.device
@ -390,7 +396,7 @@ impl VfioPciDevice {
} }
fn disable_intx(&mut self) { fn disable_intx(&mut self) {
if let Some(intx) = &mut self.interrupt.intx { if let Some(intx) = &mut self.common.interrupt.intx {
if intx.enabled { if intx.enabled {
if let Err(e) = self.device.disable_irq(VFIO_PCI_INTX_IRQ_INDEX) { if let Err(e) = self.device.disable_irq(VFIO_PCI_INTX_IRQ_INDEX) {
error!("Could not disable INTx: {}", e); error!("Could not disable INTx: {}", e);
@ -402,7 +408,7 @@ impl VfioPciDevice {
} }
fn enable_msi(&self) -> Result<()> { fn enable_msi(&self) -> Result<()> {
if let Some(msi) = &self.interrupt.msi { if let Some(msi) = &self.common.interrupt.msi {
let mut irq_fds: Vec<EventFd> = Vec::new(); let mut irq_fds: Vec<EventFd> = Vec::new();
for i in 0..msi.cfg.num_enabled_vectors() { for i in 0..msi.cfg.num_enabled_vectors() {
if let Some(eventfd) = msi.interrupt_source_group.notifier(i as InterruptIndex) { if let Some(eventfd) = msi.interrupt_source_group.notifier(i as InterruptIndex) {
@ -427,7 +433,7 @@ impl VfioPciDevice {
} }
fn enable_msix(&self) -> Result<()> { fn enable_msix(&self) -> Result<()> {
if let Some(msix) = &self.interrupt.msix { if let Some(msix) = &self.common.interrupt.msix {
let mut irq_fds: Vec<EventFd> = Vec::new(); let mut irq_fds: Vec<EventFd> = Vec::new();
for i in 0..msix.bar.table_entries.len() { for i in 0..msix.bar.table_entries.len() {
if let Some(eventfd) = msix.interrupt_source_group.notifier(i as InterruptIndex) { if let Some(eventfd) = msix.interrupt_source_group.notifier(i as InterruptIndex) {
@ -464,7 +470,7 @@ impl VfioPciDevice {
} }
if let Some(interrupt_source_group) = legacy_interrupt_group { if let Some(interrupt_source_group) = legacy_interrupt_group {
self.interrupt.intx = Some(VfioIntx { self.common.interrupt.intx = Some(VfioIntx {
interrupt_source_group, interrupt_source_group,
enabled: false, enabled: false,
}); });
@ -507,7 +513,7 @@ impl VfioPciDevice {
let msix_config = MsixConfig::new(msix_cap.table_size(), interrupt_source_group.clone(), 0); let msix_config = MsixConfig::new(msix_cap.table_size(), interrupt_source_group.clone(), 0);
self.interrupt.msix = Some(VfioMsix { self.common.interrupt.msix = Some(VfioMsix {
bar: msix_config, bar: msix_config,
cap: msix_cap, cap: msix_cap,
cap_offset: cap.into(), cap_offset: cap.into(),
@ -533,7 +539,7 @@ impl VfioPciDevice {
let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone()); let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone());
self.interrupt.msi = Some(VfioMsi { self.common.interrupt.msi = Some(VfioMsi {
cfg: msi_config, cfg: msi_config,
cap_offset: cap.into(), cap_offset: cap.into(),
interrupt_source_group, interrupt_source_group,
@ -582,7 +588,7 @@ impl VfioPciDevice {
} }
fn update_msi_capabilities(&mut self, offset: u64, data: &[u8]) -> Result<()> { fn update_msi_capabilities(&mut self, offset: u64, data: &[u8]) -> Result<()> {
match self.interrupt.update_msi(offset, data) { match self.common.interrupt.update_msi(offset, data) {
Some(InterruptUpdateAction::EnableMsi) => { Some(InterruptUpdateAction::EnableMsi) => {
// Disable INTx before we can enable MSI // Disable INTx before we can enable MSI
self.disable_intx(); self.disable_intx();
@ -600,7 +606,7 @@ impl VfioPciDevice {
} }
fn update_msix_capabilities(&mut self, offset: u64, data: &[u8]) -> Result<()> { fn update_msix_capabilities(&mut self, offset: u64, data: &[u8]) -> Result<()> {
match self.interrupt.update_msix(offset, data) { match self.common.interrupt.update_msix(offset, data) {
Some(InterruptUpdateAction::EnableMsix) => { Some(InterruptUpdateAction::EnableMsix) => {
// Disable INTx before we can enable MSI-X // Disable INTx before we can enable MSI-X
self.disable_intx(); self.disable_intx();
@ -618,7 +624,7 @@ impl VfioPciDevice {
} }
fn find_region(&self, addr: u64) -> Option<MmioRegion> { fn find_region(&self, addr: u64) -> Option<MmioRegion> {
for region in self.mmio_regions.iter() { for region in self.common.mmio_regions.iter() {
if addr >= region.start.raw_value() if addr >= region.start.raw_value()
&& addr < region.start.unchecked_add(region.length).raw_value() && addr < region.start.unchecked_add(region.length).raw_value()
{ {
@ -642,12 +648,12 @@ impl VfioPciDevice {
{ {
let fd = self.device.as_raw_fd(); let fd = self.device.as_raw_fd();
for region in self.mmio_regions.iter_mut() { for region in self.common.mmio_regions.iter_mut() {
// We want to skip the mapping of the BAR containing the MSI-X // We want to skip the mapping of the BAR containing the MSI-X
// table even if it is mappable. The reason is we need to trap // table even if it is mappable. The reason is we need to trap
// any access to the MSI-X table and update the GSI routing // any access to the MSI-X table and update the GSI routing
// accordingly. // accordingly.
if let Some(msix) = &self.interrupt.msix { if let Some(msix) = &self.common.interrupt.msix {
if region.index == msix.cap.table_bir() || region.index == msix.cap.pba_bir() { if region.index == msix.cap.table_bir() || region.index == msix.cap.pba_bir() {
continue; continue;
} }
@ -708,7 +714,7 @@ impl VfioPciDevice {
} }
pub fn unmap_mmio_regions(&mut self) { pub fn unmap_mmio_regions(&mut self) {
for region in self.mmio_regions.iter() { for region in self.common.mmio_regions.iter() {
if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) = if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) =
(region.host_addr, region.mmap_size, region.mem_slot) (region.host_addr, region.mmap_size, region.mem_slot)
{ {
@ -761,7 +767,7 @@ impl VfioPciDevice {
} }
pub fn mmio_regions(&self) -> Vec<MmioRegion> { pub fn mmio_regions(&self) -> Vec<MmioRegion> {
self.mmio_regions.clone() self.common.mmio_regions.clone()
} }
} }
@ -769,19 +775,19 @@ impl Drop for VfioPciDevice {
fn drop(&mut self) { fn drop(&mut self) {
self.unmap_mmio_regions(); self.unmap_mmio_regions();
if let Some(msix) = &self.interrupt.msix { if let Some(msix) = &self.common.interrupt.msix {
if msix.bar.enabled() { if msix.bar.enabled() {
self.disable_msix(); self.disable_msix();
} }
} }
if let Some(msi) = &self.interrupt.msi { if let Some(msi) = &self.common.interrupt.msi {
if msi.cfg.enabled() { if msi.cfg.enabled() {
self.disable_msi(); self.disable_msi();
} }
} }
if self.interrupt.intx_in_use() { if self.common.interrupt.intx_in_use() {
self.disable_intx(); self.disable_intx();
} }
} }
@ -954,17 +960,19 @@ impl PciDevice for VfioPciDevice {
.set_region_type(region_type); .set_region_type(region_type);
if bar_id == VFIO_PCI_ROM_REGION_INDEX { if bar_id == VFIO_PCI_ROM_REGION_INDEX {
self.configuration self.common
.configuration
.add_pci_rom_bar(&config, flags & 0x1) .add_pci_rom_bar(&config, flags & 0x1)
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?; .map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
} else { } else {
self.configuration self.common
.configuration
.add_pci_bar(&config) .add_pci_bar(&config)
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?; .map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
} }
ranges.push((bar_addr, region_size, region_type)); ranges.push((bar_addr, region_size, region_type));
self.mmio_regions.push(MmioRegion { self.common.mmio_regions.push(MmioRegion {
start: bar_addr, start: bar_addr,
length: region_size, length: region_size,
type_: region_type, type_: region_type,
@ -987,7 +995,7 @@ impl PciDevice for VfioPciDevice {
&mut self, &mut self,
allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
) -> std::result::Result<(), PciDeviceError> { ) -> std::result::Result<(), PciDeviceError> {
for region in self.mmio_regions.iter() { for region in self.common.mmio_regions.iter() {
match region.type_ { match region.type_ {
PciBarRegionType::IoRegion => { PciBarRegionType::IoRegion => {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -1021,7 +1029,8 @@ impl PciDevice for VfioPciDevice {
// We keep our local cache updated with the BARs. // We keep our local cache updated with the BARs.
// We'll read it back from there when the guest is asking // We'll read it back from there when the guest is asking
// for BARs (see read_config_register()). // for BARs (see read_config_register()).
self.configuration self.common
.configuration
.write_config_register(reg_idx, offset, data); .write_config_register(reg_idx, offset, data);
return None; return None;
} }
@ -1032,7 +1041,7 @@ impl PciDevice for VfioPciDevice {
// update our local cache accordingly. // update our local cache accordingly.
// Depending on how the capabilities are modified, this could // Depending on how the capabilities are modified, this could
// trigger a VFIO MSI or MSI-X toggle. // trigger a VFIO MSI or MSI-X toggle.
if let Some((cap_id, cap_base)) = self.interrupt.accessed(reg) { if let Some((cap_id, cap_base)) = self.common.interrupt.accessed(reg) {
let cap_offset: u64 = reg - cap_base + offset; let cap_offset: u64 = reg - cap_base + offset;
match cap_id { match cap_id {
PciCapabilityId::MessageSignalledInterrupts => { PciCapabilityId::MessageSignalledInterrupts => {
@ -1071,7 +1080,7 @@ impl PciDevice for VfioPciDevice {
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(&reg_idx) if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(&reg_idx)
|| reg_idx == PCI_ROM_EXP_BAR_INDEX || reg_idx == PCI_ROM_EXP_BAR_INDEX
{ {
return self.configuration.read_reg(reg_idx); return self.common.configuration.read_reg(reg_idx);
} }
// Since we don't support passing multi-functions devices, we should // Since we don't support passing multi-functions devices, we should
@ -1094,7 +1103,9 @@ impl PciDevice for VfioPciDevice {
reg_idx: usize, reg_idx: usize,
data: &[u8], data: &[u8],
) -> Option<BarReprogrammingParams> { ) -> Option<BarReprogrammingParams> {
self.configuration.detect_bar_reprogramming(reg_idx, data) self.common
.configuration
.detect_bar_reprogramming(reg_idx, data)
} }
fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) { fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
@ -1102,8 +1113,12 @@ impl PciDevice for VfioPciDevice {
if let Some(region) = self.find_region(addr) { if let Some(region) = self.find_region(addr) {
let offset = addr - region.start.raw_value(); let offset = addr - region.start.raw_value();
if self.interrupt.msix_table_accessed(region.index, offset) { if self
self.interrupt.msix_read_table(offset, data); .common
.interrupt
.msix_table_accessed(region.index, offset)
{
self.common.interrupt.msix_read_table(offset, data);
} else { } else {
self.device.region_read(region.index, data, offset); self.device.region_read(region.index, data, offset);
} }
@ -1112,7 +1127,7 @@ impl PciDevice for VfioPciDevice {
// INTx EOI // INTx EOI
// The guest reading from the BAR potentially means the interrupt has // The guest reading from the BAR potentially means the interrupt has
// been received and can be acknowledged. // been received and can be acknowledged.
if self.interrupt.intx_in_use() { if self.common.interrupt.intx_in_use() {
if let Err(e) = self.device.unmask_irq(VFIO_PCI_INTX_IRQ_INDEX) { if let Err(e) = self.device.unmask_irq(VFIO_PCI_INTX_IRQ_INDEX) {
error!("Failed unmasking INTx IRQ: {}", e); error!("Failed unmasking INTx IRQ: {}", e);
} }
@ -1125,8 +1140,12 @@ impl PciDevice for VfioPciDevice {
let offset = addr - region.start.raw_value(); let offset = addr - region.start.raw_value();
// If the MSI-X table is written to, we need to update our cache. // If the MSI-X table is written to, we need to update our cache.
if self.interrupt.msix_table_accessed(region.index, offset) { if self
self.interrupt.msix_write_table(offset, data); .common
.interrupt
.msix_table_accessed(region.index, offset)
{
self.common.interrupt.msix_write_table(offset, data);
} else { } else {
self.device.region_write(region.index, data, offset); self.device.region_write(region.index, data, offset);
} }
@ -1135,7 +1154,7 @@ impl PciDevice for VfioPciDevice {
// INTx EOI // INTx EOI
// The guest writing to the BAR potentially means the interrupt has // The guest writing to the BAR potentially means the interrupt has
// been received and can be acknowledged. // been received and can be acknowledged.
if self.interrupt.intx_in_use() { if self.common.interrupt.intx_in_use() {
if let Err(e) = self.device.unmask_irq(VFIO_PCI_INTX_IRQ_INDEX) { if let Err(e) = self.device.unmask_irq(VFIO_PCI_INTX_IRQ_INDEX) {
error!("Failed unmasking INTx IRQ: {}", e); error!("Failed unmasking INTx IRQ: {}", e);
} }
@ -1145,7 +1164,7 @@ impl PciDevice for VfioPciDevice {
} }
fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> { fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> {
for region in self.mmio_regions.iter_mut() { for region in self.common.mmio_regions.iter_mut() {
if region.start.raw_value() == old_base { if region.start.raw_value() == old_base {
region.start = GuestAddress(new_base); region.start = GuestAddress(new_base);