===================================================================
@@ -322,33 +322,54 @@ static void pci_bridge_check_ranges(stru
}
}
-/* Helper function for sizing routines: find first available
- bus resource of a given type. Note: we intentionally skip
- the bus resources which have already been assigned (that is,
- have non-NULL parent resource). */
-static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
+void pci_bridge_release_not_used_res(struct pci_bus *bus)
{
int i;
struct resource *r;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ /* for pci bridges res only */
+ for (i = 0; i < 3; i++) {
r = bus->resource[i];
- if (r == &ioport_resource || r == &iomem_resource)
- continue;
- if (r && (r->flags & type_mask) == type) {
+ if (r && (r->flags & type_mask)) {
if (!r->parent)
- return r;
+ continue;
/*
* 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;
+ dev_printk(KERN_DEBUG, &bus->dev,
+ "resource %d %s %pR released\n", i,
+ (r->flags & IORESOURCE_IO) ? "io: " :
+ ((r->flags & IORESOURCE_PREFETCH)?
+ "pref mem":"mem:"),
+ r);
}
}
+}
+EXPORT_SYMBOL(pci_bridge_release_not_used_res);
+
+/* Helper function for sizing routines: find first available
+ bus resource of a given type. Note: we intentionally skip
+ the bus resources which have already been assigned (that is,
+ have non-NULL parent resource). */
+static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
+{
+ int i;
+ struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ r = bus->resource[i];
+ if (r == &ioport_resource || r == &iomem_resource)
+ continue;
+ if (r && (r->flags & type_mask) == type && !r->parent)
+ return r;
+ }
return NULL;
}
@@ -588,6 +609,41 @@ void __ref pci_bus_size_bridges(struct p
}
EXPORT_SYMBOL(pci_bus_size_bridges);
+static void pci_bus_release_bridges_not_used_res(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ switch (dev->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ pci_bus_release_bridges_not_used_res(b);
+ break;
+ }
+ }
+
+ /* The root bus? */
+ if (!bus->self)
+ return;
+
+ switch (bus->self->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ pci_bridge_release_not_used_res(bus);
+ break;
+ }
+}
+
void __ref pci_bridge_assign_resources(const struct pci_dev *bridge)
{
struct pci_bus *b;
@@ -687,6 +743,11 @@ pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
+ /* Try to release bridge resources, that there is not child under it */
+ list_for_each_entry(bus, &pci_root_buses, node) {
+ pci_bus_release_bridges_not_used_res(bus);
+ }
+
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) {
===================================================================
@@ -171,6 +171,7 @@ int pciehp_unconfigure_device(struct slo
}
pci_dev_put(temp);
}
+ pci_bridge_release_not_used_res(parent);
return rc;
}
===================================================================
@@ -759,6 +759,7 @@ int pci_vpd_truncate(struct pci_dev *dev
void pci_bridge_assign_resources(const struct pci_dev *bridge);
void pci_bus_assign_resources(const struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus);
+void pci_bridge_release_not_used_res(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
void pdev_enable_device(struct pci_dev *);