[PATCH 00/10] PCI: Improve head free space usage

STALE166d

19 messages, 5 authors, 2026-03-27 · open the first message on its own page

[PATCH 00/10] PCI: Improve head free space usage

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:58:26

Hi all,

This series attempts to take advantage of free head space (the free
space before the aligned start address) in order to generally produce a
tighter packing of the resources/bridge windows.

The recent changes to the resource fitting algorithm caused resource
allocation failures in some cases where a bridge window that is sized
to be gapless could no longer be assigned. The previous algorithm left
a huge gaps which allowed it to place the remainder (non-aligning part
of the size) before the start address of used for the gapless fit,
whereas the new gapless approach always had to place the remainder
after the aligning part of the resources. There is not always space
for the remainder triggering those failures (e.g., when the aligning
part must be placed at the top of the window).

This series attempts to allow placing the remainder once again before
the aligning part, but now without leaving huge gaps to retain the
benefits of the gapless bridge windows. The approach is somewhat hacky
but should work thanks to PCI resources fundamentally consisting only
power-of-two atoms.

There maybe cases where architecture would not want to do such
relocation. This series adds the relocation to arch
pcibios_align_resource() functions to allow all of them taking
advantage of the better resource packing but if somebody objects doing
this relocation for a particular arch, I can remove it, please just let
me know (this relocation doesn't seem critical unless there are
regressions).

Ilpo Järvinen (10):
  resource: Add __resource_contains_unbound() for internal contains
    checks
  resource: Pass full extent of empty space to resource_alignf CB
  resource: Rename 'tmp' variable to 'full_avail'
  ARM/PCI: Remove unnecessary second application of align
  am68k/PCI: Remove unnecessary second application of align
  MIPS: PCI: Remove unnecessary second application of align
  parisc/PCI: Cleanup align handling
  PCI: Rename window_alignment() to pci_min_window_alignment()
  PCI: Align head space better
  PCI: Fix alignment calculation for resource size larger than align

 arch/alpha/kernel/pci.c          |  1 +
 arch/arm/kernel/bios32.c         |  9 ++++---
 arch/m68k/kernel/pcibios.c       |  8 +++++--
 arch/mips/pci/pci-generic.c      |  8 ++++---
 arch/mips/pci/pci-legacy.c       |  3 +++
 arch/parisc/kernel/pci.c         | 17 ++++++++------
 arch/powerpc/kernel/pci-common.c |  6 ++++-
 arch/s390/pci/pci.c              |  1 +
 arch/sh/drivers/pci/pci.c        |  6 ++++-
 arch/x86/pci/i386.c              |  5 +++-
 arch/xtensa/kernel/pci.c         |  3 +++
 drivers/pci/pci.h                |  3 +++
 drivers/pci/setup-bus.c          | 15 ++++++++----
 drivers/pci/setup-res.c          | 40 +++++++++++++++++++++++++++++++-
 drivers/pcmcia/rsrc_nonstatic.c  |  3 ++-
 include/linux/ioport.h           | 22 +++++++++++++++---
 include/linux/pci.h              | 12 +++++++---
 kernel/resource.c                | 33 +++++++++++++-------------
 18 files changed, 149 insertions(+), 46 deletions(-)


base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
-- 
2.39.5

[PATCH 01/10] resource: Add __resource_contains_unbound() for internal contains checks

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:58:40

__find_resource_space() currently uses resource_contains() but for
tentative resources that are not yet crafted into the resource tree. As
resource_contains() checks that IORESOURCE_UNSET is not set for either
of the resources, the caller has to hack around this problem by
clearing the IORESOURCE_UNSET flag (essentially lying to
resource_contains()).

Instead of the hack, introduce __resource_contains_unbound() for cases
like this.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 include/linux/ioport.h | 20 +++++++++++++++++---
 kernel/resource.c      |  4 ++--
 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 5533a5debf3f..19d5e04564d9 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -304,14 +304,28 @@ static inline unsigned long resource_ext_type(const struct resource *res)
 {
 	return res->flags & IORESOURCE_EXT_TYPE_BITS;
 }
-/* True iff r1 completely contains r2 */
-static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
+
+/*
+ * For checking if @r1 completely contains @r2 for resources that have real
+ * addresses but are not yet crafted into the resource tree. Normally
+ * resource_contains() should be used instead of this function as it checks
+ * also IORESOURCE_UNSET flag.
+ */
+static inline bool __resource_contains_unbound(const struct resource *r1,
+					       const struct resource *r2)
 {
 	if (resource_type(r1) != resource_type(r2))
 		return false;
+
+	return r1->start <= r2->start && r1->end >= r2->end;
+}
+/* True iff r1 completely contains r2 */
+static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
+{
 	if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
 		return false;
-	return r1->start <= r2->start && r1->end >= r2->end;
+
+	return __resource_contains_unbound(r1, r2);
 }
 
 /* True if any part of r1 overlaps r2 */
diff --git a/kernel/resource.c b/kernel/resource.c
index bb966699da31..1e2f1dfc0edd 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -754,7 +754,7 @@ static int __find_resource_space(struct resource *root, struct resource *old,
 		/* Check for overflow after ALIGN() */
 		avail.start = ALIGN(tmp.start, constraint->align);
 		avail.end = tmp.end;
-		avail.flags = new->flags & ~IORESOURCE_UNSET;
+		avail.flags = new->flags;
 		if (avail.start >= tmp.start) {
 			alloc.flags = avail.flags;
 			if (alignf) {
@@ -765,7 +765,7 @@ static int __find_resource_space(struct resource *root, struct resource *old,
 			}
 			alloc.end = alloc.start + size - 1;
 			if (alloc.start <= alloc.end &&
-			    resource_contains(&avail, &alloc)) {
+			    __resource_contains_unbound(&avail, &alloc)) {
 				new->start = alloc.start;
 				new->end = alloc.end;
 				return 0;
-- 
2.39.5

[PATCH 02/10] resource: Pass full extent of empty space to resource_alignf CB

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:59:06

__find_resource_space() calculates the full extent of empty space but
only passes the aligned space to resource_alignf callback. In some
situations, the callback may choose take advantage of the free space
before the requested alignment.

Pass the full extent of the calculated empty space to resource_alignf
callback as an additional parameter.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/alpha/kernel/pci.c          | 1 +
 arch/arm/kernel/bios32.c         | 4 +++-
 arch/m68k/kernel/pcibios.c       | 4 +++-
 arch/mips/pci/pci-generic.c      | 3 ++-
 arch/mips/pci/pci-legacy.c       | 1 +
 arch/parisc/kernel/pci.c         | 4 +++-
 arch/powerpc/kernel/pci-common.c | 4 +++-
 arch/s390/pci/pci.c              | 1 +
 arch/sh/drivers/pci/pci.c        | 4 +++-
 arch/x86/pci/i386.c              | 3 ++-
 arch/xtensa/kernel/pci.c         | 1 +
 drivers/pci/setup-res.c          | 3 ++-
 drivers/pcmcia/rsrc_nonstatic.c  | 3 ++-
 include/linux/ioport.h           | 2 ++
 include/linux/pci.h              | 7 ++++---
 kernel/resource.c                | 3 ++-
 16 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 51a8a4c4572a..11df411b1d18 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -125,6 +125,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
 
 resource_size_t
 pcibios_align_resource(void *data, const struct resource *res,
+		       const struct resource *empty_res,
 		       resource_size_t size, resource_size_t align)
 {
 	struct pci_dev *dev = data;
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index b5793e8fbdc1..5b9b4fcd0e54 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -560,7 +560,9 @@ char * __init pcibios_setup(char *str)
  * which might be mirrored at 0x0100-0x03ff..
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t align)
 {
 	struct pci_dev *dev = data;
 	resource_size_t start = res->start;
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index e6ab3f9ff5d8..1415f6e4e5ce 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -27,7 +27,9 @@
  * which might be mirrored at 0x0100-0x03ff..
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-	resource_size_t size, resource_size_t align)
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t align)
 {
 	resource_size_t start = res->start;
 
diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c
index d2d68bac3d25..f4957c26efc7 100644
--- a/arch/mips/pci/pci-generic.c
+++ b/arch/mips/pci/pci-generic.c
@@ -22,7 +22,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
+				       const struct resource *empty_res,
+				       resource_size_t size, resource_size_t align)
 {
 	struct pci_dev *dev = data;
 	resource_size_t start = res->start;
diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c
index d04b7c1294b6..817e97402afe 100644
--- a/arch/mips/pci/pci-legacy.c
+++ b/arch/mips/pci/pci-legacy.c
@@ -52,6 +52,7 @@ unsigned long pci_address_to_pio(phys_addr_t address)
  */
 resource_size_t
 pcibios_align_resource(void *data, const struct resource *res,
+		       const struct resource *empty_res,
 		       resource_size_t size, resource_size_t align)
 {
 	struct pci_dev *dev = data;
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index cf285b17a5ae..f99b20795d5a 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -196,7 +196,9 @@ void __ref pcibios_init_bridge(struct pci_dev *dev)
  * than res->start.
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t alignment)
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t alignment)
 {
 	resource_size_t mask, align, start = res->start;
 
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index a7a2fb605971..e7bfa15da043 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1132,7 +1132,9 @@ static int skip_isa_ioresource_align(struct pci_dev *dev)
  * which might have be mirrored at 0x0100-0x03ff..
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t align)
 {
 	struct pci_dev *dev = data;
 	resource_size_t start = res->start;
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2a430722cbe4..39bd2adfc240 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -266,6 +266,7 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
 }
 
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				       const struct resource *empty_res,
 				       resource_size_t size,
 				       resource_size_t align)
 {
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index a3903304f33f..7a0522316ee3 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -168,7 +168,9 @@ subsys_initcall(pcibios_init);
  * modulo 0x400.
  */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t align)
 {
 	struct pci_dev *dev = data;
 	struct pci_channel *hose = dev->sysdata;
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index c4ec39ad276b..6fbd4b34c3f7 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -153,7 +153,8 @@ skip_isa_ioresource_align(struct pci_dev *dev) {
  */
 resource_size_t
 pcibios_align_resource(void *data, const struct resource *res,
-			resource_size_t size, resource_size_t align)
+		       const struct resource *empty_res,
+		       resource_size_t size, resource_size_t align)
 {
 	struct pci_dev *dev = data;
 	resource_size_t start = res->start;
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 62c900e400d6..64ccb7e0d92f 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -39,6 +39,7 @@
  */
 resource_size_t
 pcibios_align_resource(void *data, const struct resource *res,
+		       const struct resource *empty_res,
 		       resource_size_t size, resource_size_t align)
 {
 	struct pci_dev *dev = data;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index bb2aef373d6f..c375e255c509 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -251,10 +251,11 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
  */
 resource_size_t __weak pcibios_align_resource(void *data,
 					      const struct resource *res,
+					      const struct resource *empty_res,
 					      resource_size_t size,
 					      resource_size_t align)
 {
-       return res->start;
+	return res->start;
 }
 
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 0679dd434719..949e69921fe9 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -602,7 +602,8 @@ static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
 
 static resource_size_t
 pcmcia_align(void *align_data, const struct resource *res,
-	resource_size_t size, resource_size_t align)
+	     const struct resource *empty_res,
+	     resource_size_t size, resource_size_t align)
 {
 	struct pcmcia_align_data *data = align_data;
 	struct resource_map *m;
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 19d5e04564d9..3c73c9c0d4f7 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -202,6 +202,7 @@ enum {
  * typedef resource_alignf - Resource alignment callback
  * @data:	Private data used by the callback
  * @res:	Resource candidate range (an empty resource space)
+ * @empty_res:	Empty resource range without alignment applied
  * @size:	The minimum size of the empty space
  * @align:	Alignment from the constraints
  *
@@ -212,6 +213,7 @@ enum {
  */
 typedef resource_size_t (*resource_alignf)(void *data,
 					   const struct resource *res,
+					   const struct resource *empty_res,
 					   resource_size_t size,
 					   resource_size_t align);
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d5123..ac332ff9da9f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1206,9 +1206,10 @@ int __must_check pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup(char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-resource_size_t pcibios_align_resource(void *, const struct resource *,
-				resource_size_t,
-				resource_size_t);
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				       const struct resource *empty_res,
+				       resource_size_t size,
+				       resource_size_t align);
 
 /* Generic PCI functions used internally */
 
diff --git a/kernel/resource.c b/kernel/resource.c
index 1e2f1dfc0edd..1b8d3101bdc6 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -759,7 +759,8 @@ static int __find_resource_space(struct resource *root, struct resource *old,
 			alloc.flags = avail.flags;
 			if (alignf) {
 				alloc.start = alignf(constraint->alignf_data,
-						     &avail, size, constraint->align);
+						     &avail, &tmp,
+						     size, constraint->align);
 			} else {
 				alloc.start = avail.start;
 			}
-- 
2.39.5

[PATCH 03/10] resource: Rename 'tmp' variable to 'full_avail'

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:59:17

__find_resource_space() has variable called 'tmp'. Rename it to
'full_avail' to better indicate its purpose.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 kernel/resource.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/kernel/resource.c b/kernel/resource.c
index 1b8d3101bdc6..8c5fcb30fc33 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -727,39 +727,39 @@ static int __find_resource_space(struct resource *root, struct resource *old,
 				 struct resource_constraint *constraint)
 {
 	struct resource *this = root->child;
-	struct resource tmp = *new, avail, alloc;
+	struct resource full_avail = *new, avail, alloc;
 	resource_alignf alignf = constraint->alignf;
 
-	tmp.start = root->start;
+	full_avail.start = root->start;
 	/*
 	 * Skip past an allocated resource that starts at 0, since the assignment
-	 * of this->start - 1 to tmp->end below would cause an underflow.
+	 * of this->start - 1 to full_avail->end below would cause an underflow.
 	 */
 	if (this && this->start == root->start) {
-		tmp.start = (this == old) ? old->start : this->end + 1;
+		full_avail.start = (this == old) ? old->start : this->end + 1;
 		this = this->sibling;
 	}
 	for(;;) {
 		if (this)
-			tmp.end = (this == old) ?  this->end : this->start - 1;
+			full_avail.end = (this == old) ?  this->end : this->start - 1;
 		else
-			tmp.end = root->end;
+			full_avail.end = root->end;
 
-		if (tmp.end < tmp.start)
+		if (full_avail.end < full_avail.start)
 			goto next;
 
-		resource_clip(&tmp, constraint->min, constraint->max);
-		arch_remove_reservations(&tmp);
+		resource_clip(&full_avail, constraint->min, constraint->max);
+		arch_remove_reservations(&full_avail);
 
 		/* Check for overflow after ALIGN() */
-		avail.start = ALIGN(tmp.start, constraint->align);
-		avail.end = tmp.end;
+		avail.start = ALIGN(full_avail.start, constraint->align);
+		avail.end = full_avail.end;
 		avail.flags = new->flags;
-		if (avail.start >= tmp.start) {
+		if (avail.start >= full_avail.start) {
 			alloc.flags = avail.flags;
 			if (alignf) {
 				alloc.start = alignf(constraint->alignf_data,
-						     &avail, &tmp,
+						     &avail, &full_avail,
 						     size, constraint->align);
 			} else {
 				alloc.start = avail.start;
@@ -777,7 +777,7 @@ next:		if (!this || this->end == root->end)
 			break;
 
 		if (this != old)
-			tmp.start = this->end + 1;
+			full_avail.start = this->end + 1;
 		this = this->sibling;
 	}
 	return -EBUSY;
-- 
2.39.5

[PATCH 04/10] ARM/PCI: Remove unnecessary second application of align

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:59:38

Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/arm/kernel/bios32.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 5b9b4fcd0e54..cedb83a85dd9 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -571,8 +571,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if (res->flags & IORESOURCE_IO && start & 0x300)
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	host_bridge = pci_find_host_bridge(dev->bus);
 
 	if (host_bridge->align_resource)
-- 
2.39.5

[PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 16:59:52

Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/m68k/kernel/pcibios.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if ((res->flags & IORESOURCE_IO) && (start & 0x300))
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	return start;
 }
 
-- 
2.39.5

[PATCH 06/10] MIPS: PCI: Remove unnecessary second application of align

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:00:06

Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/mips/pci/pci-generic.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/mips/pci/pci-generic.c b/arch/mips/pci/pci-generic.c
index f4957c26efc7..aaa1d6de8bef 100644
--- a/arch/mips/pci/pci-generic.c
+++ b/arch/mips/pci/pci-generic.c
@@ -32,8 +32,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if (res->flags & IORESOURCE_IO && start & 0x300)
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	host_bridge = pci_find_host_bridge(dev->bus);
 
 	if (host_bridge->align_resource)
-- 
2.39.5

[PATCH 07/10] parisc/PCI: Cleanup align handling

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:00:19

Caller of pcibios_align_resource() (__find_resource_space()) already
aligns the start address by 'alignment' so aligning is only necessary
if align > alignment.

Change also to use ALIGN() instead of open-coding.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/parisc/kernel/pci.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index f99b20795d5a..f50be1a63c4c 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -8,6 +8,7 @@
  * Copyright (C) 1999-2001 Hewlett-Packard Company
  * Copyright (C) 1999-2001 Grant Grundler
  */
+#include <linux/align.h>
 #include <linux/eisa.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -200,7 +201,7 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 				       resource_size_t size,
 				       resource_size_t alignment)
 {
-	resource_size_t mask, align, start = res->start;
+	resource_size_t align, start = res->start;
 
 	DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
 		pci_name(((struct pci_dev *) data)),
@@ -209,11 +210,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 
 	/* If it's not IO, then it's gotta be MEM */
 	align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
-
-	/* Align to largest of MIN or input size */
-	mask = max(alignment, align) - 1;
-	start += mask;
-	start &= ~mask;
+	if (align > alignment)
+		start = ALIGN(start, align);
 
 	return start;
 }
-- 
2.39.5

[PATCH 08/10] PCI: Rename window_alignment() to pci_min_window_alignment()

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:00:32

window_alignment() lacks prefix. Rename it to pci_min_window_alignment()
in order to include the prefix and also add min to indicate the returned
window alignment is the minimum PCI spec and arch allows.

Also make it available in drivers/pci/pci.h as upcoming changes will need
to call it from outside of setup-bus.c.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 drivers/pci/pci.h       | 3 +++
 drivers/pci/setup-bus.c | 6 +++---
 2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13d998fbacce..2edb03c1c6b9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1053,6 +1053,9 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
 	return resource_alignment(res);
 }
 
+resource_size_t pci_min_window_alignment(struct pci_bus *bus,
+					 unsigned long type);
+
 void pci_acs_init(struct pci_dev *dev);
 void pci_enable_acs(struct pci_dev *dev);
 #ifdef CONFIG_PCI_QUIRKS
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 61f769aaa2f6..edc0d682dcad 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1035,7 +1035,7 @@ resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
 #define PCI_P2P_DEFAULT_IO_ALIGN	SZ_4K
 #define PCI_P2P_DEFAULT_IO_ALIGN_1K	SZ_1K
 
-static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
+resource_size_t pci_min_window_alignment(struct pci_bus *bus, unsigned long type)
 {
 	resource_size_t align = 1, arch_align;
 
@@ -1084,7 +1084,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
 	if (resource_assigned(b_res))
 		return;
 
-	min_align = window_alignment(bus, IORESOURCE_IO);
+	min_align = pci_min_window_alignment(bus, IORESOURCE_IO);
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		struct resource *r;
 
@@ -1339,7 +1339,7 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
 		}
 	}
 
-	win_align = window_alignment(bus, b_res->flags);
+	win_align = pci_min_window_alignment(bus, b_res->flags);
 	min_align = calculate_head_align(aligns, max_order);
 	min_align = max(min_align, win_align);
 	size0 = calculate_memsize(size, realloc_head ? 0 : add_size,
-- 
2.39.5

[PATCH 09/10] PCI: Align head space better

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:00:47

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>
---
 arch/arm/kernel/bios32.c         |  3 +++
 arch/m68k/kernel/pcibios.c       |  4 ++++
 arch/mips/pci/pci-generic.c      |  3 +++
 arch/mips/pci/pci-legacy.c       |  2 ++
 arch/parisc/kernel/pci.c         |  3 +++
 arch/powerpc/kernel/pci-common.c |  2 ++
 arch/sh/drivers/pci/pci.c        |  2 ++
 arch/x86/pci/i386.c              |  2 ++
 arch/xtensa/kernel/pci.c         |  2 ++
 drivers/pci/setup-res.c          | 39 +++++++++++++++++++++++++++++++-
 include/linux/pci.h              |  5 ++++
 kernel/resource.c                |  2 +-
 12 files changed, 67 insertions(+), 2 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..994c3bd36ef2 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 (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;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index c375e255c509..fbc05cda96ee 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -244,6 +244,41 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
 	return 0;
 }
 
+/*
+ * For mem bridge windows, try to relocate tail remainder space to space
+ * before res->start if there's enough free space there. This enables
+ * tighter packing for resources.
+ */
+resource_size_t pci_align_resource(struct pci_dev *dev,
+				   const struct resource *res,
+				   const struct resource *empty_res,
+				   resource_size_t size,
+				   resource_size_t align)
+{
+	resource_size_t remainder, start_addr;
+
+	if (!(res->flags & IORESOURCE_MEM))
+		return res->start;
+
+	if (IS_ALIGNED(size, align))
+		return res->start;
+
+	remainder = size - ALIGN_DOWN(size, align);
+	/* Don't mess with size that doesn't align with window size granularity */
+	if (!IS_ALIGNED(remainder, pci_min_window_alignment(dev->bus, res->flags)))
+		return res->start;
+	/* Try to place remainder that doesn't fill align before */
+	if (res->start < remainder)
+		return res->start;
+	start_addr = res->start - remainder;
+	if (empty_res->start > start_addr)
+		return res->start;
+
+	pci_dbg(dev, "%pR: moving candidate start address below align to %llx\n",
+		res, (unsigned long long)start_addr);
+	return start_addr;
+}
+
 /*
  * We don't have to worry about legacy ISA devices, so nothing to do here.
  * This is marked as __weak because multiple architectures define it; it should
@@ -255,7 +290,9 @@ resource_size_t __weak pcibios_align_resource(void *data,
 					      resource_size_t size,
 					      resource_size_t align)
 {
-	return res->start;
+	struct pci_dev *dev = data;
+
+	return pci_align_resource(dev, res, empty_res, size, align);
 }
 
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index ac332ff9da9f..cedf948dc614 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1210,6 +1210,11 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 				       const struct resource *empty_res,
 				       resource_size_t size,
 				       resource_size_t align);
+resource_size_t pci_align_resource(struct pci_dev *dev,
+				   const struct resource *res,
+				   const struct resource *empty_res,
+				   resource_size_t size,
+				   resource_size_t align);
 
 /* Generic PCI functions used internally */
 
diff --git a/kernel/resource.c b/kernel/resource.c
index 8c5fcb30fc33..d02a53fb95d8 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -766,7 +766,7 @@ static int __find_resource_space(struct resource *root, struct resource *old,
 			}
 			alloc.end = alloc.start + size - 1;
 			if (alloc.start <= alloc.end &&
-			    __resource_contains_unbound(&avail, &alloc)) {
+			    __resource_contains_unbound(&full_avail, &alloc)) {
 				new->start = alloc.start;
 				new->end = alloc.end;
 				return 0;
-- 
2.39.5

[PATCH 10/10] PCI: Fix alignment calculation for resource size larger than align

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:01:00

The commit bc75c8e50711 ("PCI: Rewrite bridge window head alignment
function") did not use if (r_size <= align) check from pbus_size_mem()
for the new head alignment bookkeeping structure (aligns2[]). In some
configurations, this can result in producing a gap into the bridge
window which the resource larger than its alignment cannot fill.

The old alignment calculation algorithm was removed by the subsequent
commit 3958bf16e2fe ("PCI: Stop over-estimating bridge window size")
which renamed the aligns2[] array leaving only aligns[] array.

Add the if (r_size <= align) check back to avoid this problem.

Fixes: bc75c8e50711 ("PCI: Rewrite bridge window head alignment function")
Closes: https://lore.kernel.org/all/b05a6f14-979d-42c9-924c-d8408cb12ae7@roeck-us.net/
Reported-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 drivers/pci/setup-bus.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index edc0d682dcad..e5af8799c36f 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1333,7 +1333,14 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
 			r_size = resource_size(r);
 			size += max(r_size, align);
 
-			aligns[order] += align;
+			/*
+			 * If resource's size is larger than its alignment,
+			 * some configurations result in an unwanted gap in
+			 * the head space that the larger resource cannot
+			 * fill.
+			 */
+			if (r_size <= align)
+				aligns[order] += align;
 			if (order > max_order)
 				max_order = order;
 		}
-- 
2.39.5

Re: [PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: Geert Uytterhoeven <geert@linux-m68k.org>
Date: 2026-03-24 17:06:41

CC gerg

On Tue, 24 Mar 2026 at 17:59, Ilpo Järvinen
[off-list ref] wrote:
quoted hunk
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/m68k/kernel/pcibios.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        if ((res->flags & IORESOURCE_IO) && (start & 0x300))
                start = (start + 0x3ff) & ~0x3ff;

-       start = (start + align - 1) & ~(align - 1);
-
        return start;
 }

--
2.39.5

Re: [PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: 2026-03-24 17:43:20

Hi Ilpo,

On Tue, 2026-03-24 at 18:56 +0200, Ilpo Järvinen wrote:
quoted hunk
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/m68k/kernel/pcibios.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if ((res->flags & IORESOURCE_IO) && (start & 0x300))
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	return start;
 }
Sorry if it's a stupid question, but what does "am68k" in the subject refer to?

Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913

Re: [PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-24 17:56:13

On Tue, 24 Mar 2026, John Paul Adrian Glaubitz wrote:
Hi Ilpo,

On Tue, 2026-03-24 at 18:56 +0200, Ilpo Järvinen wrote:
quoted
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/m68k/kernel/pcibios.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if ((res->flags & IORESOURCE_IO) && (start & 0x300))
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	return start;
 }
Sorry if it's a stupid question, but what does "am68k" in the subject refer to?
The extra "a" is a typo. I'm sorry about that.

-- 
 i.

Re: [PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: 2026-03-24 18:36:38

On Tue, 2026-03-24 at 19:55 +0200, Ilpo Järvinen wrote:
On Tue, 24 Mar 2026, John Paul Adrian Glaubitz wrote:
quoted
Hi Ilpo,

On Tue, 2026-03-24 at 18:56 +0200, Ilpo Järvinen wrote:
quoted
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 arch/m68k/kernel/pcibios.c | 2 --
 1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 	if ((res->flags & IORESOURCE_IO) && (start & 0x300))
 		start = (start + 0x3ff) & ~0x3ff;
 
-	start = (start + align - 1) & ~(align - 1);
-
 	return start;
 }
Sorry if it's a stupid question, but what does "am68k" in the subject refer to?
The extra "a" is a typo. I'm sorry about that.
No worries, I just thought I missed something obvious and felt stupid to ask ;-).

Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913

Re: [PATCH 09/10] PCI: Align head space better

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-25 12:04:16

On Tue, 24 Mar 2026, Ilpo Järvinen wrote:
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>
---
 arch/arm/kernel/bios32.c         |  3 +++
 arch/m68k/kernel/pcibios.c       |  4 ++++
 arch/mips/pci/pci-generic.c      |  3 +++
 arch/mips/pci/pci-legacy.c       |  2 ++
 arch/parisc/kernel/pci.c         |  3 +++
 arch/powerpc/kernel/pci-common.c |  2 ++
 arch/sh/drivers/pci/pci.c        |  2 ++
 arch/x86/pci/i386.c              |  2 ++
 arch/xtensa/kernel/pci.c         |  2 ++
 drivers/pci/setup-res.c          | 39 +++++++++++++++++++++++++++++++-
 include/linux/pci.h              |  5 ++++
 kernel/resource.c                |  2 +-
 12 files changed, 67 insertions(+), 2 deletions(-)
quoted hunk
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 7a0522316ee3..994c3bd36ef2 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 (res->flags & IORESOURCE_MEM) {
I'll be adding the missing if into this in v2 (found by sashiko). It seems 
lkp didn't test this so it was not caught earlier.
+		start = pci_align_resource(dev, res, empty_res, size, align);
 	}
 
 	return start;
-- 
 i.

Re: [PATCH 00/10] PCI: Improve head free space usage

From: Bjorn Helgaas <helgaas@kernel.org>
Date: 2026-03-26 19:25:22

[+cc Xifer; thanks very much for reporting and testing!]

On Tue, Mar 24, 2026 at 06:56:23PM +0200, Ilpo Järvinen wrote:
Hi all,

This series attempts to take advantage of free head space (the free
space before the aligned start address) in order to generally produce a
tighter packing of the resources/bridge windows.

The recent changes to the resource fitting algorithm caused resource
allocation failures in some cases where a bridge window that is sized
to be gapless could no longer be assigned. The previous algorithm left
a huge gaps which allowed it to place the remainder (non-aligning part
of the size) before the start address of used for the gapless fit,
whereas the new gapless approach always had to place the remainder
after the aligning part of the resources. There is not always space
for the remainder triggering those failures (e.g., when the aligning
part must be placed at the top of the window).

This series attempts to allow placing the remainder once again before
the aligning part, but now without leaving huge gaps to retain the
benefits of the gapless bridge windows. The approach is somewhat hacky
but should work thanks to PCI resources fundamentally consisting only
power-of-two atoms.

There maybe cases where architecture would not want to do such
relocation. This series adds the relocation to arch
pcibios_align_resource() functions to allow all of them taking
advantage of the better resource packing but if somebody objects doing
this relocation for a particular arch, I can remove it, please just let
me know (this relocation doesn't seem critical unless there are
regressions).

Ilpo Järvinen (10):
  resource: Add __resource_contains_unbound() for internal contains
    checks
  resource: Pass full extent of empty space to resource_alignf CB
  resource: Rename 'tmp' variable to 'full_avail'
  ARM/PCI: Remove unnecessary second application of align
  am68k/PCI: Remove unnecessary second application of align
  MIPS: PCI: Remove unnecessary second application of align
  parisc/PCI: Cleanup align handling
  PCI: Rename window_alignment() to pci_min_window_alignment()
  PCI: Align head space better
  PCI: Fix alignment calculation for resource size larger than align

 arch/alpha/kernel/pci.c          |  1 +
 arch/arm/kernel/bios32.c         |  9 ++++---
 arch/m68k/kernel/pcibios.c       |  8 +++++--
 arch/mips/pci/pci-generic.c      |  8 ++++---
 arch/mips/pci/pci-legacy.c       |  3 +++
 arch/parisc/kernel/pci.c         | 17 ++++++++------
 arch/powerpc/kernel/pci-common.c |  6 ++++-
 arch/s390/pci/pci.c              |  1 +
 arch/sh/drivers/pci/pci.c        |  6 ++++-
 arch/x86/pci/i386.c              |  5 +++-
 arch/xtensa/kernel/pci.c         |  3 +++
 drivers/pci/pci.h                |  3 +++
 drivers/pci/setup-bus.c          | 15 ++++++++----
 drivers/pci/setup-res.c          | 40 +++++++++++++++++++++++++++++++-
 drivers/pcmcia/rsrc_nonstatic.c  |  3 ++-
 include/linux/ioport.h           | 22 +++++++++++++++---
 include/linux/pci.h              | 12 +++++++---
 kernel/resource.c                | 33 +++++++++++++-------------
 18 files changed, 149 insertions(+), 46 deletions(-)
I added Xifer's tested-by, fixed the "am68k" and missing "if"
typos, and applied these to pci/resource for v7.1.

Ilpo, if you post a v2 with more changes, I'll update to it.  I
applied the series now to get a head start on 0-day building and into
next.

Re: [PATCH 05/10] am68k/PCI: Remove unnecessary second application of align

From: Greg Ungerer <gerg@linux-m68k.org>
Date: 2026-03-27 02:56:06


On 25/3/26 02:56, Ilpo Järvinen wrote:
Aligning res->start by align inside pcibios_align_resource() is
unnecessary because caller of pcibios_align_resource() is
__find_resource_space() that aligns res->start with align before
calling pcibios_align_resource().

Aligning by align in case of IORESOURCE_IO && start & 0x300 cannot ever
result in changing start either because 0x300 bits would have not
survived the earlier alignment if align was large enough to have an
impact.

Thus, remove the duplicated aligning from pcibios_align_resource().

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
LGTM.

Acked-by: Greg Ungerer <gerg@linux-m68k.org>

quoted hunk
---
  arch/m68k/kernel/pcibios.c | 2 --
  1 file changed, 2 deletions(-)
diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c
index 1415f6e4e5ce..7e286ee1976b 100644
--- a/arch/m68k/kernel/pcibios.c
+++ b/arch/m68k/kernel/pcibios.c
@@ -36,8 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
  	if ((res->flags & IORESOURCE_IO) && (start & 0x300))
  		start = (start + 0x3ff) & ~0x3ff;
  
-	start = (start + align - 1) & ~(align - 1);
-
  	return start;
  }
  

Re: [PATCH 00/10] PCI: Improve head free space usage

From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Date: 2026-03-27 10:29:12

On Thu, 26 Mar 2026, Bjorn Helgaas wrote:
[+cc Xifer; thanks very much for reporting and testing!]

On Tue, Mar 24, 2026 at 06:56:23PM +0200, Ilpo Järvinen wrote:
quoted
Hi all,

This series attempts to take advantage of free head space (the free
space before the aligned start address) in order to generally produce a
tighter packing of the resources/bridge windows.

The recent changes to the resource fitting algorithm caused resource
allocation failures in some cases where a bridge window that is sized
to be gapless could no longer be assigned. The previous algorithm left
a huge gaps which allowed it to place the remainder (non-aligning part
of the size) before the start address of used for the gapless fit,
whereas the new gapless approach always had to place the remainder
after the aligning part of the resources. There is not always space
for the remainder triggering those failures (e.g., when the aligning
part must be placed at the top of the window).

This series attempts to allow placing the remainder once again before
the aligning part, but now without leaving huge gaps to retain the
benefits of the gapless bridge windows. The approach is somewhat hacky
but should work thanks to PCI resources fundamentally consisting only
power-of-two atoms.

There maybe cases where architecture would not want to do such
relocation. This series adds the relocation to arch
pcibios_align_resource() functions to allow all of them taking
advantage of the better resource packing but if somebody objects doing
this relocation for a particular arch, I can remove it, please just let
me know (this relocation doesn't seem critical unless there are
regressions).

Ilpo Järvinen (10):
  resource: Add __resource_contains_unbound() for internal contains
    checks
  resource: Pass full extent of empty space to resource_alignf CB
  resource: Rename 'tmp' variable to 'full_avail'
  ARM/PCI: Remove unnecessary second application of align
  am68k/PCI: Remove unnecessary second application of align
  MIPS: PCI: Remove unnecessary second application of align
  parisc/PCI: Cleanup align handling
  PCI: Rename window_alignment() to pci_min_window_alignment()
  PCI: Align head space better
  PCI: Fix alignment calculation for resource size larger than align

 arch/alpha/kernel/pci.c          |  1 +
 arch/arm/kernel/bios32.c         |  9 ++++---
 arch/m68k/kernel/pcibios.c       |  8 +++++--
 arch/mips/pci/pci-generic.c      |  8 ++++---
 arch/mips/pci/pci-legacy.c       |  3 +++
 arch/parisc/kernel/pci.c         | 17 ++++++++------
 arch/powerpc/kernel/pci-common.c |  6 ++++-
 arch/s390/pci/pci.c              |  1 +
 arch/sh/drivers/pci/pci.c        |  6 ++++-
 arch/x86/pci/i386.c              |  5 +++-
 arch/xtensa/kernel/pci.c         |  3 +++
 drivers/pci/pci.h                |  3 +++
 drivers/pci/setup-bus.c          | 15 ++++++++----
 drivers/pci/setup-res.c          | 40 +++++++++++++++++++++++++++++++-
 drivers/pcmcia/rsrc_nonstatic.c  |  3 ++-
 include/linux/ioport.h           | 22 +++++++++++++++---
 include/linux/pci.h              | 12 +++++++---
 kernel/resource.c                | 33 +++++++++++++-------------
 18 files changed, 149 insertions(+), 46 deletions(-)
I added Xifer's tested-by, fixed the "am68k" and missing "if"
typos, and applied these to pci/resource for v7.1.

Ilpo, if you post a v2 with more changes, I'll update to it.  I
applied the series now to get a head start on 0-day building and into
next.
Thanks.

I don't have anything in addition to those.

-- 
 i.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help