diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 4f6bb996d0..70cfe9dc1f 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1673,6 +1673,27 @@ int domain_context_unmap_one( return rc; } +static bool any_pdev_behind_iommu(const struct domain *d, + const struct pci_dev *exclude, + const struct vtd_iommu *iommu) +{ + const struct pci_dev *pdev; + + for_each_pdev ( d, pdev ) + { + const struct acpi_drhd_unit *drhd; + + if ( pdev == exclude ) + continue; + + drhd = acpi_find_matched_drhd_unit(pdev); + if ( drhd && drhd->iommu == iommu ) + return true; + } + + return false; +} + static int domain_context_unmap(struct domain *domain, u8 devfn, struct pci_dev *pdev) { @@ -1680,7 +1701,7 @@ static int domain_context_unmap(struct domain *domain, u8 devfn, struct vtd_iommu *iommu; int ret = 0; u8 seg = pdev->seg, bus = pdev->bus, tmp_bus, tmp_devfn, secbus; - int found = 0; + bool found; drhd = acpi_find_matched_drhd_unit(pdev); if ( !drhd ) @@ -1765,23 +1786,18 @@ static int domain_context_unmap(struct domain *domain, u8 devfn, goto out; /* - * if no other devices under the same iommu owned by this domain, - * clear iommu in iommu_bitmap and clear domain_id in domid_bitmp + * If no other devices under the same iommu owned by this domain, + * clear iommu in iommu_bitmap and clear domain_id in domid_bitmap. */ - for_each_pdev ( domain, pdev ) - { - if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) - continue; + found = any_pdev_behind_iommu(domain, pdev, iommu); + /* + * Hidden devices are associated with DomXEN but usable by the hardware + * domain. Hence they need considering here as well. + */ + if ( !found && is_hardware_domain(domain) ) + found = any_pdev_behind_iommu(dom_xen, pdev, iommu); - drhd = acpi_find_matched_drhd_unit(pdev); - if ( drhd && drhd->iommu == iommu ) - { - found = 1; - break; - } - } - - if ( found == 0 ) + if ( !found ) { clear_bit(iommu->index, &dom_iommu(domain)->arch.iommu_bitmap); cleanup_domid_map(domain, iommu);