pci: Handle pending BAR reprogramming for VFIO devices properly

The way how we handle PCI configuration space for vfio and vfio-user
devices are different from the rest of PCI devices. Besides accesses to
BAR registers (trapped to access the shadowing PCI config space we
maintained), accesses to other registers (including the COMMAND
register) are handled directly by the underline vfio or vfio-user
device.

This patch adds the proper handling of pending BAR reprogramming for
vfio and vfio-user devices.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
This commit is contained in:
Bo Chen 2025-05-12 23:02:06 +00:00
parent aaf86ef209
commit 8da7c13e26
2 changed files with 30 additions and 3 deletions

View file

@ -18,8 +18,8 @@ use crate::{MsixConfig, PciInterruptPin};
// The number of 32bit registers in the config space, 4096 bytes.
const NUM_CONFIGURATION_REGISTERS: usize = 1024;
const COMMAND_REG: usize = 1;
const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
pub(crate) const COMMAND_REG: usize = 1;
pub(crate) const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
const STATUS_REG: usize = 1;
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
const BAR0_REG: usize = 4;
@ -1093,6 +1093,14 @@ impl PciConfiguration {
None
}
pub(crate) fn pending_bar_reprogram(&self) -> Vec<BarReprogrammingParams> {
self.pending_bar_reprogram.clone()
}
pub(crate) fn clear_pending_bar_reprogram(&mut self) {
self.pending_bar_reprogram = Vec::new();
}
}
impl Pausable for PciConfiguration {}

View file

@ -1292,7 +1292,26 @@ impl VfioCommon {
// to the device region to update the MSI Enable bit.
self.vfio_wrapper.write_config((reg + offset) as u32, data);
(Vec::new(), None)
// Return pending BAR repgrogramming if MSE bit is set
let mut ret_param = self.configuration.pending_bar_reprogram();
if !ret_param.is_empty() {
if self.read_config_register(crate::configuration::COMMAND_REG)
& crate::configuration::COMMAND_REG_MEMORY_SPACE_MASK
== crate::configuration::COMMAND_REG_MEMORY_SPACE_MASK
{
info!("BAR reprogramming parameter is returned: {:x?}", ret_param);
self.configuration.clear_pending_bar_reprogram();
} else {
info!(
"MSE bit is disabled. No BAR reprogramming parameter is returned: {:x?}",
ret_param
);
ret_param = Vec::new();
}
}
(ret_param, None)
}
pub(crate) fn read_config_register(&mut self, reg_idx: usize) -> u32 {