From 710f62cc826bb8c7ead99f9d6b6b269e39ff3e98 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roger=20Pau=20Monn=C3=A9?= Date: Fri, 23 Oct 2020 10:13:14 +0200 Subject: [PATCH] pci: cleanup MSI interrupts before removing device from IOMMU MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Doing the MSI cleanup after removing the device from the IOMMU leads to the following panic on AMD hardware: Assertion 'table.ptr && (index < intremap_table_entries(table.ptr, iommu))' failed at iommu_intr.c:172 ----[ Xen-4.13.1-10.0.3-d x86_64 debug=y Not tainted ]---- CPU: 3 RIP: e008:[] drivers/passthrough/amd/iommu_intr.c#get_intremap_entry+0x52/0x7b [...] Xen call trace: [] R drivers/passthrough/amd/iommu_intr.c#get_intremap_entry+0x52/0x7b [] F drivers/passthrough/amd/iommu_intr.c#update_intremap_entry_from_msi_msg+0xc0/0x342 [] F amd_iommu_msi_msg_update_ire+0x98/0x129 [] F iommu_update_ire_from_msi+0x1e/0x21 [] F msi_free_irq+0x55/0x1a0 [] F pci_cleanup_msi+0x8c/0xb0 [] F pci_remove_device+0x1af/0x2da [] F do_physdev_op+0xd18/0x1187 [] F pv_hypercall+0x1f5/0x567 [] F lstar_enter+0x112/0x120 That's because the call to iommu_remove_device on AMD hardware will remove the per-device interrupt remapping table, and hence the call to pci_cleanup_msi done afterwards will find a null intremap table and crash. Reorder the calls so that MSI interrupts are torn down before removing the device from the IOMMU. Fixes: d7cfeb7c13ed ("AMD/IOMMU: don't blindly allocate interrupt remapping tables") Signed-off-by: Roger Pau Monné Reviewed-by: Jan Beulich --- xen/drivers/passthrough/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index b035067975..2a3bce1462 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -834,10 +834,10 @@ int pci_remove_device(u16 seg, u8 bus, u8 devfn) list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) if ( pdev->bus == bus && pdev->devfn == devfn ) { + pci_cleanup_msi(pdev); ret = iommu_remove_device(pdev); if ( pdev->domain ) list_del(&pdev->domain_list); - pci_cleanup_msi(pdev); printk(XENLOG_DEBUG "PCI remove device %pp\n", &pdev->sbdf); free_pdev(pseg, pdev); break; -- 2.30.2