diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2012-08-04 14:09:03 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2012-08-06 12:10:04 -0400 |
commit | 31fe943599b7e5870edb9decb7fbb9538b218f26 (patch) | |
tree | 1119d2e2c2fe1cd7fa6911f6945611b0f7d34d7b /drivers/iommu | |
parent | a4ff1fc2ccbd81e83ac51ea44570caa361c666af (diff) |
iommu/amd: 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>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/amd_iommu.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 6d1cbdfc9b2a..b64502dfa9f4 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -296,8 +296,13 @@ static int iommu_init_device(struct device *dev) | |||
296 | } else | 296 | } else |
297 | dma_pdev = pci_dev_get(pdev); | 297 | dma_pdev = pci_dev_get(pdev); |
298 | 298 | ||
299 | /* Account for quirked devices */ | ||
299 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); | 300 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); |
300 | 301 | ||
302 | /* | ||
303 | * If it's a multifunction device that does not support our | ||
304 | * required ACS flags, add to the same group as function 0. | ||
305 | */ | ||
301 | if (dma_pdev->multifunction && | 306 | if (dma_pdev->multifunction && |
302 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) | 307 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) |
303 | swap_pci_ref(&dma_pdev, | 308 | swap_pci_ref(&dma_pdev, |
@@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev) | |||
305 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), | 310 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), |
306 | 0))); | 311 | 0))); |
307 | 312 | ||
313 | /* | ||
314 | * Devices on the root bus go through the iommu. If that's not us, | ||
315 | * find the next upstream device and test ACS up to the root bus. | ||
316 | * Finding the next device may require skipping virtual buses. | ||
317 | */ | ||
308 | while (!pci_is_root_bus(dma_pdev->bus)) { | 318 | while (!pci_is_root_bus(dma_pdev->bus)) { |
309 | if (pci_acs_path_enabled(dma_pdev->bus->self, | 319 | struct pci_bus *bus = dma_pdev->bus; |
310 | NULL, REQ_ACS_FLAGS)) | 320 | |
321 | while (!bus->self) { | ||
322 | if (!pci_is_root_bus(bus)) | ||
323 | bus = bus->parent; | ||
324 | else | ||
325 | goto root_bus; | ||
326 | } | ||
327 | |||
328 | if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) | ||
311 | break; | 329 | break; |
312 | 330 | ||
313 | swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); | 331 | swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); |
314 | } | 332 | } |
315 | 333 | ||
334 | root_bus: | ||
316 | group = iommu_group_get(&dma_pdev->dev); | 335 | group = iommu_group_get(&dma_pdev->dev); |
317 | pci_dev_put(dma_pdev); | 336 | pci_dev_put(dma_pdev); |
318 | if (!group) { | 337 | if (!group) { |