diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 6053415b4df1f0..99a97471b00d98 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -374,6 +374,8 @@ config VIRTIO_IOMMU config XEN_IOMMU bool "Xen IOMMU driver" depends on X86 && XEN + # Built-in, and asks pcifront for a device's machine BDF. + depends on XEN_PCIDEV_FRONTEND != m select IOMMU_API select IOMMU_IO_PGTABLE help diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 3c4be7805e18c9..34f4915ec8e60b 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -568,7 +568,9 @@ static int iova_reserve_iommu_regions(struct device *dev, * are invented -- pcifront hands out iomem_resource itself, and a PVH * guest with no host bridge _CRS gets Linux's catch-all default. There * is nothing meaningful to reserve, and reserving it leaves no usable - * IOVA space whatsoever. + * IOVA space whatsoever. Dom0 sees the real host bridges and keeps the + * reservation: without it an IOVA can land on a sibling's BAR, and a + * fabric without ACS delivers the DMA there instead of to the IOMMU. */ if (dev_is_pci(dev) && !xen_iommu_manages_iova(dev)) { ret = iova_reserve_pci_windows(to_pci_dev(dev), iovad); diff --git a/drivers/iommu/xen-iommu.c b/drivers/iommu/xen-iommu.c index 986cf874319eb8..ccebf8508693d5 100644 --- a/drivers/iommu/xen-iommu.c +++ b/drivers/iommu/xen-iommu.c @@ -477,9 +477,17 @@ static struct iommu_ops xen_iommu_ops = { }, }; +/* + * True when the host-bridge windows @dev sees are not the machine's and + * dma-iommu must not reserve them: a guest's IOVA space belongs to the + * hypervisor, and the windows it sees are invented. Dom0 sees the real + * host bridges, whose windows route to real BARs, so there the reservation + * stands as on bare metal. + */ bool xen_iommu_manages_iova(struct device *dev) { - return dev->iommu && dev_iommu_ops(dev) == &xen_iommu_ops; + return !xen_initial_domain() && dev->iommu && + dev_iommu_ops(dev) == &xen_iommu_ops; } static int __init xen_iommu_init(void) diff --git a/include/xen/pci.h b/include/xen/pci.h index b5efff694a03fe..c6a215b7ba5526 100644 --- a/include/xen/pci.h +++ b/include/xen/pci.h @@ -8,7 +8,8 @@ struct pci_dev; -#if defined(CONFIG_XEN_PCIDEV_FRONTEND) +/* Called from built-in code, so a modular pcifront is as good as none. */ +#if IS_BUILTIN(CONFIG_XEN_PCIDEV_FRONTEND) int pcifront_machine_sbdf(const struct pci_dev *dev, u32 *sbdf); #else static inline int pcifront_machine_sbdf(const struct pci_dev *dev, u32 *sbdf)