Dear maintainers, (PCI in particular, but also RPi5 folks)
This problem is real, and I have exhaustively searched for solutions. Recap: device tree descriptions often stop at a bridge device node. PCI enumeration then finds a device hanging off that bridge. It will create a "bus node" named "pci@0,0" or the like, and connect the found device to it. If the bridge has a non-zero offset for inbound accesses, dev_phys_to_bus, whose job it is to return this offset, will fail to do so in these cases, because it looks only 1 level up. One level up is the bus node, no DT association, so no DMA constraints. I found 3 possible ways to fix this. Solution A: search up the tree further than only one level, as patch 1 On Fri, 25 Sep 2026 12:56:15 +0200 (CEST) [email protected] (Torsten Duwe) wrote: > From: Torsten Duwe <[email protected]> > > If a device node got created dynamically, there is no guarantee that the > parent node has an associated device tree node which could specify dma > constraints. Especially PCI(e) enumeration adds intermediate "bus nodes", > also dynamically. > > Try harder to find the correct configuration by walking up the tree until > a DT association is found. > > Suggested-by: Neil Armstrong <[email protected]> > Signed-off-by: Torsten Duwe <[email protected]> > Reviewed-by: Peter Robinson <[email protected]> > Tested-by: Peter Robinson <[email protected]> > --- > drivers/core/device.c | 14 +++++++++++++- > 1 file changed, 13 insertions(+), 1 deletion(-) > > diff --git a/drivers/core/device.c b/drivers/core/device.c > index 6024534ff93..86d73b8222d 100644 > --- a/drivers/core/device.c > +++ b/drivers/core/device.c > @@ -459,7 +459,19 @@ static int device_get_dma_constraints(struct udevice > *dev) > u64 size = 0; > int ret; > > - if (!CONFIG_IS_ENABLED(DM_DMA) || !parent || !dev_has_ofnode(parent)) > + if (!CONFIG_IS_ENABLED(DM_DMA) || !parent) > + return 0; > + > + /* Look for the first node in the parent chain */ > + while (parent) { > + if (dev_has_ofnode(parent)) > + break; > + > + parent = dev_get_parent(parent); > + } > + > + /* No parents have a node, bail out */ > + if (!parent) > return 0; > > /* Solution B: clone/link the bridge's DT node on bus node creation: diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4bdd1f7477f..af383475c82 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -780,8 +780,18 @@ static int pci_find_and_bind_driver(struct udevice *parent, find_id->vendor, find_id->device); /* Determine optional OF node */ - if (ofnode_valid(dev_ofnode(parent))) + if (ofnode_valid(dev_ofnode(parent))) { pci_dev_find_ofnode(parent, bdf, &node); + /* + * For devices enumerated dynamically without a matching DT + * entry (e.g. an NVMe or a PCI-to-PCI bridge below a bridge), + * reuse the parent's OF node so the device still has one. This + * lets device_get_dma_constraints() reach the grandparent's + * dma-ranges for dynamically-enumerated devices. + */ + if (!ofnode_valid(node)) + node = dev_ofnode(parent); + } if (ofnode_valid(node) && !ofnode_is_enabled(node)) { debug("%s: Ignoring disabled device\n", __func__); or Solution C: demand device tree providers always correctly add the bus node, maybe using an overlay file or EEPROM. Solution A seems to be the least problematic one; it enhances U-Boot's capabilities. Solution B is more like the Linux kernel does it, but without allocating its own node, which makes it look a bit hacky. Solution C would be for an ideal world [TM] ;) Nonetheless we could at least for the RPi5 craft a DT overlay and send it upstream. What do you think? Who is going to decide on this? Torsten
