mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-23 00:11:16 +00:00
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:
parent
a0e48a87b8
commit
d27ea34a2d
@ -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,14 +353,16 @@ impl VfioPciDevice {
|
|||||||
vm: vm.clone(),
|
vm: vm.clone(),
|
||||||
device,
|
device,
|
||||||
container,
|
container,
|
||||||
configuration,
|
|
||||||
vfio_pci_configuration,
|
vfio_pci_configuration,
|
||||||
|
common: VfioCommon {
|
||||||
mmio_regions: Vec::new(),
|
mmio_regions: Vec::new(),
|
||||||
|
configuration,
|
||||||
interrupt: Interrupt {
|
interrupt: Interrupt {
|
||||||
intx: None,
|
intx: None,
|
||||||
msi: None,
|
msi: None,
|
||||||
msix: 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(®_idx)
|
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user