[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.16] vpci/msix: fix PBA accesses



commit ef63570d8391a35fd734a956865b8295d2c57112
Author:     Roger Pau Monné <roger.pau@xxxxxxxxxx>
AuthorDate: Thu Mar 31 10:58:42 2022 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Mar 31 10:58:42 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 657697fe34..dfc8136ffb 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -51,6 +51,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 9ea66e033f..755b4fd5c8 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -129,6 +129,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.16



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.