Skip to content

Commit

Permalink
intel-iommu: fix PCI device detach from virtual machine
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Han, Weidong authored and David Woodhouse committed Mar 25, 2009
1 parent 9cf0669 commit 3199aa6
Showing 1 changed file with 29 additions and 0 deletions.
29 changes: 29 additions & 0 deletions drivers/pci/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2808,6 +2808,33 @@ static int vm_domain_add_dev_info(struct dmar_domain *domain,
return 0;
}

static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
struct pci_dev *pdev)
{
struct pci_dev *tmp, *parent;

if (!iommu || !pdev)
return;

/* dependent device detach */
tmp = pci_find_upstream_pcie_bridge(pdev);
/* Secondary interface's bus number and devfn 0 */
if (tmp) {
parent = pdev->bus->self;
while (parent != tmp) {
iommu_detach_dev(iommu, parent->bus->number,
parent->devfn);
parent = parent->bus->self;
}
if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
iommu_detach_dev(iommu,
tmp->subordinate->number, 0);
else /* this is a legacy PCI bridge */
iommu_detach_dev(iommu,
tmp->bus->number, tmp->devfn);
}
}

static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
struct pci_dev *pdev)
{
Expand All @@ -2833,6 +2860,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
spin_unlock_irqrestore(&device_domain_lock, flags);

iommu_detach_dev(iommu, info->bus, info->devfn);
iommu_detach_dependent_devices(iommu, pdev);
free_devinfo_mem(info);

spin_lock_irqsave(&device_domain_lock, flags);
Expand Down Expand Up @@ -2882,6 +2910,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)

iommu = device_to_iommu(info->bus, info->devfn);
iommu_detach_dev(iommu, info->bus, info->devfn);
iommu_detach_dependent_devices(iommu, info->dev);

/* clear this iommu in iommu_bmp, update iommu count
* and capabilities
Expand Down

0 comments on commit 3199aa6

Please sign in to comment.