On 10/26/26 11:01, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) 
to consider:
- [Medium] PCI: number_initial clobbered on bus rescan in 
pci_scan_bridge_extend()
--

commit 66abeabff58a043b28934ad23308d764456e9fa4
Author: Mario Limonciello <[email protected]>

PCI: Preserve the initial bus number in pci_bus

This commit saves the firmware-assigned secondary bus number before PCI bus
renumbering and stores it in pci_bus->number_initial so drivers can match
firmware records against the initial bus number.

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 27008e2ea5afc..9950a9dd1db1f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c

[ ... ]

@@ -1232,6 +1233,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus 
*parent,
/* Set up the primary, secondary and subordinate bus numbers */
        child->number = child->busn_res.start = busnr;
+       child->number_initial = busnr;
        child->primary = parent->busn_res.start;
        child->busn_res.end = 0xff;
@@ -1470,6 +1472,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
                        child = pci_add_new_bus(bus, dev, secondary);
                        if (!child)
                                goto out;
+                       child->number_initial = secondary;
                        child->primary = primary;
                        pci_bus_insert_busn_res(child, secondary, subordinate);
                        child->bridge_ctl = bctl;
@@ -1491,6 +1494,8 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
                 * do in the second pass.
                 */
                if (!pass) {
+                       if (!dev->secondary_busnr)
+                               dev->secondary_busnr = secondary;
                        if (pcibios_assign_all_busses() || broken)
/*
@@ -1529,6 +1534,10 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, 
struct pci_dev *dev,
                        pci_bus_insert_busn_res(child, next_busnr,
                                                bus->busn_res.end);
                }
+               if (dev->secondary_busnr) {
+                       child->number_initial = dev->secondary_busnr;
+                       dev->secondary_busnr = 0;
+               }

[Severity: Medium]
Can this overwrite child->number_initial with the reassigned runtime bus
number during a subsequent PCI bus rescan when pcibios_assign_all_busses()
is enabled?

During the initial scan of a bridge taking the bus reassignment branch in
pci_scan_bridge_extend(), pass 0 saves the firmware secondary bus number in
dev->secondary_busnr. Pass 1 then transfers it to child->number_initial,
resets dev->secondary_busnr to 0, and writes the newly assigned bus number
(next_busnr) into the bridge's PCI_PRIMARY_BUS register:

drivers/pci/probe.c:pci_scan_bridge_extend() {
     ...
                buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) |
                        FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) |
                        FIELD_PREP(PCI_SECONDARY_BUS_MASK, 
child->busn_res.start) |
                        FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, 
child->busn_res.end);

                /* We need to blast all three values with a single write */
                pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
     ...
}

When a later bus rescan occurs (for example via pci_rescan_bus(),
/sys/bus/pci/rescan, pci_rescan_bus_bridge_resize(), or hotplug), pass 0
reads PCI_PRIMARY_BUS again, where secondary is now the reassigned bus
number. Because dev->secondary_busnr was reset to 0 in the first scan,
!dev->secondary_busnr is true and dev->secondary_busnr is set to the
reassigned bus number.

In pass 1 of the rescan, pci_find_bus(pci_domain_nr(bus), next_busnr) finds
the existing child bus, and the block after if (!child) overwrites
child->number_initial with the reassigned bus number. A similar overwrite
can occur if pci_find_bus() finds an already-existing bus during hotplug.

Also, in the new-bus case, pci_add_new_bus() calls pci_alloc_child_bus(),
which sets child->number_initial = busnr (next_busnr) before calling
device_register(&child->dev), pcibios_add_bus(child), and
child->ops->add_bus(child), so those callbacks see the reassigned bus
number in child->number_initial before pci_scan_bridge_extend() updates it
from dev->secondary_busnr.


I'll dig in.  I initially think this one is true.

Reply via email to