From c7cabc88b40af395902c22e813416cb7c2e05699 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 30 Oct 2019 09:13:29 -0700 Subject: [PATCH] vmm: Conditionally update ioeventfds for virtio PCI device The specific part of PCI BAR reprogramming that happens for a virtio PCI device is the update of the ioeventfds addresses KVM should listen to. This should not be triggered for every BAR reprogramming associated with the virtio device since a virtio PCI device might have multiple BARs. The update of the ioeventfds addresses should only happen when the BAR related to those addresses is being moved. Signed-off-by: Sebastien Boeuf --- pci/src/bus.rs | 28 ++++++++++++--------------- pci/src/configuration.rs | 4 ++-- vm-virtio/src/transport/pci_device.rs | 9 ++++++--- vmm/src/device_manager.rs | 14 +++++++++----- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/pci/src/bus.rs b/pci/src/bus.rs index 76f4ae128..94f2adb41 100644 --- a/pci/src/bus.rs +++ b/pci/src/bus.rs @@ -194,14 +194,9 @@ impl PciConfigIo { if let Some(d) = pci_bus.devices.get(device) { let mut device = d.lock().unwrap(); - // Find out if one of the device's BAR is being reprogrammed - let bar_reprog_params = device.detect_bar_reprogramming(register, data); - - // Update the register value - device.write_config_register(register, offset, data); - - // Reprogram the BAR if needed - if let Some(params) = bar_reprog_params { + // Find out if one of the device's BAR is being reprogrammed, and + // reprogram it if needed. + if let Some(params) = device.detect_bar_reprogramming(register, data) { if let Err(e) = pci_bus.device_reloc.upgrade().unwrap().move_bar( params.old_base, params.new_base, @@ -212,6 +207,9 @@ impl PciConfigIo { error!("Failed moving device BAR: {}", e); } } + + // Update the register value + device.write_config_register(register, offset, data); } } @@ -312,14 +310,9 @@ impl PciConfigMmio { if let Some(d) = pci_bus.devices.get(device) { let mut device = d.lock().unwrap(); - // Find out if one of the device's BAR is being reprogrammed - let bar_reprog_params = device.detect_bar_reprogramming(register, data); - - // Update the register value - device.write_config_register(register, offset, data); - - // Reprogram the BAR if needed - if let Some(params) = bar_reprog_params { + // Find out if one of the device's BAR is being reprogrammed, and + // reprogram it if needed. + if let Some(params) = device.detect_bar_reprogramming(register, data) { if let Err(e) = pci_bus.device_reloc.upgrade().unwrap().move_bar( params.old_base, params.new_base, @@ -330,6 +323,9 @@ impl PciConfigMmio { error!("Failed moving device BAR: {}", e); } } + + // Update the register value + device.write_config_register(register, offset, data); } } } diff --git a/pci/src/configuration.rs b/pci/src/configuration.rs index f18d8b655..ffb048468 100755 --- a/pci/src/configuration.rs +++ b/pci/src/configuration.rs @@ -563,11 +563,11 @@ impl PciConfiguration { pub fn get_bar_addr(&self, bar_num: usize) -> u64 { let bar_idx = BAR0_REG + bar_num; - let mut addr = u64::from(self.registers[bar_idx] & self.writable_bits[bar_idx]); + let mut addr = u64::from(self.bar_addr[bar_num] & self.writable_bits[bar_idx]); if let Some(bar_type) = self.bar_type[bar_num] { if bar_type == PciBarRegionType::Memory64BitRegion { - addr |= u64::from(self.registers[bar_idx + 1]) << 32; + addr |= u64::from(self.bar_addr[bar_num + 1]) << 32; } } diff --git a/vm-virtio/src/transport/pci_device.rs b/vm-virtio/src/transport/pci_device.rs index 1a0a66705..5f817d9a9 100755 --- a/vm-virtio/src/transport/pci_device.rs +++ b/vm-virtio/src/transport/pci_device.rs @@ -362,9 +362,12 @@ impl VirtioPciDevice { } } - pub fn ioeventfds(&self) -> Vec<(&EventFd, u64, u64)> { - let bar0 = self.configuration.get_bar_addr(self.settings_bar as usize); - let notify_base = bar0 + NOTIFICATION_BAR_OFFSET; + pub fn config_bar_addr(&self) -> u64 { + self.configuration.get_bar_addr(self.settings_bar as usize) + } + + pub fn ioeventfds(&self, bar_addr: u64) -> Vec<(&EventFd, u64, u64)> { + let notify_base = bar_addr + NOTIFICATION_BAR_OFFSET; self.queue_evts() .iter() .enumerate() diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 9475d92b9..1f0324a01 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -358,10 +358,13 @@ impl DeviceRelocation for AddressManager { let any_dev = pci_dev.as_any(); if let Some(virtio_pci_dev) = any_dev.downcast_ref::() { - for (event, addr, _) in virtio_pci_dev.ioeventfds() { - let io_addr = IoEventAddress::Mmio(addr); - self.vm_fd - .register_ioevent(event.as_raw_fd(), &io_addr, NoDatamatch)?; + let bar_addr = virtio_pci_dev.config_bar_addr(); + if bar_addr == new_base { + for (event, addr, _) in virtio_pci_dev.ioeventfds(new_base) { + let io_addr = IoEventAddress::Mmio(addr); + self.vm_fd + .register_ioevent(event.as_raw_fd(), &io_addr, NoDatamatch)?; + } } } @@ -1200,7 +1203,8 @@ impl DeviceManager { .allocate_bars(&mut allocator) .map_err(DeviceManagerError::AllocateBars)?; - for (event, addr, _) in virtio_pci_device.ioeventfds() { + let bar_addr = virtio_pci_device.config_bar_addr(); + for (event, addr, _) in virtio_pci_device.ioeventfds(bar_addr) { let io_addr = IoEventAddress::Mmio(addr); vm_fd .register_ioevent(event.as_raw_fd(), &io_addr, NoDatamatch)