diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-08-23 17:02:42 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-08-23 17:02:42 +0200 |
commit | 1e72fe1fca4490474984d6356bbf66e2daa89f73 (patch) | |
tree | 12d95820cbb2083a6c78cfe550a0f9b20b1246eb /drivers/iommu/amd_iommu.c | |
parent | 8a211d362cc94df2bb42323ab13d258650529bec (diff) | |
parent | a46d2619d7180bda12bad2bf15bbd0731dfc2dcf (diff) |
Merge branch 'imx/fixes-for-3.6' of git://git.linaro.org/people/shawnguo/linux-2.6 into fixes
* 'imx/fixes-for-3.6' of git://git.linaro.org/people/shawnguo/linux-2.6:
ARM: dts: imx51-babbage: fix esdhc cd/wp properties
ARM: imx6: spin the cpu until hardware takes it down
ARM i.MX6q: Add virtual 1/3.5 dividers in the LDB clock path
Also updates to Linux 3.6-rc2
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-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 6d1cbdfc9b2..b64502dfa9f 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) } else dma_pdev = pci_dev_get(pdev); + /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); + /* + * If it's a multifunction device that does not support our + * required ACS flags, add to the same group as function 0. + */ if (dma_pdev->multifunction && !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) swap_pci_ref(&dma_pdev, @@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev) PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 0))); + /* + * Devices on the root bus go through the iommu. If that's not us, + * find the next upstream device and test ACS up to the root bus. + * Finding the next device may require skipping virtual buses. + */ while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) + struct pci_bus *bus = dma_pdev->bus; + + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + goto root_bus; + } + + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); + swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } +root_bus: group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) { |