aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2014-05-19 19:01:55 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-05-23 14:40:48 -0400
commit5b28541552ef5eeffc41d6936105f38c2508e566 (patch)
tree0512fa3d261d84e3eca905b21e0147ac82311884 /drivers/pci
parent14c8530dbc1b7cd5020c44b391e34bdb731fd098 (diff)
PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources
This patch changes the way we handle 64-bit prefetchable bridge windows to make it more likely that we can assign space to all devices. Previously we put all prefetchable resources in the prefetchable bridge window. If any of those resources was 32-bit only, we restricted the window to be below 4GB. After this patch, we only put 64-bit prefetchable resources in a 64-bit prefetchable window. We put all 32-bit prefetchable resources in the non-prefetchable window, even if there are no 64-bit prefetchable resources. With the previous approach, if there was a 32-bit prefetchable resource behind a bridge, we forced the bridge's prefetchable window below 4GB, which meant that even if there was plenty of space above 4GB available, we couldn't use it, and assignment of large 64-bit resources could fail, as in the bugzilla below. The new strategy is: 1) If the prefetchable window is 64 bits wide, we put only 64-bit prefetchable resources in it. Any 32-bit prefetchable resources go in the non-prefetchable window. 2) If the prefetchable window is 32 bits wide, we put both 32- and 64-bit prefetchable resources in it. 3) If there is no prefetchable window, all MMIO resources go in the non-prefetchable window. This reduces performance for 32-bit prefetchable resources below a bridge with a 64-bit prefetchable window. We previously assigned prefetchable space, but now we'll assign non-prefetchable space. This is the case even if there are no 64-bit prefetchable resources, or if they would all fit below 4GB. In those cases, the old strategy would work and would have better performance. [bhelgaas: write changelog, add bugzilla link, fold in mem64_mask removal] Link: https://bugzilla.kernel.org/show_bug.cgi?id=74151 Tested-by: Guo Chao <yan@linux.vnet.ibm.com> Tested-by: Wei Yang <weiyang@linux.vnet.ibm.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/setup-bus.c150
-rw-r--r--drivers/pci/setup-res.c20
2 files changed, 117 insertions, 53 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 9b3498c9b739..b6585cb9bce7 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -713,12 +713,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
713 bus resource of a given type. Note: we intentionally skip 713 bus resource of a given type. Note: we intentionally skip
714 the bus resources which have already been assigned (that is, 714 the bus resources which have already been assigned (that is,
715 have non-NULL parent resource). */ 715 have non-NULL parent resource). */
716static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type) 716static struct resource *find_free_bus_resource(struct pci_bus *bus,
717 unsigned long type_mask, unsigned long type)
717{ 718{
718 int i; 719 int i;
719 struct resource *r; 720 struct resource *r;
720 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
721 IORESOURCE_PREFETCH;
722 721
723 pci_bus_for_each_resource(bus, r, i) { 722 pci_bus_for_each_resource(bus, r, i) {
724 if (r == &ioport_resource || r == &iomem_resource) 723 if (r == &ioport_resource || r == &iomem_resource)
@@ -815,7 +814,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
815 resource_size_t add_size, struct list_head *realloc_head) 814 resource_size_t add_size, struct list_head *realloc_head)
816{ 815{
817 struct pci_dev *dev; 816 struct pci_dev *dev;
818 struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); 817 struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
818 IORESOURCE_IO);
819 resource_size_t size = 0, size0 = 0, size1 = 0; 819 resource_size_t size = 0, size0 = 0, size1 = 0;
820 resource_size_t children_add_size = 0; 820 resource_size_t children_add_size = 0;
821 resource_size_t min_align, align; 821 resource_size_t min_align, align;
@@ -907,6 +907,8 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
907 * @bus : the bus 907 * @bus : the bus
908 * @mask: mask the resource flag, then compare it with type 908 * @mask: mask the resource flag, then compare it with type
909 * @type: the type of free resource from bridge 909 * @type: the type of free resource from bridge
910 * @type2: second match type
911 * @type3: third match type
910 * @min_size : the minimum memory window that must to be allocated 912 * @min_size : the minimum memory window that must to be allocated
911 * @add_size : additional optional memory window 913 * @add_size : additional optional memory window
912 * @realloc_head : track the additional memory window on this list 914 * @realloc_head : track the additional memory window on this list
@@ -915,16 +917,17 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
915 * guarantees that all child resources fit in this size. 917 * guarantees that all child resources fit in this size.
916 */ 918 */
917static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, 919static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
918 unsigned long type, resource_size_t min_size, 920 unsigned long type, unsigned long type2,
919 resource_size_t add_size, 921 unsigned long type3,
920 struct list_head *realloc_head) 922 resource_size_t min_size, resource_size_t add_size,
923 struct list_head *realloc_head)
921{ 924{
922 struct pci_dev *dev; 925 struct pci_dev *dev;
923 resource_size_t min_align, align, size, size0, size1; 926 resource_size_t min_align, align, size, size0, size1;
924 resource_size_t aligns[14]; /* Alignments from 1Mb to 8Gb */ 927 resource_size_t aligns[14]; /* Alignments from 1Mb to 8Gb */
925 int order, max_order; 928 int order, max_order;
926 struct resource *b_res = find_free_bus_resource(bus, type); 929 struct resource *b_res = find_free_bus_resource(bus,
927 unsigned int mem64_mask = 0; 930 mask | IORESOURCE_PREFETCH, type);
928 resource_size_t children_add_size = 0; 931 resource_size_t children_add_size = 0;
929 932
930 if (!b_res) 933 if (!b_res)
@@ -934,9 +937,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
934 max_order = 0; 937 max_order = 0;
935 size = 0; 938 size = 0;
936 939
937 mem64_mask = b_res->flags & IORESOURCE_MEM_64;
938 b_res->flags &= ~IORESOURCE_MEM_64;
939
940 list_for_each_entry(dev, &bus->devices, bus_list) { 940 list_for_each_entry(dev, &bus->devices, bus_list) {
941 int i; 941 int i;
942 942
@@ -944,7 +944,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
944 struct resource *r = &dev->resource[i]; 944 struct resource *r = &dev->resource[i];
945 resource_size_t r_size; 945 resource_size_t r_size;
946 946
947 if (r->parent || (r->flags & mask) != type) 947 if (r->parent || ((r->flags & mask) != type &&
948 (r->flags & mask) != type2 &&
949 (r->flags & mask) != type3))
948 continue; 950 continue;
949 r_size = resource_size(r); 951 r_size = resource_size(r);
950#ifdef CONFIG_PCI_IOV 952#ifdef CONFIG_PCI_IOV
@@ -981,7 +983,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
981 aligns[order] += align; 983 aligns[order] += align;
982 if (order > max_order) 984 if (order > max_order)
983 max_order = order; 985 max_order = order;
984 mem64_mask &= r->flags & IORESOURCE_MEM_64;
985 986
986 if (realloc_head) 987 if (realloc_head)
987 children_add_size += get_res_add_size(realloc_head, r); 988 children_add_size += get_res_add_size(realloc_head, r);
@@ -1006,7 +1007,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
1006 } 1007 }
1007 b_res->start = min_align; 1008 b_res->start = min_align;
1008 b_res->end = size0 + min_align - 1; 1009 b_res->end = size0 + min_align - 1;
1009 b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; 1010 b_res->flags |= IORESOURCE_STARTALIGN;
1010 if (size1 > size0 && realloc_head) { 1011 if (size1 > size0 && realloc_head) {
1011 add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); 1012 add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
1012 dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " 1013 dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
@@ -1122,8 +1123,9 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
1122 struct list_head *realloc_head) 1123 struct list_head *realloc_head)
1123{ 1124{
1124 struct pci_dev *dev; 1125 struct pci_dev *dev;
1125 unsigned long mask, prefmask; 1126 unsigned long mask, prefmask, type2 = 0, type3 = 0;
1126 resource_size_t additional_mem_size = 0, additional_io_size = 0; 1127 resource_size_t additional_mem_size = 0, additional_io_size = 0;
1128 struct resource *b_res;
1127 1129
1128 list_for_each_entry(dev, &bus->devices, bus_list) { 1130 list_for_each_entry(dev, &bus->devices, bus_list) {
1129 struct pci_bus *b = dev->subordinate; 1131 struct pci_bus *b = dev->subordinate;
@@ -1168,15 +1170,37 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
1168 has already been allocated by arch code, try 1170 has already been allocated by arch code, try
1169 non-prefetchable range for both types of PCI memory 1171 non-prefetchable range for both types of PCI memory
1170 resources. */ 1172 resources. */
1173 b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];
1171 mask = IORESOURCE_MEM; 1174 mask = IORESOURCE_MEM;
1172 prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; 1175 prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
1173 if (pbus_size_mem(bus, prefmask, prefmask, 1176 if (b_res[2].flags & IORESOURCE_MEM_64) {
1177 prefmask |= IORESOURCE_MEM_64;
1178 if (pbus_size_mem(bus, prefmask, prefmask,
1179 prefmask, prefmask,
1174 realloc_head ? 0 : additional_mem_size, 1180 realloc_head ? 0 : additional_mem_size,
1175 additional_mem_size, realloc_head)) 1181 additional_mem_size, realloc_head)) {
1176 mask = prefmask; /* Success, size non-prefetch only. */ 1182 /*
1177 else 1183 * Success, with pref mmio64,
1178 additional_mem_size += additional_mem_size; 1184 * next will size non-pref or
1179 pbus_size_mem(bus, mask, IORESOURCE_MEM, 1185 * non-mmio64 */
1186 mask = prefmask;
1187 type2 = prefmask & ~IORESOURCE_MEM_64;
1188 type3 = prefmask & ~IORESOURCE_PREFETCH;
1189 }
1190 }
1191 if (!type2) {
1192 prefmask &= ~IORESOURCE_MEM_64;
1193 if (pbus_size_mem(bus, prefmask, prefmask,
1194 prefmask, prefmask,
1195 realloc_head ? 0 : additional_mem_size,
1196 additional_mem_size, realloc_head)) {
1197 /* Success, next will size non-prefetch. */
1198 mask = prefmask;
1199 } else
1200 additional_mem_size += additional_mem_size;
1201 type2 = type3 = IORESOURCE_MEM;
1202 }
1203 pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
1180 realloc_head ? 0 : additional_mem_size, 1204 realloc_head ? 0 : additional_mem_size,
1181 additional_mem_size, realloc_head); 1205 additional_mem_size, realloc_head);
1182 break; 1206 break;
@@ -1262,42 +1286,66 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
1262static void pci_bridge_release_resources(struct pci_bus *bus, 1286static void pci_bridge_release_resources(struct pci_bus *bus,
1263 unsigned long type) 1287 unsigned long type)
1264{ 1288{
1265 int idx; 1289 struct pci_dev *dev = bus->self;
1266 bool changed = false;
1267 struct pci_dev *dev;
1268 struct resource *r; 1290 struct resource *r;
1269 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | 1291 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
1270 IORESOURCE_PREFETCH; 1292 IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
1293 unsigned old_flags = 0;
1294 struct resource *b_res;
1295 int idx = 1;
1271 1296
1272 dev = bus->self; 1297 b_res = &dev->resource[PCI_BRIDGE_RESOURCES];
1273 for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END; 1298
1274 idx++) { 1299 /*
1275 r = &dev->resource[idx]; 1300 * 1. if there is io port assign fail, will release bridge
1276 if ((r->flags & type_mask) != type) 1301 * io port.
1277 continue; 1302 * 2. if there is non pref mmio assign fail, release bridge
1278 if (!r->parent) 1303 * nonpref mmio.
1279 continue; 1304 * 3. if there is 64bit pref mmio assign fail, and bridge pref
1280 /* 1305 * is 64bit, release bridge pref mmio.
1281 * if there are children under that, we should release them 1306 * 4. if there is pref mmio assign fail, and bridge pref is
1282 * all 1307 * 32bit mmio, release bridge pref mmio
1283 */ 1308 * 5. if there is pref mmio assign fail, and bridge pref is not
1284 release_child_resources(r); 1309 * assigned, release bridge nonpref mmio.
1285 if (!release_resource(r)) { 1310 */
1286 dev_printk(KERN_DEBUG, &dev->dev, 1311 if (type & IORESOURCE_IO)
1287 "resource %d %pR released\n", idx, r); 1312 idx = 0;
1288 /* keep the old size */ 1313 else if (!(type & IORESOURCE_PREFETCH))
1289 r->end = resource_size(r) - 1; 1314 idx = 1;
1290 r->start = 0; 1315 else if ((type & IORESOURCE_MEM_64) &&
1291 r->flags = 0; 1316 (b_res[2].flags & IORESOURCE_MEM_64))
1292 changed = true; 1317 idx = 2;
1293 } 1318 else if (!(b_res[2].flags & IORESOURCE_MEM_64) &&
1294 } 1319 (b_res[2].flags & IORESOURCE_PREFETCH))
1320 idx = 2;
1321 else
1322 idx = 1;
1323
1324 r = &b_res[idx];
1325
1326 if (!r->parent)
1327 return;
1328
1329 /*
1330 * if there are children under that, we should release them
1331 * all
1332 */
1333 release_child_resources(r);
1334 if (!release_resource(r)) {
1335 type = old_flags = r->flags & type_mask;
1336 dev_printk(KERN_DEBUG, &dev->dev, "resource %d %pR released\n",
1337 PCI_BRIDGE_RESOURCES + idx, r);
1338 /* keep the old size */
1339 r->end = resource_size(r) - 1;
1340 r->start = 0;
1341 r->flags = 0;
1295 1342
1296 if (changed) {
1297 /* avoiding touch the one without PREF */ 1343 /* avoiding touch the one without PREF */
1298 if (type & IORESOURCE_PREFETCH) 1344 if (type & IORESOURCE_PREFETCH)
1299 type = IORESOURCE_PREFETCH; 1345 type = IORESOURCE_PREFETCH;
1300 __pci_setup_bridge(bus, type); 1346 __pci_setup_bridge(bus, type);
1347 /* for next child res under same bridge */
1348 r->flags = old_flags;
1301 } 1349 }
1302} 1350}
1303 1351
@@ -1476,7 +1524,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
1476 LIST_HEAD(fail_head); 1524 LIST_HEAD(fail_head);
1477 struct pci_dev_resource *fail_res; 1525 struct pci_dev_resource *fail_res;
1478 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | 1526 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
1479 IORESOURCE_PREFETCH; 1527 IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
1480 int pci_try_num = 1; 1528 int pci_try_num = 1;
1481 enum enable_type enable_local; 1529 enum enable_type enable_local;
1482 1530
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 7eed671d5586..2473f091a9cc 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -211,15 +211,31 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
211 211
212 /* First, try exact prefetching match.. */ 212 /* First, try exact prefetching match.. */
213 ret = pci_bus_alloc_resource(bus, res, size, align, min, 213 ret = pci_bus_alloc_resource(bus, res, size, align, min,
214 IORESOURCE_PREFETCH, 214 IORESOURCE_PREFETCH | IORESOURCE_MEM_64,
215 pcibios_align_resource, dev); 215 pcibios_align_resource, dev);
216 216
217 if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) { 217 if (ret < 0 &&
218 (res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) ==
219 (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) {
220 /*
221 * That failed.
222 *
223 * Try 32bit pref
224 */
225 ret = pci_bus_alloc_resource(bus, res, size, align, min,
226 IORESOURCE_PREFETCH,
227 pcibios_align_resource, dev);
228 }
229
230 if (ret < 0 &&
231 (res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64))) {
218 /* 232 /*
219 * That failed. 233 * That failed.
220 * 234 *
221 * But a prefetching area can handle a non-prefetching 235 * But a prefetching area can handle a non-prefetching
222 * window (it will just not perform as well). 236 * window (it will just not perform as well).
237 *
238 * Also can put 64bit under 32bit range. (below 4g).
223 */ 239 */
224 ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, 240 ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
225 pcibios_align_resource, dev); 241 pcibios_align_resource, dev);