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