]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Fix bridge window alignment with optional resources
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 19 Dec 2025 17:40:14 +0000 (19:40 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 26 Jan 2026 17:00:28 +0000 (11:00 -0600)
pbus_size_mem() has two alignments, one for required resources in min_align
and another in add_align that takes account optional resources.

The add_align is applied to the bridge window through the realloc_head
list. It can happen, however, that add_align is larger than min_align but
calculated size1 and size0 are equal due to extra tailroom (e.g., hotplug
reservation, tail alignment), and therefore no entry is created to the
realloc_head list. Without the bridge appearing in the realloc head,
add_align is lost when pbus_size_mem() returns.

The problem is visible in this log for 0000:05:00.0 which lacks
add_size ... add_align ... line that would indicate it was added into
the realloc_head list:

  pci 0000:05:00.0: PCI bridge to [bus 06-16]
  ...
  pci 0000:06:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus 07] requires relaxed alignment rules
  pci 0000:06:06.0: bridge window [mem 0x00100000-0x001fffff] to [bus 0a] requires relaxed alignment rules
  pci 0000:06:07.0: bridge window [mem 0x00100000-0x003fffff] to [bus 0b] requires relaxed alignment rules
  pci 0000:06:08.0: bridge window [mem 0x00800000-0x00ffffff 64bit pref] to [bus 0c-14] requires relaxed alignment rules
  pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] requires relaxed alignment rules
  pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] requires relaxed alignment rules
  pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] add_size 100000 add_align 1000000
  pci 0000:06:0c.0: bridge window [mem 0x00100000-0x001fffff] to [bus 15] requires relaxed alignment rules
  pci 0000:06:0d.0: bridge window [mem 0x00100000-0x001fffff] to [bus 16] requires relaxed alignment rules
  pci 0000:06:0d.0: bridge window [mem 0x00100000-0x001fffff] to [bus 16] requires relaxed alignment rules
  pci 0000:05:00.0: bridge window [mem 0xd4800000-0xd97fffff]: assigned
  pci 0000:05:00.0: bridge window [mem 0x1060000000-0x10607fffff 64bit pref]: assigned
  pci 0000:06:08.0: bridge window [mem size 0x04900000]: can't assign; no space
  pci 0000:06:08.0: bridge window [mem size 0x04900000]: failed to assign

While this bug itself seems old, it has likely become more visible after
the relaxed tail alignment that does not grossly overestimate the size
needed for the bridge window.

Make sure add_align > min_align too results in adding an entry into the
realloc head list. In addition, add handling to the cases where add_size is
zero while only alignment differs.

Fixes: d74b9027a4da ("PCI: Consider additional PF's IOV BAR alignment in sizing and assigning")
Reported-by: Malte Schröder <malte+lkml@tnxip.de>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Malte Schröder <malte+lkml@tnxip.de>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20251219174036.16738-2-ilpo.jarvinen@linux.intel.com
drivers/pci/setup-bus.c

index 6e90f46f52afddf437142948540b05b3a9b5bec3..4b918ff4d2d8b916dbf13ef0b332899153314dc5 100644 (file)
@@ -14,6 +14,7 @@
  *          tighter packing. Prefetchable range support.
  */
 
+#include <linux/align.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/init.h>
@@ -456,7 +457,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
                                        "%s %pR: ignoring failure in optional allocation\n",
                                        res_name, res);
                        }
-               } else if (add_size > 0) {
+               } else if (add_size > 0 || !IS_ALIGNED(res->start, align)) {
                        res->flags |= add_res->flags &
                                 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
                        if (pci_reassign_resource(dev, idx, add_size, align))
@@ -1442,12 +1443,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
 
        resource_set_range(b_res, min_align, size0);
        b_res->flags |= IORESOURCE_STARTALIGN;
-       if (bus->self && size1 > size0 && realloc_head) {
+       if (bus->self && realloc_head && (size1 > size0 || add_align > min_align)) {
                b_res->flags &= ~IORESOURCE_DISABLED;
-               add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
+               add_size = size1 > size0 ? size1 - size0 : 0;
+               add_to_list(realloc_head, bus->self, b_res, add_size, add_align);
                pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
                           b_res, &bus->busn_res,
-                          (unsigned long long) (size1 - size0),
+                          (unsigned long long) add_size,
                           (unsigned long long) add_align);
        }
 }