aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-09-22 10:30:22 -0400
committerJoerg Roedel <jroedel@suse.de>2014-10-02 06:12:35 -0400
commit80f7b3d1b1f4ec6c80fa3b40c7c9a419e28b0897 (patch)
tree609362f89702c8a2933a691df949378ca1c50974
parent57384592c43375d2c9a14d82aebbdc95fdda9e9d (diff)
iommu/vt-d: Work around broken RMRR firmware entries
The VT-d specification states that an RMRR entry in the DMAR table needs to specify the full path to the device. This is also how newer Linux kernels implement it. Unfortunatly older drivers just match for the target device and not the full path to the device, so that BIOS vendors implement that behavior into their BIOSes to make them work with older Linux kernels. But those RMRR entries break on newer Linux kernels. Work around this issue by adding a fall-back into the RMRR matching code to match those old RMRR entries too. Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/dmar.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 68da1ab0f2cd..b3774ef3f255 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -178,17 +178,33 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,
178 int i; 178 int i;
179 179
180 if (info->bus != bus) 180 if (info->bus != bus)
181 return false; 181 goto fallback;
182 if (info->level != count) 182 if (info->level != count)
183 return false; 183 goto fallback;
184 184
185 for (i = 0; i < count; i++) { 185 for (i = 0; i < count; i++) {
186 if (path[i].device != info->path[i].device || 186 if (path[i].device != info->path[i].device ||
187 path[i].function != info->path[i].function) 187 path[i].function != info->path[i].function)
188 return false; 188 goto fallback;
189 } 189 }
190 190
191 return true; 191 return true;
192
193fallback:
194
195 if (count != 1)
196 return false;
197
198 i = info->level - 1;
199 if (bus == info->path[i].bus &&
200 path[0].device == info->path[i].device &&
201 path[0].function == info->path[i].function) {
202 pr_info(FW_BUG "RMRR entry for device %02x:%02x.%x is broken - applying workaround\n",
203 bus, path[0].device, path[0].function);
204 return true;
205 }
206
207 return false;
192} 208}
193 209
194/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */ 210/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */