diff options
-rw-r--r-- | drivers/pci/setup-bus.c | 125 |
1 files changed, 117 insertions, 8 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ebf51ad1b714..7a65db400253 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -991,30 +991,139 @@ static void pci_bus_dump_resources(struct pci_bus *bus) | |||
991 | } | 991 | } |
992 | } | 992 | } |
993 | 993 | ||
994 | static int __init pci_bus_get_depth(struct pci_bus *bus) | ||
995 | { | ||
996 | int depth = 0; | ||
997 | struct pci_dev *dev; | ||
998 | |||
999 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
1000 | int ret; | ||
1001 | struct pci_bus *b = dev->subordinate; | ||
1002 | if (!b) | ||
1003 | continue; | ||
1004 | |||
1005 | ret = pci_bus_get_depth(b); | ||
1006 | if (ret + 1 > depth) | ||
1007 | depth = ret + 1; | ||
1008 | } | ||
1009 | |||
1010 | return depth; | ||
1011 | } | ||
1012 | static int __init pci_get_max_depth(void) | ||
1013 | { | ||
1014 | int depth = 0; | ||
1015 | struct pci_bus *bus; | ||
1016 | |||
1017 | list_for_each_entry(bus, &pci_root_buses, node) { | ||
1018 | int ret; | ||
1019 | |||
1020 | ret = pci_bus_get_depth(bus); | ||
1021 | if (ret > depth) | ||
1022 | depth = ret; | ||
1023 | } | ||
1024 | |||
1025 | return depth; | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
1029 | * first try will not touch pci bridge res | ||
1030 | * second and later try will clear small leaf bridge res | ||
1031 | * will stop till to the max deepth if can not find good one | ||
1032 | */ | ||
994 | void __init | 1033 | void __init |
995 | pci_assign_unassigned_resources(void) | 1034 | pci_assign_unassigned_resources(void) |
996 | { | 1035 | { |
997 | struct pci_bus *bus; | 1036 | struct pci_bus *bus; |
998 | struct resource_list_x add_list; /* list of resources that | 1037 | struct resource_list_x add_list; /* list of resources that |
999 | want additional resources */ | 1038 | want additional resources */ |
1039 | int tried_times = 0; | ||
1040 | enum release_type rel_type = leaf_only; | ||
1041 | struct resource_list_x head, *list; | ||
1042 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
1043 | IORESOURCE_PREFETCH; | ||
1044 | unsigned long failed_type; | ||
1045 | int max_depth = pci_get_max_depth(); | ||
1046 | int pci_try_num; | ||
1047 | |||
1048 | |||
1049 | head.next = NULL; | ||
1000 | add_list.next = NULL; | 1050 | add_list.next = NULL; |
1051 | |||
1052 | pci_try_num = max_depth + 1; | ||
1053 | printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", | ||
1054 | max_depth, pci_try_num); | ||
1055 | |||
1056 | again: | ||
1001 | /* Depth first, calculate sizes and alignments of all | 1057 | /* Depth first, calculate sizes and alignments of all |
1002 | subordinate buses. */ | 1058 | subordinate buses. */ |
1003 | list_for_each_entry(bus, &pci_root_buses, node) { | 1059 | list_for_each_entry(bus, &pci_root_buses, node) |
1004 | __pci_bus_size_bridges(bus, &add_list); | 1060 | __pci_bus_size_bridges(bus, &add_list); |
1005 | } | ||
1006 | 1061 | ||
1007 | /* Depth last, allocate resources and update the hardware. */ | 1062 | /* Depth last, allocate resources and update the hardware. */ |
1008 | list_for_each_entry(bus, &pci_root_buses, node) { | 1063 | list_for_each_entry(bus, &pci_root_buses, node) |
1009 | __pci_bus_assign_resources(bus, &add_list, NULL); | 1064 | __pci_bus_assign_resources(bus, &add_list, &head); |
1010 | pci_enable_bridges(bus); | ||
1011 | } | ||
1012 | BUG_ON(add_list.next); | 1065 | BUG_ON(add_list.next); |
1066 | tried_times++; | ||
1067 | |||
1068 | /* any device complain? */ | ||
1069 | if (!head.next) | ||
1070 | goto enable_and_dump; | ||
1071 | failed_type = 0; | ||
1072 | for (list = head.next; list;) { | ||
1073 | failed_type |= list->flags; | ||
1074 | list = list->next; | ||
1075 | } | ||
1076 | /* | ||
1077 | * io port are tight, don't try extra | ||
1078 | * or if reach the limit, don't want to try more | ||
1079 | */ | ||
1080 | failed_type &= type_mask; | ||
1081 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { | ||
1082 | free_list(resource_list_x, &head); | ||
1083 | goto enable_and_dump; | ||
1084 | } | ||
1085 | |||
1086 | printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", | ||
1087 | tried_times + 1); | ||
1088 | |||
1089 | /* third times and later will not check if it is leaf */ | ||
1090 | if ((tried_times + 1) > 2) | ||
1091 | rel_type = whole_subtree; | ||
1092 | |||
1093 | /* | ||
1094 | * Try to release leaf bridge's resources that doesn't fit resource of | ||
1095 | * child device under that bridge | ||
1096 | */ | ||
1097 | for (list = head.next; list;) { | ||
1098 | bus = list->dev->bus; | ||
1099 | pci_bus_release_bridge_resources(bus, list->flags & type_mask, | ||
1100 | rel_type); | ||
1101 | list = list->next; | ||
1102 | } | ||
1103 | /* restore size and flags */ | ||
1104 | for (list = head.next; list;) { | ||
1105 | struct resource *res = list->res; | ||
1106 | |||
1107 | res->start = list->start; | ||
1108 | res->end = list->end; | ||
1109 | res->flags = list->flags; | ||
1110 | if (list->dev->subordinate) | ||
1111 | res->flags = 0; | ||
1112 | |||
1113 | list = list->next; | ||
1114 | } | ||
1115 | free_list(resource_list_x, &head); | ||
1116 | |||
1117 | goto again; | ||
1118 | |||
1119 | enable_and_dump: | ||
1120 | /* Depth last, update the hardware. */ | ||
1121 | list_for_each_entry(bus, &pci_root_buses, node) | ||
1122 | pci_enable_bridges(bus); | ||
1013 | 1123 | ||
1014 | /* dump the resource on buses */ | 1124 | /* dump the resource on buses */ |
1015 | list_for_each_entry(bus, &pci_root_buses, node) { | 1125 | list_for_each_entry(bus, &pci_root_buses, node) |
1016 | pci_bus_dump_resources(bus); | 1126 | pci_bus_dump_resources(bus); |
1017 | } | ||
1018 | } | 1127 | } |
1019 | 1128 | ||
1020 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | 1129 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) |