[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v6 4/8] vpci: Hide extended capability when it fails to initialize
When vpci fails to initialize a extended capability of device, it just returns an error and vPCI gets disabled for the whole device. So, add function to hide extended capability when initialization fails. And remove the failed extended capability handler from vpci extended capability list. Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx> --- cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx> cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> cc: Anthony PERARD <anthony.perard@xxxxxxxxxx> cc: Michal Orzel <michal.orzel@xxxxxxx> cc: Jan Beulich <jbeulich@xxxxxxxx> cc: Julien Grall <julien@xxxxxxx> cc: Stefano Stabellini <sstabellini@xxxxxxxxxx> --- v5->v6 changes: * Change to use for loop to compact code of vpci_get_previous_ext_cap_register(). * Rename parameter rm to r in vpci_ext_capability_hide(). * Change comment to describ the case that hide capability of position 0x100U. v4->v5 changes: * Modify the hex digits of PCI_EXT_CAP_NEXT_MASK and PCI_EXT_CAP_NEXT to be low case. * Rename vpci_ext_capability_mask to vpci_ext_capability_hide. v3->v4 changes: * Change definition of PCI_EXT_CAP_NEXT to be "#define PCI_EXT_CAP_NEXT(header) (MASK_EXTR(header, PCI_EXT_CAP_NEXT_MASK) & 0xFFCU)" to avoid redundancy. * Modify the commit message. * Change vpci_ext_capability_mask() to return error instead of using ASSERT. * Set the capability ID part to be zero when we need to hide the capability of position 0x100U. * Add check "if ( !offset )" in vpci_ext_capability_mask(). v2->v3 changes: * Separated from the last version patch "vpci: Hide capability when it fails to initialize". * Whole implementation changed because last version is wrong. This version gets target handler and previous handler from vpci->handlers, then remove the target. * Note: a case in function vpci_ext_capability_mask() needs to be discussed, because it may change the offset of next capability when the offset of target capability is 0x100U(the first extended capability), my implementation is just to ignore and let hardware to handle the target capability. v1->v2 changes: * Removed the "priorities" of initializing capabilities since it isn't used anymore. * Added new function vpci_capability_mask() and vpci_ext_capability_mask() to remove failed capability from list. * Called vpci_make_msix_hole() in the end of init_msix(). Best regards, Jiqian Chen. --- xen/drivers/vpci/vpci.c | 87 ++++++++++++++++++++++++++++++++++++++ xen/include/xen/pci_regs.h | 5 ++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c index f61dcf9e8131..0c266dd6a265 100644 --- a/xen/drivers/vpci/vpci.c +++ b/xen/drivers/vpci/vpci.c @@ -165,6 +165,91 @@ static int vpci_capability_hide(struct pci_dev *pdev, unsigned int cap) return 0; } +static struct vpci_register *vpci_get_previous_ext_cap_register( + struct vpci *vpci, unsigned int offset) +{ + unsigned int pos = PCI_CFG_SPACE_SIZE; + struct vpci_register *r; + + if ( offset <= PCI_CFG_SPACE_SIZE ) + { + ASSERT_UNREACHABLE(); + return NULL; + } + + for ( r = vpci_get_register(vpci, pos, 4); r; + r = pos > PCI_CFG_SPACE_SIZE ? vpci_get_register(vpci, pos, 4) + : NULL ) + { + uint32_t header = (uint32_t)(uintptr_t)r->private; + + ASSERT(header == (uintptr_t)r->private); + + pos = PCI_EXT_CAP_NEXT(header); + if ( pos == offset ) + break; + } + + return r; +} + +static int vpci_ext_capability_hide(struct pci_dev *pdev, unsigned int cap) +{ + const unsigned int offset = pci_find_ext_capability(pdev->sbdf, cap); + struct vpci_register *r, *prev_r; + struct vpci *vpci = pdev->vpci; + uint32_t header, pre_header; + + if ( offset < PCI_CFG_SPACE_SIZE ) + { + ASSERT_UNREACHABLE(); + return 0; + } + + spin_lock(&vpci->lock); + r = vpci_get_register(vpci, offset, 4); + if ( !r ) + { + spin_unlock(&vpci->lock); + return -ENODEV; + } + + header = (uint32_t)(uintptr_t)r->private; + if ( offset == PCI_CFG_SPACE_SIZE ) + { + if ( PCI_EXT_CAP_NEXT(header) <= PCI_CFG_SPACE_SIZE ) + r->private = (void *)(uintptr_t)0; + else + /* + * The first extended capability (0x100) can not be removed from + * the linked list, so instead mask its capability ID to return 0 + * and force OSes to skip it. + */ + r->private = (void *)(uintptr_t)(header & ~PCI_EXT_CAP_ID(header)); + + spin_unlock(&vpci->lock); + return 0; + } + + prev_r = vpci_get_previous_ext_cap_register(vpci, offset); + if ( !prev_r ) + { + spin_unlock(&vpci->lock); + return -ENODEV; + } + + pre_header = (uint32_t)(uintptr_t)prev_r->private; + pre_header &= ~PCI_EXT_CAP_NEXT_MASK; + pre_header |= header & PCI_EXT_CAP_NEXT_MASK; + prev_r->private = (void *)(uintptr_t)pre_header; + + list_del(&r->node); + spin_unlock(&vpci->lock); + xfree(r); + + return 0; +} + static int vpci_init_capabilities(struct pci_dev *pdev) { for ( unsigned int i = 0; i < NUM_VPCI_INIT; i++ ) @@ -204,6 +289,8 @@ static int vpci_init_capabilities(struct pci_dev *pdev) if ( !is_ext ) rc = vpci_capability_hide(pdev, cap); + else + rc = vpci_ext_capability_hide(pdev, cap); if ( rc ) { printk(XENLOG_ERR "%pd %pp: hide %s cap %u fail rc=%d\n", diff --git a/xen/include/xen/pci_regs.h b/xen/include/xen/pci_regs.h index 27b4f44eedf3..3b6963133dbd 100644 --- a/xen/include/xen/pci_regs.h +++ b/xen/include/xen/pci_regs.h @@ -448,7 +448,10 @@ /* Extended Capabilities (PCI-X 2.0 and Express) */ #define PCI_EXT_CAP_ID(header) ((header) & 0x0000ffff) #define PCI_EXT_CAP_VER(header) (((header) >> 16) & 0xf) -#define PCI_EXT_CAP_NEXT(header) (((header) >> 20) & 0xffc) +#define PCI_EXT_CAP_NEXT_MASK 0xfff00000U +/* Bottom two bits of next capability position are reserved. */ +#define PCI_EXT_CAP_NEXT(header) \ + (MASK_EXTR(header, PCI_EXT_CAP_NEXT_MASK) & 0xffcU) #define PCI_EXT_CAP_ID_ERR 1 #define PCI_EXT_CAP_ID_VC 2 -- 2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |