|
[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 |