From: Murillo Fernandes Bernardes Current code assumed that devices were directly connected to a Calgary bridge, as it tried to get the iommu table directly from the parent bus controller. When we have another bridge between the Calgary/CalIOC2 bridge and the device we should look upwards until we get to the top (Calgary/CalIOC2 bridge), where the iommu table resides. Signed-off-by: Murillo Fernandes Bernardes Signed-off-by: Muli Ben-Yehuda Cc: Andi Kleen Signed-off-by: Andrew Morton --- arch/x86_64/kernel/pci-calgary.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff -puN arch/x86_64/kernel/pci-calgary.c~calgary-fix-mis-handled-pci-topology arch/x86_64/kernel/pci-calgary.c --- a/arch/x86_64/kernel/pci-calgary.c~calgary-fix-mis-handled-pci-topology +++ a/arch/x86_64/kernel/pci-calgary.c @@ -367,16 +367,15 @@ static inline struct iommu_table *find_i pdev = to_pci_dev(dev); - /* is the device behind a bridge? */ - if (unlikely(pdev->bus->parent)) - pbus = pdev->bus->parent; - else - pbus = pdev->bus; + pbus = pdev->bus; + + /* is the device behind a bridge? Look for the root bus */ + while (pbus->parent) + pbus = pbus->parent; tbl = pci_iommu(pbus); - BUG_ON(pdev->bus->parent && - (tbl->it_busno != pdev->bus->parent->number)); + BUG_ON(tbl && (tbl->it_busno != pbus->number)); return tbl; } _