===================================================================
@@ -319,6 +319,42 @@ static void pci_bridge_check_ranges(stru
}
}
+void pci_bridge_release_not_used_res(struct pci_bus *bus)
+{
+ int idx;
+ bool changed = false;
+ struct pci_dev *dev;
+ struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ /* for pci bridges res only */
+ dev = bus->self;
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
+ idx++) {
+ r = &dev->resource[idx];
+ if (r->flags & type_mask) {
+ if (!r->parent)
+ continue;
+ /*
+ * if there is no child under that, we should release
+ * and use it.
+ */
+ if (!r->child && !release_resource(r)) {
+ dev_info(&dev->dev,
+ "resource %d %pRt released\n",
+ idx, r);
+ r->flags = 0;
+ changed = true;
+ }
+ }
+ }
+
+ if (changed)
+ pci_setup_bridge(bus);
+}
+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,
@@ -576,6 +612,48 @@ void __ref pci_bus_size_bridges(struct p
}
EXPORT_SYMBOL(pci_bus_size_bridges);
+
+/* only release those resources that is on leaf bridge */
+void __ref pci_bus_release_bridges_not_used_res(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ bool is_leaf_bridge = true;
+
+ 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:
+ is_leaf_bridge = false;
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ is_leaf_bridge = false;
+ 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:
+ if (is_leaf_bridge)
+ pci_bridge_release_not_used_res(bus);
+ break;
+ }
+}
+EXPORT_SYMBOL(pci_bus_release_bridges_not_used_res);
+
void __ref pci_bridge_assign_resources(const struct pci_dev *bridge)
{
struct pci_bus *b;
@@ -644,7 +722,8 @@ static void pci_bus_dump_res(struct pci_
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
struct resource *res = bus->resource[i];
- if (!res || !res->end)
+
+ if (!res || !res->end || !res->flags)
continue;
dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pRt\n", i, res);
===================================================================
@@ -98,6 +98,7 @@ int pciehp_configure_device(struct slot
pci_dev_put(dev);
}
+ pci_bridge_release_not_used_res(parent);
pci_bus_size_bridges(parent);
pci_clear_master(bridge);
pci_bridge_assign_resources(bridge);
@@ -171,6 +172,7 @@ int pciehp_unconfigure_device(struct slo
}
pci_dev_put(temp);
}
+ pci_bridge_release_not_used_res(parent);
return rc;
}
===================================================================
@@ -759,6 +759,8 @@ 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_bus_release_bridges_not_used_res(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 *);
===================================================================
@@ -194,6 +194,7 @@ static void __init pcibios_allocate_reso
static int __init pcibios_assign_resources(void)
{
struct pci_dev *dev = NULL;
+ struct pci_bus *bus;
struct resource *r;
if (!(pci_probe & PCI_ASSIGN_ROMS)) {
@@ -213,6 +214,11 @@ static int __init pcibios_assign_resourc
}
}
+ /* 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);
+ }
+
pci_assign_unassigned_resources();
return 0;