When VFIO opens a VF, it issues a Function Level Reset which clears
PCI_COMMAND_MEMORY. This unmaps all BARs, including the migration
BAR.

Add a QEMU-internal BAR type flag that keeps a memory BAR mapped
regardless of PCI_COMMAND_MEMORY. This is needed for host-only
control regions (e.g. migration BARs) that are accessed by a VFIO
variant driver, not by the guest.

Assisted-by: Claude
Signed-off-by: Cédric Le Goater <[email protected]>
---
 include/hw/pci/pci.h | 6 ++++++
 hw/pci/pci.c         | 6 ++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index f2448e941a0b..923c8f0e15bc 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -164,6 +164,12 @@ typedef struct PCIIORegion {
     MemoryRegion *address_space;
 } PCIIORegion;
 
+/*
+ * QEMU-internal: keep this BAR mapped regardless of PCI_COMMAND_MEMORY.
+ * Stripped before writing to config space.
+ */
+#define PCI_BASE_ADDRESS_MEM_ALWAYS_ON  0x10
+
 #define PCI_ROM_SLOT 6
 #define PCI_NUM_REGIONS 7
 
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index d3191609e283..1394132c1472 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1544,7 +1544,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
         }
 
         addr = pci_bar(pci_dev, region_num);
-        pci_set_long(pci_dev->config + addr, type);
+        pci_set_long(pci_dev->config + addr,
+                     type & ~PCI_BASE_ADDRESS_MEM_ALWAYS_ON);
 
         if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
             r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
@@ -1686,7 +1687,8 @@ pcibus_t pci_bar_address(PCIDevice *d,
         return new_addr;
     }
 
-    if (!(cmd & PCI_COMMAND_MEMORY)) {
+    if (!(cmd & PCI_COMMAND_MEMORY) &&
+        !(type & PCI_BASE_ADDRESS_MEM_ALWAYS_ON)) {
         return PCI_BAR_UNMAPPED;
     }
     new_addr = pci_config_get_bar_addr(d, reg, type, size);
-- 
2.55.0


Reply via email to