diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-07-04 14:11:08 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-07-04 14:19:10 -0400 |
commit | 3dfc813d94bba2046c6aed216e0fd69ac93a8e03 (patch) | |
tree | 227c2cecfdab3b9bb86508e9d8b6de51e68bfa70 /drivers/pci/intel-iommu.c | |
parent | 6941af2810c6fc970b88f7c0d52ba4e286acbee5 (diff) |
intel-iommu: Don't use identity mapping for PCI devices behind bridges
Our current strategy for pass-through mode is to put all devices into
the 1:1 domain at startup (which is before we know what their dma_mask
will be), and only _later_ take them out of that domain, if it turns out
that they really can't address all of memory.
However, when there are a bunch of PCI devices behind a bridge, they all
end up with the same source-id on their DMA transactions, and hence in
the same IOMMU domain. This means that we _can't_ easily move them from
the 1:1 domain into their own domain at runtime, because there might be DMA
in-flight from their siblings.
So we have to adjust our pass-through strategy: For PCI devices not on
the root bus, and for the bridges which will take responsibility for
their transactions, we have to start up _out_ of the 1:1 domain, just in
case.
This fixes the BUG() we see when we have 32-bit-capable devices behind a
PCI-PCI bridge, and use the software identity mapping.
It does mean that we might end up using 'normal' mapping mode for some
devices which could actually live with the faster 1:1 mapping -- but
this is only for PCI devices behind bridges, which presumably aren't the
devices for which people are most concerned about performance.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r-- | drivers/pci/intel-iommu.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index f9fc4f3bfa3f..360fb67a30d7 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -2122,6 +2122,36 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup) | |||
2122 | if (iommu_identity_mapping == 2) | 2122 | if (iommu_identity_mapping == 2) |
2123 | return IS_GFX_DEVICE(pdev); | 2123 | return IS_GFX_DEVICE(pdev); |
2124 | 2124 | ||
2125 | /* | ||
2126 | * We want to start off with all devices in the 1:1 domain, and | ||
2127 | * take them out later if we find they can't access all of memory. | ||
2128 | * | ||
2129 | * However, we can't do this for PCI devices behind bridges, | ||
2130 | * because all PCI devices behind the same bridge will end up | ||
2131 | * with the same source-id on their transactions. | ||
2132 | * | ||
2133 | * Practically speaking, we can't change things around for these | ||
2134 | * devices at run-time, because we can't be sure there'll be no | ||
2135 | * DMA transactions in flight for any of their siblings. | ||
2136 | * | ||
2137 | * So PCI devices (unless they're on the root bus) as well as | ||
2138 | * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of | ||
2139 | * the 1:1 domain, just in _case_ one of their siblings turns out | ||
2140 | * not to be able to map all of memory. | ||
2141 | */ | ||
2142 | if (!pdev->is_pcie) { | ||
2143 | if (!pci_is_root_bus(pdev->bus)) | ||
2144 | return 0; | ||
2145 | if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) | ||
2146 | return 0; | ||
2147 | } else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | ||
2148 | return 0; | ||
2149 | |||
2150 | /* | ||
2151 | * At boot time, we don't yet know if devices will be 64-bit capable. | ||
2152 | * Assume that they will -- if they turn out not to be, then we can | ||
2153 | * take them out of the 1:1 domain later. | ||
2154 | */ | ||
2125 | if (!startup) | 2155 | if (!startup) |
2126 | return pdev->dma_mask > DMA_BIT_MASK(32); | 2156 | return pdev->dma_mask > DMA_BIT_MASK(32); |
2127 | 2157 | ||