diff options
| -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) { |
