[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v8 3/8] vpci: Hide legacy capability when it fails to initialize
On Thu, Jul 24, 2025 at 01:50:01PM +0800, Jiqian Chen wrote: > When vpci fails to initialize a legacy capability of device, it just > returns an error and vPCI gets disabled for the whole device. That > most likely renders the device unusable, plus possibly causing issues > to Xen itself if guest attempts to program the native MSI or MSI-X > capabilities if present. > > So, add new function to hide legacy capability when initialization > fails. And remove the failed legacy capability from the vpci emulated > legacy capability list. > > Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx> > --- > cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx> > --- > v7->v8 changes: > * Change the type of next from uint31_t to unsigned int in > vpci_get_previous_cap_register(). > * Change to not return error when cleanup fail for dom0. > > v6->v7 changes: > * Change the pointer parameter of vpci_get_register(), > vpci_get_previous_cap_register() and vpci_capability_hide() to be const. > > v5->v6 changes: > * Rename parameter rm to r in vpci_get_register(). > * Use for loop to compact the code of vpci_get_previous_cap_register(). > * Rename prev_next_r to prev_r in vpci_capability_hide((). > * Add printing when cap init, cleanup and hide fail. > > v4->v5 changes: > * Modify vpci_get_register() to delete some unnecessary check, so that > I don't need to move function vpci_register_cmp(). > * Rename vpci_capability_mask() to vpci_capability_hide(). > > v3->v4 changes: > * Modify the commit message. > * In function vpci_get_previous_cap_register(), add an ASSERT_UNREACHABLE() > if offset below 0x40. > * Modify vpci_capability_mask() to return error instead of using ASSERT. > * Use vpci_remove_register to remove PCI_CAP_LIST_ID register instead of open > code. > * Add check "if ( !offset )" in vpci_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 adds a new helper function vpci_get_register() and uses it to > get > target handler and previous handler from vpci->handlers, then remove the > target. > > 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 | 111 +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 110 insertions(+), 1 deletion(-) > > diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c > index 7778acee0df6..9960b11cf2c9 100644 > --- a/xen/drivers/vpci/vpci.c > +++ b/xen/drivers/vpci/vpci.c > @@ -83,6 +83,88 @@ static int assign_virtual_sbdf(struct pci_dev *pdev) > > #endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */ > > +static struct vpci_register *vpci_get_register(const struct vpci *vpci, > + unsigned int offset, > + unsigned int size) > +{ > + struct vpci_register *r; > + > + ASSERT(spin_is_locked(&vpci->lock)); > + > + list_for_each_entry ( r, &vpci->handlers, node ) > + { > + if ( r->offset == offset && r->size == size ) > + return r; > + > + if ( offset <= r->offset ) > + break; > + } > + > + return NULL; > +} > + > +static struct vpci_register *vpci_get_previous_cap_register( > + const struct vpci *vpci, unsigned int offset) > +{ > + unsigned int next; > + struct vpci_register *r; > + > + if ( offset < 0x40 ) > + { > + ASSERT_UNREACHABLE(); > + return NULL; > + } > + > + for ( r = vpci_get_register(vpci, PCI_CAPABILITY_LIST, 1); r; > + r = next >= 0x40 ? vpci_get_register(vpci, > + next + PCI_CAP_LIST_NEXT, 1) > + : NULL ) > + { > + next = (unsigned int)(uintptr_t)r->private; > + ASSERT(next == (uintptr_t)r->private); > + if ( next == offset ) > + break; > + } > + > + return r; > +} > + > +static int vpci_capability_hide(const struct pci_dev *pdev, unsigned int cap) > +{ > + const unsigned int offset = pci_find_cap_offset(pdev->sbdf, cap); > + struct vpci_register *prev_r, *next_r; > + struct vpci *vpci = pdev->vpci; > + > + if ( !offset ) > + { > + ASSERT_UNREACHABLE(); > + return 0; > + } > + > + spin_lock(&vpci->lock); > + prev_r = vpci_get_previous_cap_register(vpci, offset); > + next_r = vpci_get_register(vpci, offset + PCI_CAP_LIST_NEXT, 1); > + if ( !prev_r || !next_r ) > + { > + spin_unlock(&vpci->lock); > + return -ENODEV; > + } > + > + prev_r->private = next_r->private; > + /* > + * Not calling vpci_remove_register() here is to avoid redoing > + * the register search I would prefer a full stop after the sentence here, but since it's still a single sentence multi line comment, I don't think it's strictly necessary. Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |