]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/iommu/dmar.c
Merge branches 'arm/exynos', 'arm/omap', 'arm/smmu', 'x86/vt-d', 'x86/amd' and 'core...
[karo-tx-linux.git] / drivers / iommu / dmar.c
index 06d268abe951bebd946deac82cf092f3f7a67ee3..c5c61cabd6e3ea3508c39b7d799476676fb85d32 100644 (file)
@@ -155,6 +155,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
        if (event == BUS_NOTIFY_ADD_DEVICE) {
                for (tmp = dev; tmp; tmp = tmp->bus->self) {
                        level--;
+                       info->path[level].bus = tmp->bus->number;
                        info->path[level].device = PCI_SLOT(tmp->devfn);
                        info->path[level].function = PCI_FUNC(tmp->devfn);
                        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,
        int i;
 
        if (info->bus != bus)
-               return false;
+               goto fallback;
        if (info->level != count)
-               return false;
+               goto fallback;
 
        for (i = 0; i < count; i++) {
                if (path[i].device != info->path[i].device ||
                    path[i].function != info->path[i].function)
-                       return false;
+                       goto fallback;
        }
 
        return true;
+
+fallback:
+
+       if (count != 1)
+               return false;
+
+       i = info->level - 1;
+       if (bus              == info->path[i].bus &&
+           path[0].device   == info->path[i].device &&
+           path[0].function == info->path[i].function) {
+               pr_info(FW_BUG "RMRR entry for device %02x:%02x.%x is broken - applying workaround\n",
+                       bus, path[0].device, path[0].function);
+               return true;
+       }
+
+       return false;
 }
 
 /* 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,
 
        for_each_active_dev_scope(devices, count, index, tmp)
                if (tmp == &info->dev->dev) {
-                       rcu_assign_pointer(devices[index].dev, NULL);
+                       RCU_INIT_POINTER(devices[index].dev, NULL);
                        synchronize_rcu();
                        put_device(tmp);
                        return 1;