aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/dmar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/dmar.c')
-rw-r--r--drivers/iommu/dmar.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 06d268abe951..c5c61cabd6e3 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -155,6 +155,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
155 if (event == BUS_NOTIFY_ADD_DEVICE) { 155 if (event == BUS_NOTIFY_ADD_DEVICE) {
156 for (tmp = dev; tmp; tmp = tmp->bus->self) { 156 for (tmp = dev; tmp; tmp = tmp->bus->self) {
157 level--; 157 level--;
158 info->path[level].bus = tmp->bus->number;
158 info->path[level].device = PCI_SLOT(tmp->devfn); 159 info->path[level].device = PCI_SLOT(tmp->devfn);
159 info->path[level].function = PCI_FUNC(tmp->devfn); 160 info->path[level].function = PCI_FUNC(tmp->devfn);
160 if (pci_is_root_bus(tmp->bus)) 161 if (pci_is_root_bus(tmp->bus))
@@ -177,17 +178,33 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,
177 int i; 178 int i;
178 179
179 if (info->bus != bus) 180 if (info->bus != bus)
180 return false; 181 goto fallback;
181 if (info->level != count) 182 if (info->level != count)
182 return false; 183 goto fallback;
183 184
184 for (i = 0; i < count; i++) { 185 for (i = 0; i < count; i++) {
185 if (path[i].device != info->path[i].device || 186 if (path[i].device != info->path[i].device ||
186 path[i].function != info->path[i].function) 187 path[i].function != info->path[i].function)
187 return false; 188 goto fallback;
188 } 189 }
189 190
190 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;
191} 208}
192 209
193/* 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 */
@@ -247,7 +264,7 @@ int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, u16 segment,
247 264
248 for_each_active_dev_scope(devices, count, index, tmp) 265 for_each_active_dev_scope(devices, count, index, tmp)
249 if (tmp == &info->dev->dev) { 266 if (tmp == &info->dev->dev) {
250 rcu_assign_pointer(devices[index].dev, NULL); 267 RCU_INIT_POINTER(devices[index].dev, NULL);
251 synchronize_rcu(); 268 synchronize_rcu();
252 put_device(tmp); 269 put_device(tmp);
253 return 1; 270 return 1;