Introduce 'bool map' and allow invoking modify_bars() without changing
the memory decoding bit. This will allow hardware domain to reposition
BARs without affecting the memory decoding bit.
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
---
This also lays some groundwork to allow domUs to toggle the guest view
without affecting hardware, a step toward addressing the FIXME in [1].
[1] https://lore.kernel.org/xen-devel/20250814160358.95543-4-roger.pau@citrix.com/
v2->v3:
* use bool
* switch to task->map in more places
v1->v2:
* new patch
---
xen/drivers/vpci/header.c | 38 ++++++++++++++++++++------------------
xen/include/xen/vpci.h | 1 +
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index e57c00839841..9856840c3c87 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -116,11 +116,12 @@ static int cf_check map_range(
* BAR's enable bit has changed with the memory decoding bit already enabled.
* If rom_only is not set then it's the memory decoding bit that changed.
*/
-static void modify_decoding(const struct pci_dev *pdev, uint16_t cmd,
- bool rom_only)
+static void modify_decoding(const struct pci_dev *pdev,
+ struct vpci_map_task *task)
{
struct vpci_header *header = &pdev->vpci->header;
- bool map = cmd & PCI_COMMAND_MEMORY;
+ bool rom_only = task->rom_only;
+ bool map = task->map;
unsigned int i;
for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
@@ -167,7 +168,7 @@ static void modify_decoding(const struct pci_dev *pdev, uint16_t cmd,
if ( !rom_only )
{
- pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
+ pci_conf_write16(pdev->sbdf, PCI_COMMAND, task->cmd);
header->bars_mapped = map;
}
else
@@ -190,7 +191,7 @@ static int vpci_process_map_task(const struct pci_dev *pdev,
struct rangeset *mem = bar->mem;
struct map_data data = {
.d = pdev->domain,
- .map = task->cmd & PCI_COMMAND_MEMORY,
+ .map = task->map,
.bar = bar,
};
int rc;
@@ -205,9 +206,11 @@ static int vpci_process_map_task(const struct pci_dev *pdev,
if ( rc )
{
- spin_lock(&pdev->vpci->lock);
/* Disable memory decoding unconditionally on failure. */
- modify_decoding(pdev, task->cmd & ~PCI_COMMAND_MEMORY, false);
+ task->cmd &= ~PCI_COMMAND_MEMORY;
+ task->map = false;
+ spin_lock(&pdev->vpci->lock);
+ modify_decoding(pdev, task);
spin_unlock(&pdev->vpci->lock);
/* Clean all the rangesets */
@@ -225,7 +228,7 @@ static int vpci_process_map_task(const struct pci_dev *pdev,
}
spin_lock(&pdev->vpci->lock);
- modify_decoding(pdev, task->cmd, task->rom_only);
+ modify_decoding(pdev, task);
spin_unlock(&pdev->vpci->lock);
task->pending = false;
@@ -305,7 +308,7 @@ static int __init apply_map(struct domain *d, const struct pci_dev *pdev,
}
}
if ( !rc )
- modify_decoding(pdev, task->cmd, false);
+ modify_decoding(pdev, task);
task->pending = false;
@@ -333,7 +336,7 @@ static void defer_map(const struct pci_dev *pdev)
}
static int modify_bars(const struct pci_dev *pdev, uint16_t cmd, bool rom_only,
- unsigned int map_slot)
+ bool map, unsigned int map_slot)
{
struct vpci_header *header = &pdev->vpci->header;
struct pci_dev *tmp;
@@ -534,6 +537,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t cmd, bool rom_only,
task->cmd = cmd;
task->rom_only = rom_only;
+ task->map = map;
task->pending = true;
if ( system_state < SYS_STATE_active )
@@ -546,7 +550,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t cmd, bool rom_only,
* be called iff the memory decoding bit is enabled, thus the operation
* will always be to establish mappings and process all the BARs.
*/
- ASSERT((cmd & PCI_COMMAND_MEMORY) && !rom_only);
+ ASSERT(map && !rom_only);
return apply_map(pdev->domain, pdev, task);
}
@@ -583,7 +587,7 @@ static void cf_check cmd_write(
* memory decoding bit has not been changed, so leave everything as-is,
* hoping the guest will realize and try again.
*/
- modify_bars(pdev, cmd, false, 0);
+ modify_bars(pdev, cmd, false, cmd & PCI_COMMAND_MEMORY, 0);
else
pci_conf_write16(pdev->sbdf, reg, cmd);
}
@@ -747,11 +751,8 @@ static void cf_check rom_write(
header->rom_enabled = new_enabled;
pci_conf_write32(pdev->sbdf, reg, val);
}
- /*
- * Pass PCI_COMMAND_MEMORY or 0 to signal a map/unmap request, note that
- * this fabricated command is never going to be written to the register.
- */
- else if ( modify_bars(pdev, new_enabled ? PCI_COMMAND_MEMORY : 0, true, 0) )
+ /* Note that the command value 0 will never be written to the register */
+ else if ( modify_bars(pdev, 0, true, new_enabled, 0) )
/*
* No memory has been added or removed from the p2m (because the actual
* p2m changes are deferred in defer_map) and the ROM enable bit has
@@ -941,7 +942,8 @@ int vpci_init_header(struct pci_dev *pdev)
goto fail;
}
- return (cmd & PCI_COMMAND_MEMORY) ? modify_bars(pdev, cmd, false, 0) : 0;
+ return (cmd & PCI_COMMAND_MEMORY) ? modify_bars(pdev, cmd, false, true, 0)
+ : 0;
fail:
pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index e4fbf7b702d6..a6f8cb67dcac 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -166,6 +166,7 @@ struct vpci_vcpu {
} bars[ARRAY_SIZE(((struct vpci_header *)NULL)->bars)];
uint16_t cmd;
bool rom_only : 1;
+ bool map : 1;
bool pending : 1;
} task[1];
};
--
2.53.0
© 2016 - 2026 Red Hat, Inc.