diff options
| author | Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> | 2026-03-24 18:56:32 +0200 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-03-27 10:19:08 -0500 |
| commit | 9036bd0efcb6162a77f3bf9bacbafba7686c7275 (patch) | |
| tree | 3703add19570c960793e308699e7b7da4c40d470 /arch | |
| parent | 8bbe8cec891f88dd3de8cae44812a884e10f1446 (diff) | |
| download | linux-next-9036bd0efcb6162a77f3bf9bacbafba7686c7275.tar.gz linux-next-9036bd0efcb6162a77f3bf9bacbafba7686c7275.zip | |
PCI: Align head space better
When a bridge window contains big and small resource(s), the small
resource(s) may not amount to the half of the size of the big resource
which would allow calculate_head_align() to shrink the head alignment.
This results in always placing the small resource(s) after the big
resource.
In general, it would be good to be able to place the small resource(s)
before the big resource to achieve better utilization of the address space.
In the cases where the large resource can only fit at the end of the
window, it is even required.
However, carrying the information over from pbus_size_mem() and
calculate_head_align() to __pci_assign_resource() and
pcibios_align_resource() is not easy with the current data structures.
A somewhat hacky way to move the non-aligning tail part to the head is
possible within pcibios_align_resource(). The free space between the start
of the free space span and the aligned start address can be compared with
the non-aligning remainder of the size. If the free space is larger than
the remainder, placing the remainder before the start address is possible.
This relocation should generally work, because PCI resources consist only
power-of-2 atoms.
Various arch requirements may still need to override the relocation, so the
relocation is only applied selectively in such cases.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221205
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Xifer <xiferdev@gmail.com>
Link: https://patch.msgid.link/20260324165633.4583-10-ilpo.jarvinen@linux.intel.com
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm/kernel/bios32.c | 3 | ||||
| -rw-r--r-- | arch/m68k/kernel/pcibios.c | 4 | ||||
| -rw-r--r-- | arch/mips/pci/pci-generic.c | 3 | ||||
| -rw-r--r-- | arch/mips/pci/pci-legacy.c | 2 | ||||
| -rw-r--r-- | arch/parisc/kernel/pci.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci-common.c | 2 | ||||
| -rw-r--r-- | arch/sh/drivers/pci/pci.c | 2 | ||||
| -rw-r--r-- | arch/x86/pci/i386.c | 2 | ||||
| -rw-r--r-- | arch/xtensa/kernel/pci.c | 2 |
9 files changed, 23 insertions, 0 deletions
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index cedb83a85dd9..ac0e890510da 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -577,6 +577,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return host_bridge->align_resource(dev, res, start, size, align); + if (res->flags & IORESOURCE_MEM) + return pci_align_resource(dev, res, empty_res, size, align); + return start; } diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c index 7e286ee1976b..7a9e60df79c5 100644 --- a/arch/m68k/kernel/pcibios.c +++ b/arch/m68k/kernel/pcibios.c @@ -31,11 +31,15 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; resource_size_t start = res->start; if ((res->flags & IORESOURCE_IO) && (start & 0x300)) start = (start + 0x3ff) & ~0x3ff; + if (res->flags & IORESOURCE_MEM) + return pci_align_resource(dev, res, empty_res, size, align); + return start; } diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c index aaa1d6de8bef..c2e23d0c1d77 100644 --- a/arch/mips/pci/pci-generic.c +++ b/arch/mips/pci/pci-generic.c @@ -38,6 +38,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return host_bridge->align_resource(dev, res, start, size, align); + if (res->flags & IORESOURCE_MEM) + return pci_align_resource(dev, res, empty_res, size, align); + return start; } diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index 817e97402afe..dae6dafdd6e0 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -70,6 +70,8 @@ pcibios_align_resource(void *data, const struct resource *res, if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; } else if (res->flags & IORESOURCE_MEM) { + start = pci_align_resource(dev, res, empty_res, size, align); + /* Make sure we start at our min on all hoses */ if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start) start = PCIBIOS_MIN_MEM + hose->mem_resource->start; diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index f50be1a63c4c..b8007c7400d4 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -201,6 +201,7 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, resource_size_t size, resource_size_t alignment) { + struct pci_dev *dev = data; resource_size_t align, start = res->start; DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n", @@ -212,6 +213,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; if (align > alignment) start = ALIGN(start, align); + else + start = pci_align_resource(dev, res, empty_res, size, alignment); return start; } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index e7bfa15da043..8efe95a0c4ff 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1144,6 +1144,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return start; if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; + } else if (res->flags & IORESOURCE_MEM) { + start = pci_align_resource(dev, res, empty_res, size, align); } return start; diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 7a0522316ee3..878a27a1acfb 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -185,6 +185,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, */ if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; + } else if (res->flags & IORESOURCE_MEM) { + start = pci_align_resource(dev, res, empty_res, size, align); } return start; diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 6fbd4b34c3f7..e2de26b82940 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -165,6 +165,8 @@ pcibios_align_resource(void *data, const struct resource *res, if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; } else if (res->flags & IORESOURCE_MEM) { + start = pci_align_resource(dev, res, empty_res, size, align); + /* The low 1MB range is reserved for ISA cards */ if (start < BIOS_END) start = BIOS_END; diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 64ccb7e0d92f..305031551136 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -54,6 +54,8 @@ pcibios_align_resource(void *data, const struct resource *res, if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; + } else if (res->flags & IORESOURCE_MEM) { + start = pci_align_resource(dev, res, empty_res, size, align); } return start; |
