nfs: new subdir Documentation/filesystems/nfs
[safe/jmp/linux-2.6] / drivers / pci / setup-bus.c
index 7c443b4..0959430 100644 (file)
@@ -299,8 +299,17 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
                r = bus->resource[i];
                if (r == &ioport_resource || r == &iomem_resource)
                        continue;
-               if (r && (r->flags & type_mask) == type && !r->parent)
-                       return r;
+               if (r && (r->flags & type_mask) == type) {
+                       if (!r->parent)
+                               return r;
+                       /*
+                        * if there is no child under that, we should release
+                        * and use it. don't need to reset it, pbus_size_* will
+                        * set it again
+                        */
+                       if (!r->child && !release_resource(r))
+                               return r;
+               }
        }
        return NULL;
 }
@@ -309,7 +318,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
    since these windows have 4K granularity and the IO ranges
    of non-bridge PCI devices are limited to 256 bytes.
    We must be careful with the ISA aliasing though. */
-static void pbus_size_io(struct pci_bus *bus)
+static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -336,6 +345,8 @@ static void pbus_size_io(struct pci_bus *bus)
                                size1 += r_size;
                }
        }
+       if (size < min_size)
+               size = min_size;
 /* To be fixed in 2.5: we should have sort of HAVE_ISA
    flag in the struct pci_bus. */
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
@@ -354,7 +365,8 @@ static void pbus_size_io(struct pci_bus *bus)
 
 /* Calculate the size of the bus and minimal alignment which
    guarantees that all child resources fit in this size. */
-static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
+                        unsigned long type, resource_size_t min_size)
 {
        struct pci_dev *dev;
        resource_size_t min_align, align, size;
@@ -404,6 +416,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
                        mem64_mask &= r->flags & IORESOURCE_MEM_64;
                }
        }
+       if (size < min_size)
+               size = min_size;
 
        align = 0;
        min_align = 0;
@@ -483,6 +497,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
+       resource_size_t min_mem_size = 0, min_io_size = 0;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                struct pci_bus *b = dev->subordinate;
@@ -512,8 +527,12 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 
        case PCI_CLASS_BRIDGE_PCI:
                pci_bridge_check_ranges(bus);
+               if (bus->self->is_hotplug_bridge) {
+                       min_io_size  = pci_hotplug_io_size;
+                       min_mem_size = pci_hotplug_mem_size;
+               }
        default:
-               pbus_size_io(bus);
+               pbus_size_io(bus, min_io_size);
                /* If the bridge supports prefetchable range, size it
                   separately. If it doesn't, or its prefetchable window
                   has already been allocated by arch code, try
@@ -521,9 +540,11 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
                   resources. */
                mask = IORESOURCE_MEM;
                prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-               if (pbus_size_mem(bus, prefmask, prefmask))
+               if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size))
                        mask = prefmask; /* Success, size non-prefetch only. */
-               pbus_size_mem(bus, mask, IORESOURCE_MEM);
+               else
+                       min_mem_size += min_mem_size;
+               pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size);
                break;
        }
 }