Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

PCI: Remove old_size limit from bridge window sizing

calculate_memsize() applies lower bound to the resource size before
aligning the resource size making it impossible to shrink bridge window
resources. I've not found any justification for this lower bound and
nothing indicated it was to work around some HW issue.

Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
of release_resource()"), releasing a bridge window during BAR resize
resulted in clearing start and end address of the resource. Clearing
addresses destroys the resource size as a side-effect, therefore nullifying
the effect of the old size lower bound.

After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead of
release_resource()"), BAR resize uses the aligned old size, which results
in exceeding what fits into the parent window in some cases:

xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]

The old size of 0x6200000000000-0x6203fbff0ffff resource was used as the
lower bound which results in 0x4000000000 size request due to alignment.
That exceeds what can fit into the parent window.

Since the lower bound never even was enforced fully because the resource
addresses were cleared when the bridge window is released, remove the
old_size lower bound entirely and trust the calculated bridge window size
is enough.

This same problem may occur on io window side but seems less likely to
cause issues due to general difference in alignment. Removing the lower
bound may have other unforeseen consequences in case of io window so it's
better to leave it as -next material if no problem is reported related to
io window sizing (BAR resize shouldn't touch io windows anyway).

Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
Reported-by: Simon Richter <Simon.Richter@hogyros.de>
Link: https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20251219174036.16738-6-ilpo.jarvinen@linux.intel.com

authored by

Ilpo Järvinen and committed by
Bjorn Helgaas
f909e3ee 4326ab18

+3 -8
+3 -8
drivers/pci/setup-bus.c
··· 1071 1071 resource_size_t min_size, 1072 1072 resource_size_t add_size, 1073 1073 resource_size_t children_add_size, 1074 - resource_size_t old_size, 1075 1074 resource_size_t align) 1076 1075 { 1077 1076 if (size < min_size) 1078 1077 size = min_size; 1079 - if (old_size == 1) 1080 - old_size = 0; 1081 1078 1082 1079 size = max(size, add_size) + children_add_size; 1083 - return ALIGN(max(size, old_size), align); 1080 + return ALIGN(size, align); 1084 1081 } 1085 1082 1086 1083 resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, ··· 1295 1298 resource_size_t children_add_size = 0; 1296 1299 resource_size_t children_add_align = 0; 1297 1300 resource_size_t add_align = 0; 1298 - resource_size_t old_size; 1299 1301 1300 1302 if (!b_res) 1301 1303 return; ··· 1360 1364 } 1361 1365 } 1362 1366 1363 - old_size = resource_size(b_res); 1364 1367 win_align = window_alignment(bus, b_res->flags); 1365 1368 min_align = calculate_head_align(aligns, max_order); 1366 1369 min_align = max(min_align, win_align); 1367 - size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); 1370 + size0 = calculate_memsize(size, min_size, 0, 0, win_align); 1368 1371 1369 1372 if (size0) { 1370 1373 resource_set_range(b_res, min_align, size0); ··· 1373 1378 if (realloc_head && (add_size > 0 || children_add_size > 0)) { 1374 1379 add_align = max(min_align, add_align); 1375 1380 size1 = calculate_memsize(size, min_size, add_size, children_add_size, 1376 - old_size, win_align); 1381 + win_align); 1377 1382 } 1378 1383 1379 1384 if (!size0 && !size1) {