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]>

Reply via email to