(
&mut self,
reg_idx: usize,
offset: u64,
data: &[u8],
)
| 1275 | } |
| 1276 | |
| 1277 | pub(crate) fn write_config_register( |
| 1278 | &mut self, |
| 1279 | reg_idx: usize, |
| 1280 | offset: u64, |
| 1281 | data: &[u8], |
| 1282 | ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) { |
| 1283 | // When the guest wants to write to a BAR, we trap it into |
| 1284 | // our local configuration space. We're not reprogramming |
| 1285 | // VFIO device. |
| 1286 | if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_idx) |
| 1287 | || reg_idx == PCI_ROM_EXP_BAR_INDEX |
| 1288 | { |
| 1289 | // We keep our local cache updated with the BARs. |
| 1290 | // We'll read it back from there when the guest is asking |
| 1291 | // for BARs (see read_config_register()). |
| 1292 | return ( |
| 1293 | self.configuration |
| 1294 | .write_config_register(reg_idx, offset, data), |
| 1295 | None, |
| 1296 | ); |
| 1297 | } |
| 1298 | |
| 1299 | let reg = (reg_idx * PCI_CONFIG_REGISTER_SIZE) as u64; |
| 1300 | |
| 1301 | // If the MSI or MSI-X capabilities are accessed, we need to |
| 1302 | // update our local cache accordingly. |
| 1303 | // Depending on how the capabilities are modified, this could |
| 1304 | // trigger a VFIO MSI or MSI-X toggle. |
| 1305 | if let Some((cap_id, cap_base)) = self.interrupt.accessed(reg) { |
| 1306 | let cap_offset: u64 = reg - cap_base + offset; |
| 1307 | match cap_id { |
| 1308 | PciCapabilityId::MessageSignalledInterrupts => { |
| 1309 | if let Err(e) = self.update_msi_capabilities(cap_offset, data) { |
| 1310 | error!("Could not update MSI capabilities: {e}"); |
| 1311 | } |
| 1312 | } |
| 1313 | PciCapabilityId::MsiX => { |
| 1314 | if let Err(e) = self.update_msix_capabilities(cap_offset, data) { |
| 1315 | error!("Could not update MSI-X capabilities: {e}"); |
| 1316 | } |
| 1317 | } |
| 1318 | _ => {} |
| 1319 | } |
| 1320 | } |
| 1321 | |
| 1322 | // Make sure to write to the device's PCI config space after MSI/MSI-X |
| 1323 | // interrupts have been enabled/disabled. In case of MSI, when the |
| 1324 | // interrupts are enabled through VFIO (using VFIO_DEVICE_SET_IRQS), |
| 1325 | // the MSI Enable bit in the MSI capability structure found in the PCI |
| 1326 | // config space is disabled by default. That's why when the guest is |
| 1327 | // enabling this bit, we first need to enable the MSI interrupts with |
| 1328 | // VFIO through VFIO_DEVICE_SET_IRQS ioctl, and only after we can write |
| 1329 | // to the device region to update the MSI Enable bit. |
| 1330 | self.vfio_wrapper.write_config((reg + offset) as u32, data); |
| 1331 | |
| 1332 | // Return pending BAR repgrogramming if MSE bit is set |
| 1333 | let mut ret_param = self.configuration.pending_bar_reprogram(); |
| 1334 | if !ret_param.is_empty() { |
nothing calls this directly
no test coverage detected