diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c index bb76e70799..f537f3f25d 100644 --- a/xen/drivers/vpci/header.c +++ b/xen/drivers/vpci/header.c @@ -825,6 +825,39 @@ static int vpci_init_capability_list(struct pci_dev *pdev) PCI_STATUS_RSVDZ_MASK); } +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) ) + /* Extended capabilities read as zero, write ignore for DomU */ + return vpci_add_register(pdev->vpci, vpci_read_val, NULL, + pos, 4, (void *)0); + + do + { + uint32_t header = pci_conf_read32(pdev->sbdf, pos); + int rc; + + rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL, + pos, 4, (void *)(uintptr_t)header); + if ( rc == -EEXIST ) + { + printk(XENLOG_WARNING + "%pd %pp: overlap in extended cap list, offset %#x\n", + pdev->domain, &pdev->sbdf, pos); + return 0; + } + + if ( rc ) + return rc; + + pos = PCI_EXT_CAP_NEXT(header); + } while ( pos >= PCI_CFG_SPACE_SIZE ); + + return 0; +} + static int cf_check init_header(struct pci_dev *pdev) { uint16_t cmd; @@ -877,14 +910,9 @@ static int cf_check init_header(struct pci_dev *pdev) if ( rc ) return rc; - if ( !is_hwdom ) - { - /* Extended capabilities read as zero, write ignore */ - rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL, 0x100, 4, - (void *)0); - if ( rc ) - return rc; - } + rc = vpci_init_ext_capability_list(pdev); + if ( rc ) + return rc; if ( pdev->ignore_bars ) return 0;