From: Stefano Stabellini <stefano.stabellini@amd.com>
With Dom0 now being able to use a virtual bridge we need a way to
distinguish Dom0 using HW bridghe from Dom0 using virtual bridge.
Introduce a new macro has_vpci_bridge that would determine if a domain
should be treated as using HW bridge (only Dom0 with pci-scan disabled)
or as using a virtual one (all DomUs and Dom0 with pci-scan enabled)
Use the macro in drivers/vpci.
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
---
v2->v3:
* s/is_hwdom/is_hw_bridge/
v1->v2:
* simplify definition
---
xen/arch/arm/include/asm/pci.h | 1 +
xen/arch/arm/pci/pci.c | 2 +-
xen/drivers/vpci/header.c | 74 +++++++++++++++++-----------------
xen/drivers/vpci/vpci.c | 4 +-
xen/include/xen/vpci.h | 8 ++++
5 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/xen/arch/arm/include/asm/pci.h b/xen/arch/arm/include/asm/pci.h
index 0680b2f50c..7289f7688b 100644
--- a/xen/arch/arm/include/asm/pci.h
+++ b/xen/arch/arm/include/asm/pci.h
@@ -23,6 +23,7 @@
#define pci_to_dev(pcidev) (&(pcidev)->arch.dev)
extern bool pci_passthrough_enabled;
+extern bool pci_scan_enabled;
struct rangeset;
diff --git a/xen/arch/arm/pci/pci.c b/xen/arch/arm/pci/pci.c
index 49ee003c5e..951639eb3f 100644
--- a/xen/arch/arm/pci/pci.c
+++ b/xen/arch/arm/pci/pci.c
@@ -92,7 +92,7 @@ bool __read_mostly pci_passthrough_enabled;
boolean_param("pci-passthrough", pci_passthrough_enabled);
/* By default pci scan is disabled. */
-static __ro_after_init bool pci_scan_enabled;
+__ro_after_init bool pci_scan_enabled;
boolean_param("pci-scan", pci_scan_enabled);
static int __init pci_init(void)
diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index 469f497744..528e8b660b 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -230,7 +230,7 @@ bool vpci_process_pending(struct vcpu *v)
read_unlock(&v->domain->pci_lock);
- if ( !is_hardware_domain(v->domain) )
+ if ( has_vpci_bridge(v->domain) )
domain_crash(v->domain);
return false;
@@ -492,7 +492,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t cmd, bool rom_only)
}
}
- if ( !is_hardware_domain(d) )
+ if ( has_vpci_bridge(d) )
break;
d = dom_xen;
@@ -522,7 +522,7 @@ static void cf_check cmd_write(
{
struct vpci_header *header = data;
- if ( !is_hardware_domain(pdev->domain) )
+ if ( has_vpci_bridge(pdev->domain) )
{
const struct vpci *vpci = pdev->vpci;
@@ -564,7 +564,7 @@ static void cf_check bar_write(
struct vpci_bar *bar = data;
bool hi = false;
- ASSERT(is_hardware_domain(pdev->domain));
+ ASSERT(!has_vpci_bridge(pdev->domain));
if ( bar->type == VPCI_BAR_MEM64_HI )
{
@@ -747,7 +747,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
{
int rc;
bool mask_cap_list = false;
- bool is_hwdom = is_hardware_domain(pdev->domain);
+ bool is_hw_bridge = !has_vpci_bridge(pdev->domain);
if ( pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST )
{
@@ -758,17 +758,17 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
PCI_CAP_ID_MSIX,
};
/*
- * For dom0, we should expose all capabilities instead of a fixed
+ * For hw bridge, we should expose all capabilities instead of a fixed
* capabilities array, so setting n to 0 here is to get the next
* capability position directly in pci_find_next_cap_ttl.
*/
- const unsigned int n = is_hwdom ? 0 : ARRAY_SIZE(supported_caps);
+ const unsigned int n = is_hw_bridge ? 0 : ARRAY_SIZE(supported_caps);
next = pci_find_next_cap_ttl(pdev->sbdf, PCI_CAPABILITY_LIST,
supported_caps, n, &ttl);
rc = vpci_add_register(pdev->vpci, vpci_read_val,
- is_hwdom ? vpci_hw_write8 : NULL,
+ is_hw_bridge ? vpci_hw_write8 : NULL,
PCI_CAPABILITY_LIST, 1,
(void *)(uintptr_t)next);
if ( rc )
@@ -776,7 +776,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
next &= ~3;
- if ( !next && !is_hwdom )
+ if ( !next && !is_hw_bridge )
/*
* If we don't have any supported capabilities to expose to the
* guest, mask the PCI_STATUS_CAP_LIST bit in the status
@@ -792,7 +792,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
pos + PCI_CAP_LIST_NEXT,
supported_caps, n, &ttl);
- if ( !is_hwdom )
+ if ( !is_hw_bridge )
{
rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL,
pos + PCI_CAP_LIST_ID, 1, NULL);
@@ -801,7 +801,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
}
rc = vpci_add_register(pdev->vpci, vpci_read_val,
- is_hwdom ? vpci_hw_write8 : NULL,
+ is_hw_bridge ? vpci_hw_write8 : NULL,
pos + PCI_CAP_LIST_NEXT, 1,
(void *)(uintptr_t)next);
if ( rc )
@@ -811,8 +811,8 @@ static int vpci_init_capability_list(struct pci_dev *pdev)
}
}
- /* Return early for the hw domain, no masking of PCI_STATUS. */
- if ( is_hwdom )
+ /* Return early for the hw bridge, no masking of PCI_STATUS. */
+ if ( is_hw_bridge )
return 0;
/* Utilize rsvdp_mask to hide PCI_STATUS_CAP_LIST from the guest. */
@@ -829,7 +829,7 @@ static int vpci_init_ext_capability_list(const struct pci_dev *pdev)
{
unsigned int pos = PCI_CFG_SPACE_SIZE;
- if ( !is_hardware_domain(pdev->domain) )
+ if ( has_vpci_bridge(pdev->domain) )
/* Extended capabilities read as zero, write ignore for DomU */
return vpci_add_register(pdev->vpci, vpci_read_val, NULL,
pos, 4, (void *)0);
@@ -866,7 +866,7 @@ int vpci_init_header(struct pci_dev *pdev)
struct vpci_header *header = &pdev->vpci->header;
struct vpci_bar *bars = header->bars;
int rc;
- bool is_hwdom = is_hardware_domain(pdev->domain);
+ bool is_hw_bridge = !has_vpci_bridge(pdev->domain);
ASSERT(rw_is_write_locked(&pdev->domain->pci_lock));
@@ -893,15 +893,15 @@ int vpci_init_header(struct pci_dev *pdev)
* PCI_COMMAND_PARITY, PCI_COMMAND_SERR, and PCI_COMMAND_FAST_BACK.
*/
rc = vpci_add_register_mask(pdev->vpci,
- is_hwdom ? vpci_hw_read16 : guest_cmd_read,
+ is_hw_bridge ? vpci_hw_read16 : guest_cmd_read,
cmd_write, PCI_COMMAND, 2, header, 0, 0,
- is_hwdom ? 0
- : PCI_COMMAND_RSVDP_MASK |
- PCI_COMMAND_IO |
- PCI_COMMAND_PARITY |
- PCI_COMMAND_WAIT |
- PCI_COMMAND_SERR |
- PCI_COMMAND_FAST_BACK,
+ is_hw_bridge ? 0
+ : PCI_COMMAND_RSVDP_MASK |
+ PCI_COMMAND_IO |
+ PCI_COMMAND_PARITY |
+ PCI_COMMAND_WAIT |
+ PCI_COMMAND_SERR |
+ PCI_COMMAND_FAST_BACK,
0);
if ( rc )
return rc;
@@ -925,7 +925,7 @@ int vpci_init_header(struct pci_dev *pdev)
* start with memory decoding disabled, and modify_bars() will not be called
* at the end of this function.
*/
- if ( !is_hwdom )
+ if ( !is_hw_bridge )
cmd &= ~(PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_INVALIDATE |
PCI_COMMAND_SPECIAL | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
PCI_COMMAND_IO);
@@ -933,7 +933,7 @@ int vpci_init_header(struct pci_dev *pdev)
header->guest_cmd = cmd;
/* Disable memory decoding before sizing. */
- if ( !is_hwdom || (cmd & PCI_COMMAND_MEMORY) )
+ if ( !is_hw_bridge || (cmd & PCI_COMMAND_MEMORY) )
pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd & ~PCI_COMMAND_MEMORY);
for ( i = 0; i < num_bars; i++ )
@@ -945,9 +945,10 @@ int vpci_init_header(struct pci_dev *pdev)
{
bars[i].type = VPCI_BAR_MEM64_HI;
rc = vpci_add_register(pdev->vpci,
- is_hwdom ? vpci_hw_read32
- : guest_mem_bar_read,
- is_hwdom ? bar_write : guest_mem_bar_write,
+ is_hw_bridge ? vpci_hw_read32
+ : guest_mem_bar_read,
+ is_hw_bridge ? bar_write
+ : guest_mem_bar_write,
reg, 4, &bars[i]);
if ( rc )
goto fail;
@@ -959,7 +960,7 @@ int vpci_init_header(struct pci_dev *pdev)
if ( (val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO )
{
bars[i].type = VPCI_BAR_IO;
- if ( !IS_ENABLED(CONFIG_X86) && !is_hwdom )
+ if ( !IS_ENABLED(CONFIG_X86) && !is_hw_bridge )
{
rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
reg, 4, (void *)0);
@@ -988,7 +989,7 @@ int vpci_init_header(struct pci_dev *pdev)
{
bars[i].type = VPCI_BAR_EMPTY;
- if ( !is_hwdom )
+ if ( !is_hw_bridge )
{
rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
reg, 4, (void *)0);
@@ -1005,17 +1006,18 @@ int vpci_init_header(struct pci_dev *pdev)
bars[i].prefetchable = val & PCI_BASE_ADDRESS_MEM_PREFETCH;
rc = vpci_add_register(pdev->vpci,
- is_hwdom ? vpci_hw_read32 : guest_mem_bar_read,
- is_hwdom ? bar_write : guest_mem_bar_write,
+ is_hw_bridge ? vpci_hw_read32
+ : guest_mem_bar_read,
+ is_hw_bridge ? bar_write : guest_mem_bar_write,
reg, 4, &bars[i]);
if ( rc )
goto fail;
}
/* Check expansion ROM. */
- rc = is_hwdom ? pci_size_mem_bar(pdev->sbdf, rom_reg, &addr, &size,
- PCI_BAR_ROM)
- : 0;
+ rc = is_hw_bridge ? pci_size_mem_bar(pdev->sbdf, rom_reg, &addr, &size,
+ PCI_BAR_ROM)
+ : 0;
if ( rc > 0 && size )
{
struct vpci_bar *rom = &header->bars[num_bars];
@@ -1038,7 +1040,7 @@ int vpci_init_header(struct pci_dev *pdev)
goto fail;
}
}
- else if ( !is_hwdom )
+ else if ( !is_hw_bridge )
{
/* TODO: Check expansion ROM, we do not handle ROM for guests for now */
header->bars[num_bars].type = VPCI_BAR_EMPTY;
diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index 07c7071d0a..8ea89b9805 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -48,7 +48,7 @@ static int assign_virtual_sbdf(struct pci_dev *pdev)
ASSERT(rw_is_write_locked(&pdev->domain->pci_lock));
- if ( is_hardware_domain(d) )
+ if ( !has_vpci_bridge(d) )
return 0;
/*
@@ -429,7 +429,7 @@ static const struct pci_dev *translate_virtual_device(const struct domain *d,
#ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
const struct pci_dev *pdev;
- ASSERT(!is_hardware_domain(d));
+ ASSERT(has_vpci_bridge(d));
ASSERT(rw_is_locked(&d->pci_lock));
for_each_pdev ( d, pdev )
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index 9ae75d946a..d4695cb353 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -339,6 +339,14 @@ static inline int __must_check vpci_reset_device(struct pci_dev *pdev)
return vpci_assign_device(pdev);
}
+#ifdef CONFIG_ARM
+#include <asm/pci.h>
+
+#define has_vpci_bridge(d) (!is_hardware_domain(d) || pci_scan_enabled)
+#else
+#define has_vpci_bridge(d) (!is_hardware_domain(d))
+#endif
+
#endif
/*
--
2.51.2
On 18.11.2025 14:36, Mykyta Poturai wrote:
> From: Stefano Stabellini <stefano.stabellini@amd.com>
>
> With Dom0 now being able to use a virtual bridge we need a way to
> distinguish Dom0 using HW bridghe from Dom0 using virtual bridge.
> Introduce a new macro has_vpci_bridge that would determine if a domain
> should be treated as using HW bridge (only Dom0 with pci-scan disabled)
> or as using a virtual one (all DomUs and Dom0 with pci-scan enabled)
Where does the connection of "pci-scan {en,dis}abled" with "kind of bridges
in use" come from? There is a connection for what you're trying to achieve
right now, but this doesn't want setting in stone now, to avoid making it
harder to decouple the two again later.
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -230,7 +230,7 @@ bool vpci_process_pending(struct vcpu *v)
>
> read_unlock(&v->domain->pci_lock);
>
> - if ( !is_hardware_domain(v->domain) )
> + if ( has_vpci_bridge(v->domain) )
> domain_crash(v->domain);
At this example (applies more or less similarly elsewhere as well, and needs
answering separately for every instance), and effectively re-iterating a
point made previously: Why is it the kind of bridges that are used which
determines whether to call domain_crash() here?
Jan
© 2016 - 2025 Red Hat, Inc.