On 2026-08-06T18:18:18, Scott Moser <[email protected]> wrote: > dm: pci: fix uninitialized fdt_pci_addr fall-through in pci_get_devfn > > pci_get_devfn() reads addr.phys_hi and returns the low bits of it as the > requested devfn even on the -ENOENT branch, where ofnode_read_pci_addr() > has NOT written *addr. The C standard leaves that read undefined; in > practice the returned value depends on the compilers stack layout and on > -ftrivial-auto-var-init. That value ends up in pplat->devfn (set by > pci_uclass_child_post_bind()) and is later compared for equality in > pci_bus_find_devfn() during PCI enumeration, so an under-determined > value produces an under-determined driver-binding outcome. > > Concretely, this fires on Raspberry Pi 5 (BCM2712) when built with GCC > -ftrivial-auto-var-init=zero. In that build addr.phys_hi is zeroed > rather than left as stack junk, so pci_get_devfn() returns 0 for every > DT-declared non-PCI child of a PCI bus. The Pi 5 device tree includes > one such child under the second root complex -- the rp1 simple-bus > node representing the on-SoC RP1 south bridge as seen from the OS > side. Under zero-init: > > * pci_uclass_child_post_bind(rp1) sets pplat->devfn = 0 > * pci_bind_bus_devices() of the second root complex reads vendor at > bdf 02:00.0, calls pci_bus_find_devfn(bus, 0x0000, &dev) > * pci_bus_find_devfn() finds rp1 with pplat->devfn == 0x0000 == the > requested devfn, returns it as the pre-bound match > * pci_find_and_bind_driver() is skipped; the RP1 root port is never > bound as pci_bridge_drv and its downstream bus is never enumerated > * dm_pciauto_postscan_setup_bridge() then writes PCI_SUBORDINATE_BUS > = 0 and PCI_MEMORY_LIMIT = 0 on the root port; Linux flags the > bridge as "bridge configuration invalid ([bus 01-00])", the rp1 > driver fails to enable the endpoint with -EINVAL, and every > RP1-hosted peripheral (USB, onboard Ethernet, ttyAMA10) is > non-functional for the rest of boot. > > Under the default -ftrivial-auto-var-init=uninitialized, addr.phys_hi > happens to be non-zero stack residue that does not collide with the > requested devfn, so the same code path just returns -ENODEV from > pci_bus_find_devfn() and pci_find_and_bind_driver() correctly runs the > fallback. The bug has been latent since introduction; -zero exposes it > deterministically. > > A "reg" property that is simply absent now consistently returns -ENODEV, > matching the documented contract in include/dm/pci.h, instead of a value > that depends on stack state. A malformed "reg" property still returns > -EINVAL, as it did before this fix. > > Fixes: b52142004fbd ("pci: Add pci_get_devfn() to extract devfn from the > fdt_pci_addr") > Signed-off-by: Dustin Kirkland <[email protected]> > Cc: Scott Moser <[email protected]> > > drivers/core/util.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass <[email protected]>
