diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-01-22 04:02:20 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-02-22 19:17:19 -0500 |
commit | 5009b46025acb2d3955d2c93574604fba667ef39 (patch) | |
tree | 13c9822a92c3b797364313f1e52856caf6ab67c3 | |
parent | ba02b242bbf8e4e1bc63d62e8ccec33b4e5ea132 (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>
-rw-r--r-- | drivers/pci/setup-bus.c | 82 |
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 | } |
605 | EXPORT_SYMBOL(pci_bus_assign_resources); | 605 | EXPORT_SYMBOL(pci_bus_assign_resources); |
606 | 606 | ||
607 | static 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 | |||
649 | enum 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 | */ | ||
657 | static 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 | |||
607 | static void pci_bus_dump_res(struct pci_bus *bus) | 689 | static void pci_bus_dump_res(struct pci_bus *bus) |
608 | { | 690 | { |
609 | int i; | 691 | int i; |