PCI: add pci_bridge_release_resources and pci_bus_release_bridge_resources
We use this in later patches to free resrouce ranges for reassignment in an effort to support a wider variety of PCI topologies. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Reviewed-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
parent
ba02b242bb
commit
5009b46025
|
@ -604,6 +604,88 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_bus_assign_resources);
|
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)
|
static void pci_bus_dump_res(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
Loading…
Reference in New Issue