Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[cascardo/linux.git] / drivers / pci / probe.c
index a723b2b..46ada5c 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;
 }
@@ -451,20 +470,21 @@ void pci_read_bridge_bases(struct pci_bus *child)
        }
 }
 
-static struct pci_bus * pci_alloc_bus(void)
+static struct pci_bus *pci_alloc_bus(void)
 {
        struct pci_bus *b;
 
        b = kzalloc(sizeof(*b), GFP_KERNEL);
-       if (b) {
-               INIT_LIST_HEAD(&b->node);
-               INIT_LIST_HEAD(&b->children);
-               INIT_LIST_HEAD(&b->devices);
-               INIT_LIST_HEAD(&b->slots);
-               INIT_LIST_HEAD(&b->resources);
-               b->max_bus_speed = PCI_SPEED_UNKNOWN;
-               b->cur_bus_speed = PCI_SPEED_UNKNOWN;
-       }
+       if (!b)
+               return NULL;
+
+       INIT_LIST_HEAD(&b->node);
+       INIT_LIST_HEAD(&b->children);
+       INIT_LIST_HEAD(&b->devices);
+       INIT_LIST_HEAD(&b->slots);
+       INIT_LIST_HEAD(&b->resources);
+       b->max_bus_speed = PCI_SPEED_UNKNOWN;
+       b->cur_bus_speed = PCI_SPEED_UNKNOWN;
        return b;
 }
 
@@ -485,11 +505,11 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
        struct pci_host_bridge *bridge;
 
        bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
-       if (bridge) {
-               INIT_LIST_HEAD(&bridge->windows);
-               bridge->bus = b;
-       }
+       if (!bridge)
+               return NULL;
 
+       INIT_LIST_HEAD(&bridge->windows);
+       bridge->bus = b;
        return bridge;
 }
 
@@ -1144,6 +1164,7 @@ static void pci_release_dev(struct device *dev)
        pci_dev = to_pci_dev(dev);
        pci_release_capabilities(pci_dev);
        pci_release_of_node(pci_dev);
+       pcibios_release_device(pci_dev);
        pci_bus_put(pci_dev->bus);
        kfree(pci_dev);
 }