diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2012-08-04 14:08:55 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2012-08-06 12:09:51 -0400 |
commit | a4ff1fc2ccbd81e83ac51ea44570caa361c666af (patch) | |
tree | ad667523a59057c1b608ff8b41b372e9086f6736 /drivers/iommu/intel-iommu.c | |
parent | 1adb7d31b051cd97fbb75c46772b00c13ec29c9e (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.c | 25 |
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 | ||
4163 | root_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) { |