]> xenbits.xensource.com Git - people/hx242/xen.git/commitdiff
pci: clear {host/guest}_maskall field on assign
authorRoger Pau Monné <roger.pau@citrix.com>
Thu, 10 Oct 2019 08:59:27 +0000 (10:59 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 10 Oct 2019 08:59:27 +0000 (10:59 +0200)
The current implementation of host_maskall makes it sticky across
assign and deassign calls, which means that once a guest forces Xen to
set host_maskall the maskall bit is not going to be cleared until a
call to PHYSDEVOP_prepare_msix is performed. Such call however
shouldn't be part of the normal flow when doing PCI passthrough, and
hence the flag needs to be cleared when assigning in order to prevent
host_maskall being carried over from previous assignations.

Note that the entry maskbit is reset when the msix capability is
initialized, and the guest_maskall field is also cleared so that the
hardware value matches Xen's internal state (hardware maskall =
host_maskall | guest_maskall).

Also note that doing the reset of host_maskall there would allow the
guest to reset such field by enabling and disabling MSIX, which is not
intended.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Chao Gao <chao.gao@intel.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
xen/arch/x86/msi.c
xen/drivers/passthrough/pci.c
xen/include/asm-x86/msi.h

index 76d4034c4f5db44b3c76470618732685fbd10303..c239a00fb11d86797e9ba4ee1ab3743da5313bab 100644 (file)
@@ -1249,6 +1249,28 @@ void pci_cleanup_msi(struct pci_dev *pdev)
     msi_free_irqs(pdev);
 }
 
+int pci_reset_msix_state(struct pci_dev *pdev)
+{
+    unsigned int pos = pci_find_cap_offset(pdev->seg, pdev->bus, pdev->sbdf.dev,
+                                           pdev->sbdf.fn, PCI_CAP_ID_MSIX);
+
+    ASSERT(pos);
+    /*
+     * Xen expects the device state to be the after reset one, and hence
+     * host_maskall = guest_maskall = false and all entries should have the
+     * mask bit set. Test that the maskall bit is not set, having it set could
+     * signal that the device hasn't been reset properly.
+     */
+    if ( pci_conf_read16(pdev->sbdf, msix_control_reg(pos)) &
+         PCI_MSIX_FLAGS_MASKALL )
+        return -EBUSY;
+
+    pdev->msix->host_maskall = false;
+    pdev->msix->guest_maskall = false;
+
+    return 0;
+}
+
 int pci_msi_conf_write_intercept(struct pci_dev *pdev, unsigned int reg,
                                  unsigned int size, uint32_t *data)
 {
index 90ccb8370b644ae8e7a8409464075ac3fe035e5d..bdcc482d819b64c31b8607f74df18f327418c44a 100644 (file)
@@ -1505,7 +1505,12 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
     }
 
     if ( pdev->msix )
+    {
+        rc = pci_reset_msix_state(pdev);
+        if ( rc )
+            goto done;
         msixtbl_init(d);
+    }
 
     pdev->fault.count = 0;
 
index d0b0045d0d5edd956b15400a6258217ab60db983..6e35713ec792f2e7c2dcb9c51762c8358b7076d7 100644 (file)
@@ -92,6 +92,7 @@ extern int __setup_msi_irq(struct irq_desc *, struct msi_desc *,
 extern void teardown_msi_irq(int irq);
 extern int msi_free_vector(struct msi_desc *entry);
 extern int pci_restore_msi_state(struct pci_dev *pdev);
+extern int pci_reset_msix_state(struct pci_dev *pdev);
 
 struct msi_desc {
        struct msi_attrib {