Current logic of emulating legacy capability list is only for domU. So, expand it to emulate for dom0 too. Then it will be easy to hide a capability whose initialization fails in a function.
And restrict adding PCI_STATUS register only for domU since dom0 has no limitation to access that register. Signed-off-by: Jiqian Chen <jiqian.c...@amd.com> --- cc: "Roger Pau Monné" <roger....@citrix.com> --- v3->v4 changes: * Also pass supported_caps to pci_find_next_cap_ttl() for dom0 since the n is zero when dom0, and add a comment to explain it. * Restrict adding PCI_STATUS register only for domU since dom0 has no limitation to access that register. * For dom0 register handler, set vpci_hw_write8 to it instead of NULL. v2->v3 changes: * Not to add handler of PCI_CAP_LIST_ID when domain is dom0. v1->v2 changes: new patch. Best regards, Jiqian Chen. --- xen/drivers/vpci/header.c | 53 ++++++++++++++++++++++++--------------- xen/drivers/vpci/vpci.c | 6 +++++ xen/include/xen/vpci.h | 2 ++ 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c index 3e9b44454b43..a06c518c506c 100644 --- a/xen/drivers/vpci/header.c +++ b/xen/drivers/vpci/header.c @@ -749,9 +749,9 @@ 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); - if ( !is_hardware_domain(pdev->domain) && - pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST ) + if ( pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST ) { /* Only expose capabilities to the guest that vPCI can handle. */ unsigned int next, ttl = 48; @@ -759,12 +759,18 @@ static int vpci_init_capability_list(struct pci_dev *pdev) PCI_CAP_ID_MSI, PCI_CAP_ID_MSIX, }; + /* + * For dom0, 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); next = pci_find_next_cap_ttl(pdev->sbdf, PCI_CAPABILITY_LIST, - supported_caps, - ARRAY_SIZE(supported_caps), &ttl); + supported_caps, n, &ttl); - rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL, + rc = vpci_add_register(pdev->vpci, vpci_read_val, + is_hwdom ? vpci_hw_write8 : NULL, PCI_CAPABILITY_LIST, 1, (void *)(uintptr_t)next); if ( rc ) @@ -772,7 +778,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev) next &= ~3; - if ( !next ) + if ( !next && !is_hwdom ) /* * If we don't have any supported capabilities to expose to the * guest, mask the PCI_STATUS_CAP_LIST bit in the status @@ -786,15 +792,18 @@ static int vpci_init_capability_list(struct pci_dev *pdev) next = pci_find_next_cap_ttl(pdev->sbdf, pos + PCI_CAP_LIST_NEXT, - supported_caps, - ARRAY_SIZE(supported_caps), &ttl); + supported_caps, n, &ttl); - rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL, - pos + PCI_CAP_LIST_ID, 1, NULL); - if ( rc ) - return rc; + if ( !is_hwdom ) + { + rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL, + pos + PCI_CAP_LIST_ID, 1, NULL); + if ( rc ) + return rc; + } - rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL, + rc = vpci_add_register(pdev->vpci, vpci_read_val, + is_hwdom ? vpci_hw_write8 : NULL, pos + PCI_CAP_LIST_NEXT, 1, (void *)(uintptr_t)next); if ( rc ) @@ -805,13 +814,17 @@ static int vpci_init_capability_list(struct pci_dev *pdev) } /* Utilize rsvdp_mask to hide PCI_STATUS_CAP_LIST from the guest. */ - return vpci_add_register_mask(pdev->vpci, vpci_hw_read16, vpci_hw_write16, - PCI_STATUS, 2, NULL, - PCI_STATUS_RO_MASK & - ~(mask_cap_list ? PCI_STATUS_CAP_LIST : 0), - PCI_STATUS_RW1C_MASK, - mask_cap_list ? PCI_STATUS_CAP_LIST : 0, - PCI_STATUS_RSVDZ_MASK); + return is_hwdom ? 0 : vpci_add_register_mask(pdev->vpci, vpci_hw_read16, + vpci_hw_write16, PCI_STATUS, + 2, NULL, + PCI_STATUS_RO_MASK & + ~(mask_cap_list ? + PCI_STATUS_CAP_LIST : + 0), + PCI_STATUS_RW1C_MASK, + mask_cap_list ? + PCI_STATUS_CAP_LIST : 0, + PCI_STATUS_RSVDZ_MASK); } static int cf_check init_header(struct pci_dev *pdev) diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c index 1e6aa5d799b9..cf3326a966d0 100644 --- a/xen/drivers/vpci/vpci.c +++ b/xen/drivers/vpci/vpci.c @@ -226,6 +226,12 @@ uint32_t cf_check vpci_hw_read32( return pci_conf_read32(pdev->sbdf, reg); } +void cf_check vpci_hw_write8( + const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data) +{ + pci_conf_write8(pdev->sbdf, reg, val); +} + void cf_check vpci_hw_write16( const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data) { diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index 475981cb8155..fc8d5b470b0b 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -76,6 +76,8 @@ uint32_t cf_check vpci_hw_read16( const struct pci_dev *pdev, unsigned int reg, void *data); uint32_t cf_check vpci_hw_read32( const struct pci_dev *pdev, unsigned int reg, void *data); +void cf_check vpci_hw_write8( + const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data); void cf_check vpci_hw_write16( const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data); -- 2.34.1