[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 8/8] vpci/msix: Add function to clean MSIX resources
On Wed, Apr 09, 2025 at 02:45:28PM +0800, Jiqian Chen wrote: > When init_msix() fails, it needs to clean all MSIX resources. > So, add a new function fini_msix() to do that. > > And to unregister the mmio handler of vpci_msix_table_ops, add > a new function. > > Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx> > --- > cc: Jan Beulich <jbeulich@xxxxxxxx> > cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx> > --- > v1->v2 changes: > new patch. > > Best regards, > Jiqian Chen. > --- > xen/arch/x86/hvm/intercept.c | 44 ++++++++++++++++++++++ > xen/arch/x86/include/asm/hvm/io.h | 3 ++ > xen/drivers/vpci/msix.c | 61 ++++++++++++++++++++++++++++--- > 3 files changed, 103 insertions(+), 5 deletions(-) > > diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c > index da22c386763e..5eacf51d4d2c 100644 > --- a/xen/arch/x86/hvm/intercept.c > +++ b/xen/arch/x86/hvm/intercept.c > @@ -276,6 +276,50 @@ void register_mmio_handler(struct domain *d, > handler->mmio.ops = ops; > } > > +void unregister_mmio_handler(struct domain *d, > + const struct hvm_mmio_ops *ops) > +{ > + unsigned int i, count = d->arch.hvm.io_handler_count; > + > + ASSERT(d->arch.hvm.io_handler); > + > + if ( !count ) > + return; > + > + for ( i = 0; i < count; i++ ) > + if ( d->arch.hvm.io_handler[i].type == IOREQ_TYPE_COPY && > + d->arch.hvm.io_handler[i].mmio.ops == ops ) > + break; > + > + if ( i == count ) > + return; > + > + for ( ; i < count - 1; i++ ) > + { > + struct hvm_io_handler *curr = &d->arch.hvm.io_handler[i]; > + struct hvm_io_handler *next = &d->arch.hvm.io_handler[i + 1]; > + > + curr->type = next->type; > + curr->ops = next->ops; > + if ( next->type == IOREQ_TYPE_COPY ) > + { > + curr->portio.port = 0; > + curr->portio.size = 0; > + curr->portio.action = 0; > + curr->mmio.ops = next->mmio.ops; > + } > + else > + { > + curr->mmio.ops = 0; > + curr->portio.port = next->portio.port; > + curr->portio.size = next->portio.size; > + curr->portio.action = next->portio.action; > + } > + } Can't you use memmove() instead of a for loop? memmove(&d->arch.hvm.io_handler[i], &d->arch.hvm.io_handler[i + 1], sizeof(d->arch.hvm.io_handler[0]) * (count - i - 1)); > + > + d->arch.hvm.io_handler_count--; > +} > + > void register_portio_handler(struct domain *d, unsigned int port, > unsigned int size, portio_action_t action) > { > diff --git a/xen/arch/x86/include/asm/hvm/io.h > b/xen/arch/x86/include/asm/hvm/io.h > index 565bad300d20..018d2745fd99 100644 > --- a/xen/arch/x86/include/asm/hvm/io.h > +++ b/xen/arch/x86/include/asm/hvm/io.h > @@ -75,6 +75,9 @@ bool hvm_mmio_internal(paddr_t gpa); > void register_mmio_handler(struct domain *d, > const struct hvm_mmio_ops *ops); > > +void unregister_mmio_handler(struct domain *d, > + const struct hvm_mmio_ops *ops); > + > void register_portio_handler( > struct domain *d, unsigned int port, unsigned int size, > portio_action_t action); > diff --git a/xen/drivers/vpci/msix.c b/xen/drivers/vpci/msix.c > index 6537374c79a0..60654d4f6d0b 100644 > --- a/xen/drivers/vpci/msix.c > +++ b/xen/drivers/vpci/msix.c > @@ -703,6 +703,54 @@ int vpci_make_msix_hole(const struct pci_dev *pdev) > return 0; > } > > +static void fini_msix(struct pci_dev *pdev) > +{ > + struct vpci *vpci = pdev->vpci; > + > + if ( !vpci->msix ) > + return; > + > + list_del(&vpci->msix->next); > + if ( list_empty(&pdev->domain->arch.hvm.msix_tables) ) > + unregister_mmio_handler(pdev->domain, &vpci_msix_table_ops); At the point the MMIO handler is added the capability initialization cannot fail, so arguably if the MSI-X handler is registered there will always be at least one functional MSI-X capability that requires it. IOW: you can likely drop the addition of unregister_mmio_handler() and avoid the removal of the MMIO handler. Worst case a domain will end up with a dummy handler that does nothing, but it won't cause malfunctions. > + > + /* Remove any MSIX regions if present. */ > + for ( unsigned int i = 0; > + vpci->msix && i < ARRAY_SIZE(vpci->msix->tables); > + i++ ) > + { > + unsigned long start = PFN_DOWN(vmsix_table_addr(pdev->vpci, i)); > + unsigned long end = PFN_DOWN(vmsix_table_addr(pdev->vpci, i) + > + vmsix_table_size(pdev->vpci, i) - 1); > + > + for ( unsigned int j = 0; j < ARRAY_SIZE(vpci->header.bars); j++ ) > + { > + int rc; > + const struct vpci_bar *bar = &vpci->header.bars[j]; > + > + if ( rangeset_is_empty(bar->mem) ) > + continue; > + > + rc = rangeset_remove_range(bar->mem, start, end); > + if ( rc ) > + { > + gprintk(XENLOG_WARNING, > + "%pp: failed to remove MSIX table [%lx, %lx]: %d\n", > + &pdev->sbdf, start, end, rc); > + return; > + } > + } > + } There's no need to do any of this rangeset manipulation. The BAR rangesets are re-created for any map/unmap request, and hence should be empty unless there's a concurrent operation going on (which won't be the case when initializing the capabilities). > + > + for ( unsigned int i = 0; i < ARRAY_SIZE(vpci->msix->table); i++ ) > + if ( vpci->msix->table[i] ) > + iounmap(vpci->msix->table[i]); The MSI-X init function never maps tables, so the code here (given it's current usage) will also never unmap anything. However I would also like to use this code for vPCI deassing, at which point the logic will get used. Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |