aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2010-01-22 04:02:20 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-22 19:17:19 -0500
commit5009b46025acb2d3955d2c93574604fba667ef39 (patch)
tree13c9822a92c3b797364313f1e52856caf6ab67c3 /drivers/pci/setup-bus.c
parentba02b242bbf8e4e1bc63d62e8ccec33b4e5ea132 (diff)
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>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 52fbd426a1c7..7371a5479a99 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -604,6 +604,88 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
604} 604}
605EXPORT_SYMBOL(pci_bus_assign_resources); 605EXPORT_SYMBOL(pci_bus_assign_resources);
606 606
607static void pci_bridge_release_resources(struct pci_bus *bus,
608 unsigned long type)
609{
610 int idx;
611 bool changed = false;
612 struct pci_dev *dev;
613 struct resource *r;
614 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
615 IORESOURCE_PREFETCH;
616
617 dev = bus->self;
618 for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END;
619 idx++) {
620 r = &dev->resource[idx];
621 if ((r->flags & type_mask) != type)
622 continue;
623 if (!r->parent)
624 continue;
625 /*
626 * if there are children under that, we should release them
627 * all
628 */
629 release_child_resources(r);
630 if (!release_resource(r)) {
631 dev_printk(KERN_DEBUG, &dev->dev,
632 "resource %d %pR released\n", idx, r);
633 /* keep the old size */
634 r->end = resource_size(r) - 1;
635 r->start = 0;
636 r->flags = 0;
637 changed = true;
638 }
639 }
640
641 if (changed) {
642 /* avoiding touch the one without PREF */
643 if (type & IORESOURCE_PREFETCH)
644 type = IORESOURCE_PREFETCH;
645 __pci_setup_bridge(bus, type);
646 }
647}
648
649enum release_type {
650 leaf_only,
651 whole_subtree,
652};
653/*
654 * try to release pci bridge resources that is from leaf bridge,
655 * so we can allocate big new one later
656 */
657static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus,
658 unsigned long type,
659 enum release_type rel_type)
660{
661 struct pci_dev *dev;
662 bool is_leaf_bridge = true;
663
664 list_for_each_entry(dev, &bus->devices, bus_list) {
665 struct pci_bus *b = dev->subordinate;
666 if (!b)
667 continue;
668
669 is_leaf_bridge = false;
670
671 if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
672 continue;
673
674 if (rel_type == whole_subtree)
675 pci_bus_release_bridge_resources(b, type,
676 whole_subtree);
677 }
678
679 if (pci_is_root_bus(bus))
680 return;
681
682 if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI)
683 return;
684
685 if ((rel_type == whole_subtree) || is_leaf_bridge)
686 pci_bridge_release_resources(bus, type);
687}
688
607static void pci_bus_dump_res(struct pci_bus *bus) 689static void pci_bus_dump_res(struct pci_bus *bus)
608{ 690{
609 int i; 691 int i;