From a53ed45d0755ecb4d682f73dabfa04e8c78ea73e Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 22 Jan 2010 01:02:20 -0800 Subject: [PATCH] --- yaml --- r: 180974 b: refs/heads/master c: 5009b46025acb2d3955d2c93574604fba667ef39 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/pci/setup-bus.c | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 8d007a75f822..7d67793714fc 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ba02b242bbf8e4e1bc63d62e8ccec33b4e5ea132 +refs/heads/master: 5009b46025acb2d3955d2c93574604fba667ef39 diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 52fbd426a1c7..7371a5479a99 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -604,6 +604,88 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_assign_resources); +static void pci_bridge_release_resources(struct pci_bus *bus, + unsigned long type) +{ + int idx; + bool changed = false; + struct pci_dev *dev; + struct resource *r; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | + IORESOURCE_PREFETCH; + + dev = bus->self; + for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END; + idx++) { + r = &dev->resource[idx]; + if ((r->flags & type_mask) != type) + continue; + if (!r->parent) + continue; + /* + * if there are children under that, we should release them + * all + */ + release_child_resources(r); + if (!release_resource(r)) { + dev_printk(KERN_DEBUG, &dev->dev, + "resource %d %pR released\n", idx, r); + /* keep the old size */ + r->end = resource_size(r) - 1; + r->start = 0; + r->flags = 0; + changed = true; + } + } + + if (changed) { + /* avoiding touch the one without PREF */ + if (type & IORESOURCE_PREFETCH) + type = IORESOURCE_PREFETCH; + __pci_setup_bridge(bus, type); + } +} + +enum release_type { + leaf_only, + whole_subtree, +}; +/* + * try to release pci bridge resources that is from leaf bridge, + * so we can allocate big new one later + */ +static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus, + unsigned long type, + enum release_type rel_type) +{ + 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; + + is_leaf_bridge = false; + + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + continue; + + if (rel_type == whole_subtree) + pci_bus_release_bridge_resources(b, type, + whole_subtree); + } + + if (pci_is_root_bus(bus)) + return; + + if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI) + return; + + if ((rel_type == whole_subtree) || is_leaf_bridge) + pci_bridge_release_resources(bus, type); +} + static void pci_bus_dump_res(struct pci_bus *bus) { int i;