diff options
-rw-r--r-- | drivers/pci/setup-bus.c | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index f560814c557c..f76f6e90f3b9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -780,11 +780,65 @@ static void pci_bus_dump_resources(struct pci_bus *bus) | |||
780 | } | 780 | } |
781 | } | 781 | } |
782 | 782 | ||
783 | static int __init pci_bus_get_depth(struct pci_bus *bus) | ||
784 | { | ||
785 | int depth = 0; | ||
786 | struct pci_dev *dev; | ||
787 | |||
788 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
789 | int ret; | ||
790 | struct pci_bus *b = dev->subordinate; | ||
791 | if (!b) | ||
792 | continue; | ||
793 | |||
794 | ret = pci_bus_get_depth(b); | ||
795 | if (ret + 1 > depth) | ||
796 | depth = ret + 1; | ||
797 | } | ||
798 | |||
799 | return depth; | ||
800 | } | ||
801 | static int __init pci_get_max_depth(void) | ||
802 | { | ||
803 | int depth = 0; | ||
804 | struct pci_bus *bus; | ||
805 | |||
806 | list_for_each_entry(bus, &pci_root_buses, node) { | ||
807 | int ret; | ||
808 | |||
809 | ret = pci_bus_get_depth(bus); | ||
810 | if (ret > depth) | ||
811 | depth = ret; | ||
812 | } | ||
813 | |||
814 | return depth; | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * first try will not touch pci bridge res | ||
819 | * second and later try will clear small leaf bridge res | ||
820 | * will stop till to the max deepth if can not find good one | ||
821 | */ | ||
783 | void __init | 822 | void __init |
784 | pci_assign_unassigned_resources(void) | 823 | pci_assign_unassigned_resources(void) |
785 | { | 824 | { |
786 | struct pci_bus *bus; | 825 | struct pci_bus *bus; |
826 | int tried_times = 0; | ||
827 | enum release_type rel_type = leaf_only; | ||
828 | struct resource_list_x head, *list; | ||
829 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
830 | IORESOURCE_PREFETCH; | ||
831 | unsigned long failed_type; | ||
832 | int max_depth = pci_get_max_depth(); | ||
833 | int pci_try_num; | ||
834 | |||
835 | head.next = NULL; | ||
787 | 836 | ||
837 | pci_try_num = max_depth + 1; | ||
838 | printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", | ||
839 | max_depth, pci_try_num); | ||
840 | |||
841 | again: | ||
788 | /* Depth first, calculate sizes and alignments of all | 842 | /* Depth first, calculate sizes and alignments of all |
789 | subordinate buses. */ | 843 | subordinate buses. */ |
790 | list_for_each_entry(bus, &pci_root_buses, node) { | 844 | list_for_each_entry(bus, &pci_root_buses, node) { |
@@ -792,9 +846,65 @@ pci_assign_unassigned_resources(void) | |||
792 | } | 846 | } |
793 | /* Depth last, allocate resources and update the hardware. */ | 847 | /* Depth last, allocate resources and update the hardware. */ |
794 | list_for_each_entry(bus, &pci_root_buses, node) { | 848 | list_for_each_entry(bus, &pci_root_buses, node) { |
795 | pci_bus_assign_resources(bus); | 849 | __pci_bus_assign_resources(bus, &head); |
796 | pci_enable_bridges(bus); | 850 | } |
851 | tried_times++; | ||
852 | |||
853 | /* any device complain? */ | ||
854 | if (!head.next) | ||
855 | goto enable_and_dump; | ||
856 | failed_type = 0; | ||
857 | for (list = head.next; list;) { | ||
858 | failed_type |= list->flags; | ||
859 | list = list->next; | ||
860 | } | ||
861 | /* | ||
862 | * io port are tight, don't try extra | ||
863 | * or if reach the limit, don't want to try more | ||
864 | */ | ||
865 | failed_type &= type_mask; | ||
866 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { | ||
867 | free_failed_list(&head); | ||
868 | goto enable_and_dump; | ||
869 | } | ||
870 | |||
871 | printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", | ||
872 | tried_times + 1); | ||
873 | |||
874 | /* third times and later will not check if it is leaf */ | ||
875 | if ((tried_times + 1) > 2) | ||
876 | rel_type = whole_subtree; | ||
877 | |||
878 | /* | ||
879 | * Try to release leaf bridge's resources that doesn't fit resource of | ||
880 | * child device under that bridge | ||
881 | */ | ||
882 | for (list = head.next; list;) { | ||
883 | bus = list->dev->bus; | ||
884 | pci_bus_release_bridge_resources(bus, list->flags & type_mask, | ||
885 | rel_type); | ||
886 | list = list->next; | ||
797 | } | 887 | } |
888 | /* restore size and flags */ | ||
889 | for (list = head.next; list;) { | ||
890 | struct resource *res = list->res; | ||
891 | |||
892 | res->start = list->start; | ||
893 | res->end = list->end; | ||
894 | res->flags = list->flags; | ||
895 | if (list->dev->subordinate) | ||
896 | res->flags = 0; | ||
897 | |||
898 | list = list->next; | ||
899 | } | ||
900 | free_failed_list(&head); | ||
901 | |||
902 | goto again; | ||
903 | |||
904 | enable_and_dump: | ||
905 | /* Depth last, update the hardware. */ | ||
906 | list_for_each_entry(bus, &pci_root_buses, node) | ||
907 | pci_enable_bridges(bus); | ||
798 | 908 | ||
799 | /* dump the resource on buses */ | 909 | /* dump the resource on buses */ |
800 | list_for_each_entry(bus, &pci_root_buses, node) { | 910 | list_for_each_entry(bus, &pci_root_buses, node) { |