aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2011-05-12 20:11:37 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-05-21 15:17:11 -0400
commitda7822e5ad71ec9b745b412639f1e5e0ba795a20 (patch)
tree605722e2c2b32fd6450bc91718ac7b4240fcba6c
parentf8fcfd775523347afe460dc3a0f45d0479e784a2 (diff)
PCI: update bridge resources to get more big ranges when allocating space (again)
With Ram's fixes, this should be safe to do again. So let's give it another try. BIOS separates IO ranges between several IOHs, and on some slots, BIOS assigns resources to a bridge, but stops assigning resources to the device under that bridge, because the device needs a big resource. So: 1. allocate resources and record the failed device resources 2. clear the BIOS assigned resources of the parent bridge of failing device 3. go back and call pci assign unassigned 4. if it still fails, go up the tree, clear more bridges. and try again Now Ram's allocate requested resource already got into mainline. could put this one again. Reviewed-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--drivers/pci/setup-bus.c125
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
994static 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}
1012static 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 */
994void __init 1033void __init
995pci_assign_unassigned_resources(void) 1034pci_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
1056again:
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
1119enable_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
1020void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) 1129void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)