]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Account fully optional bridge windows correctly
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Wed, 18 Feb 2026 22:34:18 +0000 (00:34 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 19 Feb 2026 21:33:40 +0000 (15:33 -0600)
pbus_size_mem_optional() adds dev_res->add_size of a bridge window into
children_add_size when the window has a non-optional part. However, if the
bridge window is fully optional, only r_size is added (which is zero for
such a window).

Also, a second dev_res entry will be added by pci_dev_res_add_to_list()
into realloc_head for the bridge window (resulting in triggering the
realloc_head-must-be-fully-consumed sanity check after a single pass of the
resource assignment algorithm):

  WARNING: drivers/pci/setup-bus.c:2153 at pci_assign_unassigned_root_bus_resources+0xa5/0x260

Correct these problems by always adding dev_res->add_size for bridge
windows and not calling pci_dev_res_add_to_list() if the dev_res entry
exists.

Fixes: 6a5e64c75e82 ("PCI: Add pbus_mem_size_optional() to handle optional sizes")
Reported-by: RavitejaX Veesam <ravitejax.veesam@intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: RavitejaX Veesam <ravitejax.veesam@intel.com>
Link: https://patch.msgid.link/20260218223419.22366-1-ilpo.jarvinen@linux.intel.com
drivers/pci/setup-bus.c

index f30d1f7f023a7078f5552c4179615553460c9faa..bd66ac47b3b97a608deaf1933103026b6d9718bd 100644 (file)
@@ -1224,31 +1224,34 @@ static bool pbus_size_mem_optional(struct pci_dev *dev, int resno,
        struct resource *res = pci_resource_n(dev, resno);
        bool optional = pci_resource_is_optional(dev, resno);
        resource_size_t r_size = resource_size(res);
-       struct pci_dev_resource *dev_res;
+       struct pci_dev_resource *dev_res = NULL;
 
        if (!realloc_head)
                return false;
 
-       if (!optional) {
-               /*
-                * Only bridges have optional sizes in realloc_head at this
-                * point. As res_to_dev_res() walks the entire realloc_head
-                * list, skip calling it when known unnecessary.
-                */
-               if (!pci_resource_is_bridge_win(resno))
-                       return false;
-
+       /*
+        * Only bridges have optional sizes in realloc_head at this
+        * point. As res_to_dev_res() walks the entire realloc_head
+        * list, skip calling it when known unnecessary.
+        */
+       if (pci_resource_is_bridge_win(resno)) {
                dev_res = res_to_dev_res(realloc_head, res);
                if (dev_res) {
                        *children_add_size += dev_res->add_size;
                        *add_align = max(*add_align, dev_res->min_align);
                }
+       }
 
+       if (!optional)
                return false;
-       }
 
-       /* Put SRIOV requested res to the optional list */
-       pci_dev_res_add_to_list(realloc_head, dev, res, 0, align);
+       /*
+        * Put requested res to the optional list if not there yet (SR-IOV,
+        * disabled ROM). Bridge windows with an optional part are already
+        * on the list.
+        */
+       if (!dev_res)
+               pci_dev_res_add_to_list(realloc_head, dev, res, 0, align);
        *children_add_size += r_size;
        *add_align = max(align, *add_align);