[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.15] vpci/msix: fix PBA accesses
commit dd79dcc9f1bfd775fd7889d6684c41feee7c4eb0 Author: Roger Pau Monné <roger.pau@xxxxxxxxxx> AuthorDate: Mon Apr 4 15:19:52 2022 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Mon Apr 4 15:19:52 2022 +0200 vpci/msix: fix PBA accesses Map the PBA in order to access it from the MSI-X read and write handlers. Note that previously the handlers would pass the physical host address into the {read,write}{l,q} handlers, which is wrong as those expect a linear address. Map the PBA using ioremap when the first access is performed. Note that 32bit arches might want to abstract the call to ioremap into a vPCI arch handler, so they can use a fixmap range to map the PBA. Reported-by: Jan Beulich <jbeulich@xxxxxxxx> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> Tested-by: Alex Olson <Alex.Olson@xxxxxxxxxx> master commit: b4f21160601155762a4d014db9623af921fec959 master date: 2022-03-09 16:21:01 +0100 --- xen/drivers/vpci/msix.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++--- xen/drivers/vpci/vpci.c | 2 ++ xen/include/xen/vpci.h | 2 ++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/xen/drivers/vpci/msix.c b/xen/drivers/vpci/msix.c index 846f1b8d70..ac5de98f6d 100644 --- a/xen/drivers/vpci/msix.c +++ b/xen/drivers/vpci/msix.c @@ -182,6 +182,38 @@ static struct vpci_msix_entry *get_entry(struct vpci_msix *msix, return &msix->entries[(addr - start) / PCI_MSIX_ENTRY_SIZE]; } +static void __iomem *get_pba(struct vpci *vpci) +{ + struct vpci_msix *msix = vpci->msix; + /* + * PBA will only be unmapped when the device is deassigned, so access it + * without holding the vpci lock. + */ + void __iomem *pba = read_atomic(&msix->pba); + + if ( likely(pba) ) + return pba; + + pba = ioremap(vmsix_table_addr(vpci, VPCI_MSIX_PBA), + vmsix_table_size(vpci, VPCI_MSIX_PBA)); + if ( !pba ) + return read_atomic(&msix->pba); + + spin_lock(&vpci->lock); + if ( !msix->pba ) + { + write_atomic(&msix->pba, pba); + spin_unlock(&vpci->lock); + } + else + { + spin_unlock(&vpci->lock); + iounmap(pba); + } + + return read_atomic(&msix->pba); +} + static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len, unsigned long *data) { @@ -200,6 +232,10 @@ static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len, if ( VMSIX_ADDR_IN_RANGE(addr, msix->pdev->vpci, VPCI_MSIX_PBA) ) { + struct vpci *vpci = msix->pdev->vpci; + unsigned int idx = addr - vmsix_table_addr(vpci, VPCI_MSIX_PBA); + const void __iomem *pba = get_pba(vpci); + /* * Access to PBA. * @@ -207,14 +243,22 @@ static int msix_read(struct vcpu *v, unsigned long addr, unsigned int len, * guest address space. If this changes the address will need to be * translated. */ + if ( !pba ) + { + gprintk(XENLOG_WARNING, + "%pp: unable to map MSI-X PBA, report all pending\n", + msix->pdev); + return X86EMUL_OKAY; + } + switch ( len ) { case 4: - *data = readl(addr); + *data = readl(pba + idx); break; case 8: - *data = readq(addr); + *data = readq(pba + idx); break; default: @@ -278,14 +322,27 @@ static int msix_write(struct vcpu *v, unsigned long addr, unsigned int len, /* Ignore writes to PBA for DomUs, it's behavior is undefined. */ if ( is_hardware_domain(d) ) { + struct vpci *vpci = msix->pdev->vpci; + unsigned int idx = addr - vmsix_table_addr(vpci, VPCI_MSIX_PBA); + const void __iomem *pba = get_pba(vpci); + + if ( !pba ) + { + /* Unable to map the PBA, ignore write. */ + gprintk(XENLOG_WARNING, + "%pp: unable to map MSI-X PBA, write ignored\n", + msix->pdev); + return X86EMUL_OKAY; + } + switch ( len ) { case 4: - writel(data, addr); + writel(data, pba + idx); break; case 8: - writeq(data, addr); + writeq(data, pba + idx); break; default: diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c index cbd1bac7fc..a27c9e600d 100644 --- a/xen/drivers/vpci/vpci.c +++ b/xen/drivers/vpci/vpci.c @@ -48,6 +48,8 @@ void vpci_remove_device(struct pci_dev *pdev) xfree(r); } spin_unlock(&pdev->vpci->lock); + if ( pdev->vpci->msix && pdev->vpci->msix->pba ) + iounmap(pdev->vpci->msix->pba); xfree(pdev->vpci->msix); xfree(pdev->vpci->msi); xfree(pdev->vpci); diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index 9f5b5d52e1..f19e79447a 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -127,6 +127,8 @@ struct vpci { bool enabled : 1; /* Masked? */ bool masked : 1; + /* PBA map */ + void __iomem *pba; /* Entries. */ struct vpci_msix_entry { uint64_t addr; -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.15
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |