pci: vfio: Preserve prefetchable BAR flag

If the BAR for the VFIO device is marked as prefetchable on the
underlying device ensure that the BAR exposed through PciConfiguration
is also marked as prefetchable.

Fixes problem where NVIDIA devices are not usable with PCI VFIO
passthrough. See related NVIDIA kernel driver bug:
 https://github.com/NVIDIA/open-gpu-kernel-modules/issues/344.

Fixes: #4451

Signed-off-by: Steven Dake <sdake@lambdal.com>
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Steven Dake 2022-08-08 05:23:04 +00:00 committed by Rob Bradford
parent 62f1b6bc61
commit 868d1f6902
2 changed files with 21 additions and 3 deletions

View File

@ -999,6 +999,12 @@ impl PciBarConfiguration {
self
}
#[must_use]
pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self {
self.prefetchable = prefetchable;
self
}
pub fn idx(&self) -> usize {
self.idx
}

View File

@ -5,8 +5,9 @@
use crate::{
msi_num_enabled_vectors, BarReprogrammingParams, MsiCap, MsiConfig, MsixCap, MsixConfig,
PciBarConfiguration, PciBarRegionType, PciBdf, PciCapabilityId, PciClassCode, PciConfiguration,
PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciBdf, PciCapabilityId,
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
MSIX_TABLE_ENTRY_SIZE,
};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
@ -415,6 +416,7 @@ impl VfioCommon {
while bar_id < VFIO_PCI_CONFIG_REGION_INDEX {
let mut region_size: u64 = 0;
let mut region_type = PciBarRegionType::Memory32BitRegion;
let mut prefetchable = PciBarPrefetchable::NotPrefetchable;
let mut flags: u32 = 0;
let mut restored_bar_addr = None;
@ -467,6 +469,13 @@ impl VfioCommon {
false
};
if matches!(
flags & PCI_CONFIG_BAR_PREFETCHABLE,
PCI_CONFIG_BAR_PREFETCHABLE
) {
prefetchable = PciBarPrefetchable::Prefetchable
};
// To get size write all 1s
self.vfio_wrapper
.write_config_dword(bar_offset, 0xffff_ffff);
@ -566,7 +575,8 @@ impl VfioCommon {
.set_index(bar_id as usize)
.set_address(bar_addr.raw_value())
.set_size(region_size)
.set_region_type(region_type);
.set_region_type(region_type)
.set_prefetchable(prefetchable);
if bar_id == VFIO_PCI_ROM_REGION_INDEX {
self.configuration
@ -1505,6 +1515,8 @@ const PCI_CONFIG_CAPABILITY_OFFSET: u32 = 0x34;
const PCI_CONFIG_IO_BAR: u32 = 0x1;
// 64-bit memory bar flag.
const PCI_CONFIG_MEMORY_BAR_64BIT: u32 = 0x4;
// Prefetchable BAR bit
const PCI_CONFIG_BAR_PREFETCHABLE: u32 = 0x8;
// PCI config register size (4 bytes).
const PCI_CONFIG_REGISTER_SIZE: usize = 4;
// Number of BARs for a PCI device