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


Reply via email to