Skip to content

Commit 5b28541

Browse files
Yinghai Lubjorn-helgaas
authored andcommitted
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 <[email protected]> Tested-by: Wei Yang <[email protected]> Signed-off-by: Yinghai Lu <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]>
1 parent 14c8530 commit 5b28541

File tree

2 files changed

+117
-53
lines changed

2 files changed

+117
-53
lines changed

drivers/pci/setup-bus.c

Lines changed: 99 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -713,12 +713,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
713713
bus resource of a given type. Note: we intentionally skip
714714
the bus resources which have already been assigned (that is,
715715
have non-NULL parent resource). */
716-
static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
716+
static struct resource *find_free_bus_resource(struct pci_bus *bus,
717+
unsigned long type_mask, unsigned long type)
717718
{
718719
int i;
719720
struct resource *r;
720-
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
721-
IORESOURCE_PREFETCH;
722721

723722
pci_bus_for_each_resource(bus, r, i) {
724723
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,
815814
resource_size_t add_size, struct list_head *realloc_head)
816815
{
817816
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);
819819
resource_size_t size = 0, size0 = 0, size1 = 0;
820820
resource_size_t children_add_size = 0;
821821
resource_size_t min_align, align;
@@ -907,6 +907,8 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
907907
* @bus : the bus
908908
* @mask: mask the resource flag, then compare it with type
909909
* @type: the type of free resource from bridge
910+
* @type2: second match type
911+
* @type3: third match type
910912
* @min_size : the minimum memory window that must to be allocated
911913
* @add_size : additional optional memory window
912914
* @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,
915917
* guarantees that all child resources fit in this size.
916918
*/
917919
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
918-
unsigned long type, resource_size_t min_size,
919-
resource_size_t add_size,
920-
struct list_head *realloc_head)
920+
unsigned long type, unsigned long type2,
921+
unsigned long type3,
922+
resource_size_t min_size, resource_size_t add_size,
923+
struct list_head *realloc_head)
921924
{
922925
struct pci_dev *dev;
923926
resource_size_t min_align, align, size, size0, size1;
924927
resource_size_t aligns[14]; /* Alignments from 1Mb to 8Gb */
925928
int order, max_order;
926-
struct resource *b_res = find_free_bus_resource(bus, type);
927-
unsigned int mem64_mask = 0;
929+
struct resource *b_res = find_free_bus_resource(bus,
930+
mask | IORESOURCE_PREFETCH, type);
928931
resource_size_t children_add_size = 0;
929932

930933
if (!b_res)
@@ -934,17 +937,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
934937
max_order = 0;
935938
size = 0;
936939

937-
mem64_mask = b_res->flags & IORESOURCE_MEM_64;
938-
b_res->flags &= ~IORESOURCE_MEM_64;
939-
940940
list_for_each_entry(dev, &bus->devices, bus_list) {
941941
int i;
942942

943943
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
944944
struct resource *r = &dev->resource[i];
945945
resource_size_t r_size;
946946

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))
948950
continue;
949951
r_size = resource_size(r);
950952
#ifdef CONFIG_PCI_IOV
@@ -981,7 +983,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
981983
aligns[order] += align;
982984
if (order > max_order)
983985
max_order = order;
984-
mem64_mask &= r->flags & IORESOURCE_MEM_64;
985986

986987
if (realloc_head)
987988
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,
10061007
}
10071008
b_res->start = min_align;
10081009
b_res->end = size0 + min_align - 1;
1009-
b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
1010+
b_res->flags |= IORESOURCE_STARTALIGN;
10101011
if (size1 > size0 && realloc_head) {
10111012
add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
10121013
dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
@@ -1122,8 +1123,9 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
11221123
struct list_head *realloc_head)
11231124
{
11241125
struct pci_dev *dev;
1125-
unsigned long mask, prefmask;
1126+
unsigned long mask, prefmask, type2 = 0, type3 = 0;
11261127
resource_size_t additional_mem_size = 0, additional_io_size = 0;
1128+
struct resource *b_res;
11271129

11281130
list_for_each_entry(dev, &bus->devices, bus_list) {
11291131
struct pci_bus *b = dev->subordinate;
@@ -1168,15 +1170,37 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
11681170
has already been allocated by arch code, try
11691171
non-prefetchable range for both types of PCI memory
11701172
resources. */
1173+
b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];
11711174
mask = IORESOURCE_MEM;
11721175
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,
11741180
realloc_head ? 0 : additional_mem_size,
1175-
additional_mem_size, realloc_head))
1176-
mask = prefmask; /* Success, size non-prefetch only. */
1177-
else
1178-
additional_mem_size += additional_mem_size;
1179-
pbus_size_mem(bus, mask, IORESOURCE_MEM,
1181+
additional_mem_size, realloc_head)) {
1182+
/*
1183+
* Success, with pref mmio64,
1184+
* next will size non-pref or
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,
11801204
realloc_head ? 0 : additional_mem_size,
11811205
additional_mem_size, realloc_head);
11821206
break;
@@ -1262,42 +1286,66 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
12621286
static void pci_bridge_release_resources(struct pci_bus *bus,
12631287
unsigned long type)
12641288
{
1265-
int idx;
1266-
bool changed = false;
1267-
struct pci_dev *dev;
1289+
struct pci_dev *dev = bus->self;
12681290
struct resource *r;
12691291
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;
12711296

1272-
dev = bus->self;
1273-
for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END;
1274-
idx++) {
1275-
r = &dev->resource[idx];
1276-
if ((r->flags & type_mask) != type)
1277-
continue;
1278-
if (!r->parent)
1279-
continue;
1280-
/*
1281-
* if there are children under that, we should release them
1282-
* all
1283-
*/
1284-
release_child_resources(r);
1285-
if (!release_resource(r)) {
1286-
dev_printk(KERN_DEBUG, &dev->dev,
1287-
"resource %d %pR released\n", idx, r);
1288-
/* keep the old size */
1289-
r->end = resource_size(r) - 1;
1290-
r->start = 0;
1291-
r->flags = 0;
1292-
changed = true;
1293-
}
1294-
}
1297+
b_res = &dev->resource[PCI_BRIDGE_RESOURCES];
1298+
1299+
/*
1300+
* 1. if there is io port assign fail, will release bridge
1301+
* io port.
1302+
* 2. if there is non pref mmio assign fail, release bridge
1303+
* nonpref mmio.
1304+
* 3. if there is 64bit pref mmio assign fail, and bridge pref
1305+
* is 64bit, release bridge pref mmio.
1306+
* 4. if there is pref mmio assign fail, and bridge pref is
1307+
* 32bit mmio, release bridge pref mmio
1308+
* 5. if there is pref mmio assign fail, and bridge pref is not
1309+
* assigned, release bridge nonpref mmio.
1310+
*/
1311+
if (type & IORESOURCE_IO)
1312+
idx = 0;
1313+
else if (!(type & IORESOURCE_PREFETCH))
1314+
idx = 1;
1315+
else if ((type & IORESOURCE_MEM_64) &&
1316+
(b_res[2].flags & IORESOURCE_MEM_64))
1317+
idx = 2;
1318+
else if (!(b_res[2].flags & IORESOURCE_MEM_64) &&
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;
12951342

1296-
if (changed) {
12971343
/* avoiding touch the one without PREF */
12981344
if (type & IORESOURCE_PREFETCH)
12991345
type = IORESOURCE_PREFETCH;
13001346
__pci_setup_bridge(bus, type);
1347+
/* for next child res under same bridge */
1348+
r->flags = old_flags;
13011349
}
13021350
}
13031351

@@ -1476,7 +1524,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
14761524
LIST_HEAD(fail_head);
14771525
struct pci_dev_resource *fail_res;
14781526
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
1479-
IORESOURCE_PREFETCH;
1527+
IORESOURCE_PREFETCH | IORESOURCE_MEM_64;
14801528
int pci_try_num = 1;
14811529
enum enable_type enable_local;
14821530

drivers/pci/setup-res.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,31 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
211211

212212
/* First, try exact prefetching match.. */
213213
ret = pci_bus_alloc_resource(bus, res, size, align, min,
214-
IORESOURCE_PREFETCH,
214+
IORESOURCE_PREFETCH | IORESOURCE_MEM_64,
215215
pcibios_align_resource, dev);
216216

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))) {
218232
/*
219233
* That failed.
220234
*
221235
* But a prefetching area can handle a non-prefetching
222236
* window (it will just not perform as well).
237+
*
238+
* Also can put 64bit under 32bit range. (below 4g).
223239
*/
224240
ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
225241
pcibios_align_resource, dev);

0 commit comments

Comments
 (0)