]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: Fix premature removal from realloc_head list during resource assignment
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 13 Mar 2026 08:45:50 +0000 (10:45 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 26 Mar 2026 20:00:39 +0000 (15:00 -0500)
reassign_resources_sorted() checks for two things:

a) Resource assignment failures for mandatory resources by checking if the
   resource remains unassigned, which are known to always repeat, and does
   not attempt to assign them again.

b) That resource is not among the ones being processed/assigned at this
   stage, leading to skip processing such resources in
   reassign_resources_sorted() as well (resource assignment progresses
   one PCI hierarchy level at a time).

The problem here is that a) is checked before b), but b) also implies the
resource is not being assigned yet, making also a) true. As a) only skips
resource assignment but still removes the resource from realloc_head, the
later stages that would need to process the information in realloc_head
cannot obtain the optional size information anymore. This leads to
considering only non-optional part for bridge windows deeper in the PCI
hierarchy.

This problem has been observed during rescan (add_size is not considered
while attempting assignment for 0000:e2:00.0 indicating the corresponding
entry was removed from realloc_head while processing resource assignments
for 0000:e1):

  pci_bus 0000:e1: scanning bus
  ...
  pci 0000:e3:01.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e4] add_size 60c000000 add_align 800000000
  pci 0000:e3:01.0: bridge window [mem 0x00100000-0x000fffff] to [bus e4] add_size 200000 add_align 200000
  pci 0000:e3:02.0: disabling bridge window [mem 0x00000000-0x000fffff 64bit pref] to [bus e5] (unused)
  pci 0000:e2:00.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e3-e5] add_size 60c000000 add_align 800000000
  pci 0000:e2:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus e3-e5] add_size 200000 add_align 200000
  pcieport 0000:e1:02.0: bridge window [io  size 0x2000]: can't assign; no space
  pcieport 0000:e1:02.0: bridge window [io  size 0x2000]: failed to assign
  pcieport 0000:e1:02.0: bridge window [io  0x1000-0x2fff]: resource restored
  pcieport 0000:e1:02.0: bridge window [io  0x1000-0x2fff]: resource restored
  pcieport 0000:e1:02.0: bridge window [io  size 0x2000]: can't assign; no space
  pcieport 0000:e1:02.0: bridge window [io  size 0x2000]: failed to assign
  pci 0000:e2:00.0: bridge window [mem 0x28f000000000-0x28f800ffffff 64bit pref]: assigned

Fixes: 96336ec70264 ("PCI: Perform reset_resource() and build fail list in sync")
Reported-by: Peter Nisbet <peter.nisbet@intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Peter Nisbet <peter.nisbet@intel.com>
Link: https://patch.msgid.link/20260313084551.1934-1-ilpo.jarvinen@linux.intel.com
drivers/pci/setup-bus.c

index 1f87b018799f9b003794d19f13cb9148b23406ef..9506845c112c47e8a64b601ec19e73755a37340f 100644 (file)
@@ -434,6 +434,10 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
                dev = add_res->dev;
                idx = pci_resource_num(dev, res);
 
+               /* Skip this resource if not found in head list */
+               if (!res_to_dev_res(head, res))
+                       continue;
+
                /*
                 * Skip resource that failed the earlier assignment and is
                 * not optional as it would just fail again.
@@ -442,10 +446,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
                    !pci_resource_is_optional(dev, idx))
                        goto out;
 
-               /* Skip this resource if not found in head list */
-               if (!res_to_dev_res(head, res))
-                       continue;
-
                res_name = pci_resource_name(dev, idx);
                add_size = add_res->add_size;
                align = add_res->min_align;