aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/intel-iommu.c
diff options
context:
space:
mode:
authorHan, Weidong <weidong.han@intel.com>2009-02-26 04:31:12 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-03-25 11:53:53 -0400
commit3199aa6bc8766e17b8f60820c4f78d59c25fce0e (patch)
tree229e32c18afbbe5017ed3f84247055e767a57f0f /drivers/pci/intel-iommu.c
parent9cf0669746be19a4906a6c48920060bcf54c708b (diff)
intel-iommu: fix PCI device detach from virtual machine
When assign a device behind conventional PCI bridge or PCIe to PCI/PCI-x bridge to a domain, it must assign its bridge and may also need to assign secondary interface to the same domain. Dependent assignment is already there, but dependent deassignment is missed when detach device from virtual machine. This results in conventional PCI device assignment failure after it has been assigned once. This patch addes dependent deassignment, and fixes the issue. Signed-off-by: Weidong Han <weidong.han@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r--drivers/pci/intel-iommu.c29
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
2811static 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
2811static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, 2838static 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