diff options
| author | Shubham Aggarwal <shubagga@google.com> | 2026-10-09 09:51:20 +0300 |
|---|---|---|
| committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2026-10-12 12:31:30 +0300 |
| commit | 05b96e3ccf3fe6b899651d2e245b29a4f7a0e472 (patch) | |
| tree | fda6d325620ea27cdc07911800848e6b897be877 /BaseTools/Source/Python | |
| parent | 1a44fc33295d32653fb114e1f1b9b91a81d47239 (diff) | |
| download | edk2-05b96e3ccf3fe6b899651d2e245b29a4f7a0e472.tar.xz | |
MdeModulePkg/PciBusDxe: Keep discovery order of equally aligned BARs
InsertResourceNode() keeps the resource list of a bridge sorted by
descending alignment. The new node is inserted at the head of the list
and then moved towards the tail, but it stops in front of the first
node that it does not need to follow. Resources that rank equal, such
as BARs of the same size, therefore end up in the reverse order of
their discovery (LIFO), and the last discovered one is assigned the
lowest address.
Linux also sorts the resources by descending alignment in
pdev_sort_resources() (drivers/pci/setup-bus.c), but it inserts a new
resource after all the resources with the same alignment, so these
keep their discovery order (FIFO).
When the OS reassigns the PCI resources instead of keeping the firmware
assignment (for example Linux on ARM64 ACPI systems, unless the
firmware requests to preserve the PCI boot configuration through _DSM
function 5), this difference makes it swap the addresses of equally
sized BARs. While doing so, a BAR is temporarily programmed with a
range that is still decoded by another device, which is not handled by
some platforms, such as VMMs that do not allow overlapping BARs.
Insert the new node at the tail of the list and move it towards the
head instead, swapping the roles of the two compared nodes, so that
resources that rank equal keep their discovery order, consistent with
Linux.
Resources with the same alignment are also sorted by the remainder of
their length modulo the alignment. In practice, the remainder is only
non-zero for the window of a child bridge, whose length is a multiple
of the window granularity but whose alignment is the largest alignment
of the resources behind it. Such a window leaves a gap in front of the
next resource with the same alignment, so resources without a remainder
should come first. However, the check only ranks a zero remainder first
for the node that is being inserted, not for the existing node that it
is compared with, so the relative order of windows with and without a
remainder also depends on the insertion order. Reversing it can waste
address space. For example, on QEMU q35 with three PCIe root ports,
where the first one has a 3 MB MMIO window aligned to 2 MB and the
other two have a 2 MB window, the 3 MB window would be placed first,
leaving a 1 MB gap and growing the MMIO32 aperture of the root bridge
from 8 MB to 9 MB.
Therefore, rank a zero remainder first for both compared nodes.
Resources without a remainder now always come first, regardless of the
discovery order, which never increases the size of the aperture, and
only resources that rank equal are ordered by their discovery. Update
the description of InsertResourceNode() to document the full ordering.
Signed-off-by: Shubham Aggarwal <shubagga@google.com>
Diffstat (limited to 'BaseTools/Source/Python')
0 files changed, 0 insertions, 0 deletions
