aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/intel-iommu.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2012-08-04 14:08:55 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-08-06 12:09:51 -0400
commita4ff1fc2ccbd81e83ac51ea44570caa361c666af (patch)
treead667523a59057c1b608ff8b41b372e9086f6736 /drivers/iommu/intel-iommu.c
parent1adb7d31b051cd97fbb75c46772b00c13ec29c9e (diff)
iommu/intel: Fix ACS path checking
SR-IOV can create buses without a bridge. There may be other cases where this happens as well. In these cases skip to the parent bus and continue testing devices there. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Tested-by: David Ahern <dsahern@gmail.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r--drivers/iommu/intel-iommu.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0204b62480b0..2297ec193eb4 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4125,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev)
4125 } else 4125 } else
4126 dma_pdev = pci_dev_get(pdev); 4126 dma_pdev = pci_dev_get(pdev);
4127 4127
4128 /* Account for quirked devices */
4128 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); 4129 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4129 4130
4131 /*
4132 * If it's a multifunction device that does not support our
4133 * required ACS flags, add to the same group as function 0.
4134 */
4130 if (dma_pdev->multifunction && 4135 if (dma_pdev->multifunction &&
4131 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) 4136 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
4132 swap_pci_ref(&dma_pdev, 4137 swap_pci_ref(&dma_pdev,
@@ -4134,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev)
4134 PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 4139 PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
4135 0))); 4140 0)));
4136 4141
4142 /*
4143 * Devices on the root bus go through the iommu. If that's not us,
4144 * find the next upstream device and test ACS up to the root bus.
4145 * Finding the next device may require skipping virtual buses.
4146 */
4137 while (!pci_is_root_bus(dma_pdev->bus)) { 4147 while (!pci_is_root_bus(dma_pdev->bus)) {
4138 if (pci_acs_path_enabled(dma_pdev->bus->self, 4148 struct pci_bus *bus = dma_pdev->bus;
4139 NULL, REQ_ACS_FLAGS)) 4149
4150 while (!bus->self) {
4151 if (!pci_is_root_bus(bus))
4152 bus = bus->parent;
4153 else
4154 goto root_bus;
4155 }
4156
4157 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
4140 break; 4158 break;
4141 4159
4142 swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); 4160 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
4143 } 4161 }
4144 4162
4163root_bus:
4145 group = iommu_group_get(&dma_pdev->dev); 4164 group = iommu_group_get(&dma_pdev->dev);
4146 pci_dev_put(dma_pdev); 4165 pci_dev_put(dma_pdev);
4147 if (!group) { 4166 if (!group) {