]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/probe.c
PCI: Unset resource if initial BAR value is invalid
[karo-tx-linux.git] / drivers / pci / probe.c
index 631aeb7d2d2dd548d7db2ccfeae6b7518f0fc483..fe5b50bd75367898d44ad04b49152bec365f102a 100644 (file)
@@ -170,7 +170,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 {
        u32 l, sz, mask;
        u16 orig_cmd;
-       struct pci_bus_region region;
+       struct pci_bus_region region, inverted_region;
        bool bar_too_big = false, bar_disabled = false;
 
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        pci_write_config_dword(dev, pos + 4, 0);
                        region.start = 0;
                        region.end = sz64;
-                       pcibios_bus_to_resource(dev, res, &region);
                        bar_disabled = true;
                } else {
                        region.start = l64;
                        region.end = l64 + sz64;
-                       pcibios_bus_to_resource(dev, res, &region);
                }
        } else {
                sz = pci_size(l, sz, mask);
@@ -265,7 +263,28 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 
                region.start = l;
                region.end = l + sz;
-               pcibios_bus_to_resource(dev, res, &region);
+       }
+
+       pcibios_bus_to_resource(dev, res, &region);
+       pcibios_resource_to_bus(dev, &inverted_region, res);
+
+       /*
+        * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is
+        * the corresponding resource address (the physical address used by
+        * the CPU.  Converting that resource address back to a bus address
+        * should yield the original BAR value:
+        *
+        *     resource_to_bus(bus_to_resource(A)) == A
+        *
+        * If it doesn't, CPU accesses to "bus_to_resource(A)" will not
+        * be claimed by the device.
+        */
+       if (inverted_region.start != region.start) {
+               dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n",
+                        pos, &region.start);
+               res->flags |= IORESOURCE_UNSET;
+               res->end -= res->start;
+               res->start = 0;
        }
 
        goto out;
@@ -278,9 +297,9 @@ out:
                pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
 
        if (bar_too_big)
-               dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos);
+               dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos);
        if (res->flags && !bar_disabled)
-               dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
+               dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res);
 
        return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
 }
@@ -1341,7 +1360,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        list_add_tail(&dev->bus_list, &bus->devices);
        up_write(&pci_bus_sem);
 
-       pci_fixup_device(pci_fixup_final, dev);
        ret = pcibios_add_device(dev);
        WARN_ON(ret < 0);