When Dom0 informs us about MMCFG usability, this may change whether
extended capabilities are available (accessible) for devices. Zap what
might be on record, and re-initialize things.
No synchronization is added for the case where devices may already be in
use. That'll need sorting when (a) DomU support was added and (b) DomU-s
may run already while Dom0 / hwdom still boots (dom0less, Hyperlaunch).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
vpci_reinit_ext_capabilities()'es return value isn't checked, as it
doesn't feel quite right to fail the hypercall because of this. At the
same time it also doesn't feel quite right to have the function return
"void". Thoughts?
---
v4: Make sure ->cleanup() and ->init() are invoked.
v3: New.
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -8,6 +8,8 @@
#include <xen/guest_access.h>
#include <xen/iocap.h>
#include <xen/serial.h>
+#include <xen/vpci.h>
+
#include <asm/current.h>
#include <asm/io_apic.h>
#include <asm/msi.h>
@@ -169,7 +171,10 @@ int cf_check physdev_check_pci_extcfg(st
ASSERT(pdev->seg == info->segment);
if ( pdev->bus >= info->start_bus && pdev->bus <= info->end_bus )
+ {
pci_check_extcfg(pdev);
+ vpci_reinit_ext_capabilities(pdev);
+ }
return 0;
}
--- a/xen/drivers/vpci/cap.c
+++ b/xen/drivers/vpci/cap.c
@@ -285,13 +285,16 @@ static int vpci_init_ext_capability_list
return 0;
}
-int vpci_init_capabilities(struct pci_dev *pdev)
+int vpci_init_capabilities(struct pci_dev *pdev, bool ext_only)
{
int rc;
- rc = vpci_init_capability_list(pdev);
- if ( rc )
- return rc;
+ if ( !ext_only )
+ {
+ rc = vpci_init_capability_list(pdev);
+ if ( rc )
+ return rc;
+ }
rc = vpci_init_ext_capability_list(pdev);
if ( rc )
@@ -305,7 +308,7 @@ int vpci_init_capabilities(struct pci_de
unsigned int pos = 0;
if ( !is_ext )
- pos = pci_find_cap_offset(pdev->sbdf, cap);
+ pos = !ext_only ? pci_find_cap_offset(pdev->sbdf, cap) : 0;
else if ( is_hardware_domain(pdev->domain) )
pos = pci_find_ext_capability(pdev, cap);
@@ -349,7 +352,7 @@ int vpci_init_capabilities(struct pci_de
return 0;
}
-void vpci_cleanup_capabilities(struct pci_dev *pdev)
+void vpci_cleanup_capabilities(struct pci_dev *pdev, bool ext_only)
{
for ( unsigned int i = 0; i < NUM_VPCI_INIT; i++ )
{
@@ -361,7 +364,7 @@ void vpci_cleanup_capabilities(struct pc
continue;
if ( !capability->is_ext )
- pos = pci_find_cap_offset(pdev->sbdf, cap);
+ pos = !ext_only ? pci_find_cap_offset(pdev->sbdf, cap) : 0;
else if ( is_hardware_domain(pdev->domain) )
pos = pci_find_ext_capability(pdev, cap);
if ( pos )
@@ -376,6 +379,20 @@ void vpci_cleanup_capabilities(struct pc
}
}
+int vpci_reinit_ext_capabilities(struct pci_dev *pdev)
+{
+ if ( !pdev->vpci )
+ return 0;
+
+ vpci_cleanup_capabilities(pdev, true);
+
+ if ( vpci_remove_registers(pdev->vpci, PCI_CFG_SPACE_SIZE,
+ PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) )
+ ASSERT_UNREACHABLE();
+
+ return vpci_init_capabilities(pdev, true);
+}
+
/*
* Local variables:
* mode: C
--- a/xen/drivers/vpci/private.h
+++ b/xen/drivers/vpci/private.h
@@ -44,8 +44,8 @@ typedef struct {
#define REGISTER_VPCI_EXTCAP(name, finit, fclean) \
REGISTER_VPCI_CAPABILITY(PCI_EXT_CAP_ID_##name, name, finit, fclean, true)
-int vpci_init_capabilities(struct pci_dev *pdev);
-void vpci_cleanup_capabilities(struct pci_dev *pdev);
+int vpci_init_capabilities(struct pci_dev *pdev, bool ext_only);
+void vpci_cleanup_capabilities(struct pci_dev *pdev, bool ext_only);
/* Add/remove a register handler. */
int __must_check vpci_add_register_mask(struct vpci *vpci,
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -102,7 +102,7 @@ void vpci_deassign_device(struct pci_dev
&pdev->domain->vpci_dev_assigned_map);
#endif
- vpci_cleanup_capabilities(pdev);
+ vpci_cleanup_capabilities(pdev, false);
spin_lock(&pdev->vpci->lock);
while ( !list_empty(&pdev->vpci->handlers) )
@@ -159,7 +159,7 @@ int vpci_assign_device(struct pci_dev *p
if ( rc )
goto out;
- rc = vpci_init_capabilities(pdev);
+ rc = vpci_init_capabilities(pdev, false);
out:
if ( rc )
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -20,6 +20,7 @@
#define VPCI_MAX_VIRT_DEV (PCI_SLOT(~0) + 1)
int __must_check vpci_init_header(struct pci_dev *pdev);
+int vpci_reinit_ext_capabilities(struct pci_dev *pdev);
/* Assign vPCI to device by adding handlers. */
int __must_check vpci_assign_device(struct pci_dev *pdev);
@@ -197,6 +198,11 @@ bool vpci_ecam_read(pci_sbdf_t sbdf, uns
#else /* !CONFIG_HAS_VPCI */
struct vpci_vcpu {};
+static inline int vpci_reinit_ext_capabilities(struct pci_dev *pdev)
+{
+ return 0;
+}
+
static inline int vpci_assign_device(struct pci_dev *pdev)
{
return 0;
© 2016 - 2026 Red Hat, Inc.