diff options
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r-- | drivers/pci/intel-iommu.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a0ba568b831c..e541c3bdbf0d 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -2808,6 +2808,33 @@ static int vm_domain_add_dev_info(struct dmar_domain *domain, | |||
2808 | return 0; | 2808 | return 0; |
2809 | } | 2809 | } |
2810 | 2810 | ||
2811 | static void iommu_detach_dependent_devices(struct intel_iommu *iommu, | ||
2812 | struct pci_dev *pdev) | ||
2813 | { | ||
2814 | struct pci_dev *tmp, *parent; | ||
2815 | |||
2816 | if (!iommu || !pdev) | ||
2817 | return; | ||
2818 | |||
2819 | /* dependent device detach */ | ||
2820 | tmp = pci_find_upstream_pcie_bridge(pdev); | ||
2821 | /* Secondary interface's bus number and devfn 0 */ | ||
2822 | if (tmp) { | ||
2823 | parent = pdev->bus->self; | ||
2824 | while (parent != tmp) { | ||
2825 | iommu_detach_dev(iommu, parent->bus->number, | ||
2826 | parent->devfn); | ||
2827 | parent = parent->bus->self; | ||
2828 | } | ||
2829 | if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ | ||
2830 | iommu_detach_dev(iommu, | ||
2831 | tmp->subordinate->number, 0); | ||
2832 | else /* this is a legacy PCI bridge */ | ||
2833 | iommu_detach_dev(iommu, | ||
2834 | tmp->bus->number, tmp->devfn); | ||
2835 | } | ||
2836 | } | ||
2837 | |||
2811 | static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, | 2838 | static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, |
2812 | struct pci_dev *pdev) | 2839 | struct pci_dev *pdev) |
2813 | { | 2840 | { |
@@ -2833,6 +2860,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, | |||
2833 | spin_unlock_irqrestore(&device_domain_lock, flags); | 2860 | spin_unlock_irqrestore(&device_domain_lock, flags); |
2834 | 2861 | ||
2835 | iommu_detach_dev(iommu, info->bus, info->devfn); | 2862 | iommu_detach_dev(iommu, info->bus, info->devfn); |
2863 | iommu_detach_dependent_devices(iommu, pdev); | ||
2836 | free_devinfo_mem(info); | 2864 | free_devinfo_mem(info); |
2837 | 2865 | ||
2838 | spin_lock_irqsave(&device_domain_lock, flags); | 2866 | spin_lock_irqsave(&device_domain_lock, flags); |
@@ -2882,6 +2910,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain) | |||
2882 | 2910 | ||
2883 | iommu = device_to_iommu(info->bus, info->devfn); | 2911 | iommu = device_to_iommu(info->bus, info->devfn); |
2884 | iommu_detach_dev(iommu, info->bus, info->devfn); | 2912 | iommu_detach_dev(iommu, info->bus, info->devfn); |
2913 | iommu_detach_dependent_devices(iommu, info->dev); | ||
2885 | 2914 | ||
2886 | /* clear this iommu in iommu_bmp, update iommu count | 2915 | /* clear this iommu in iommu_bmp, update iommu count |
2887 | * and capabilities | 2916 | * and capabilities |