diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-06 10:50:14 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-07 04:06:59 -0400 |
commit | 26018874e3584f1658570d41d57d4c34f6a53aa0 (patch) | |
tree | cc59523e0e25e6212cae86a93f90e2023f334633 /arch/x86 | |
parent | 27c2127a15d340706c0aa84e311188a14468d841 (diff) |
x86/amd-iommu: Fix boot crash with hidden PCI devices
Some PCIe cards ship with a PCI-PCIe bridge which is not
visible as a PCI device in Linux. But the device-id of the
bridge is present in the IOMMU tables which causes a boot
crash in the IOMMU driver.
This patch fixes by removing these cards from the IOMMU
handling. This is a pure -stable fix, a real fix to handle
this situation appriatly will follow for the next merge
window.
Cc: stable@kernel.org # > 2.6.32
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b2c309b07427..7c3a95e54ec5 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -155,6 +155,10 @@ static int iommu_init_device(struct device *dev) | |||
155 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); | 155 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); |
156 | if (pdev) | 156 | if (pdev) |
157 | dev_data->alias = &pdev->dev; | 157 | dev_data->alias = &pdev->dev; |
158 | else { | ||
159 | kfree(dev_data); | ||
160 | return -ENOTSUPP; | ||
161 | } | ||
158 | 162 | ||
159 | atomic_set(&dev_data->bind, 0); | 163 | atomic_set(&dev_data->bind, 0); |
160 | 164 | ||
@@ -164,6 +168,20 @@ static int iommu_init_device(struct device *dev) | |||
164 | return 0; | 168 | return 0; |
165 | } | 169 | } |
166 | 170 | ||
171 | static void iommu_ignore_device(struct device *dev) | ||
172 | { | ||
173 | u16 devid, alias; | ||
174 | |||
175 | devid = get_device_id(dev); | ||
176 | alias = amd_iommu_alias_table[devid]; | ||
177 | |||
178 | memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry)); | ||
179 | memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry)); | ||
180 | |||
181 | amd_iommu_rlookup_table[devid] = NULL; | ||
182 | amd_iommu_rlookup_table[alias] = NULL; | ||
183 | } | ||
184 | |||
167 | static void iommu_uninit_device(struct device *dev) | 185 | static void iommu_uninit_device(struct device *dev) |
168 | { | 186 | { |
169 | kfree(dev->archdata.iommu); | 187 | kfree(dev->archdata.iommu); |
@@ -193,7 +211,9 @@ int __init amd_iommu_init_devices(void) | |||
193 | continue; | 211 | continue; |
194 | 212 | ||
195 | ret = iommu_init_device(&pdev->dev); | 213 | ret = iommu_init_device(&pdev->dev); |
196 | if (ret) | 214 | if (ret == -ENOTSUPP) |
215 | iommu_ignore_device(&pdev->dev); | ||
216 | else if (ret) | ||
197 | goto out_free; | 217 | goto out_free; |
198 | } | 218 | } |
199 | 219 | ||