diff options
Diffstat (limited to 'drivers/iommu/dmar.c')
| -rw-r--r-- | drivers/iommu/dmar.c | 25 |
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 | |||
| 193 | fallback: | ||
| 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; |
