* [PATCH 0/4] PCI: populate PCI host controller device nodes
@ 2026-05-21 8:36 Sascha Hauer
2026-05-21 8:36 ` [PATCH 1/4] of: fall back to parent-prefixed encoding when address translation fails Sascha Hauer
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Sascha Hauer @ 2026-05-21 8:36 UTC (permalink / raw)
To: BAREBOX
PCI devices usually don't have and don't need a representation in the
device tree, but sometimes they do. This series adds support for adding
device nodes for PCI devices to the barebox live tree similar to what
Linux does with CONFIG_PCI_DYNAMIC_OF_NODES enabled. We also fixup the
Linux device tree with the PCI device nodes. This allows PCI device
drivers to register of_fixups for PCI devices: The barebox internal
PCI device now gets a device node (from the patched barebox live tree)
and it can use this node to find the corresponding device node in the
Linux device tree (possibly added by barebox as well).
In my case I do not need a PCI device driver to add a node to the
Linux tree. What I want to archieve is that a MAC address of a PCI
device that is initialized in a board specific way is forwarded to
Linux using the mac-address property. For this case there are is no
further code needed, the only piece missing is the creation of the
PCI device nodes added with this series.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sascha Hauer (4):
of: fall back to parent-prefixed encoding when address translation fails
pci: fix DT node matching when reg encodes a non-zero bus number
pci: add pci_is_bridge() helper
pci: synthesize devicetree nodes for enumerated devices
drivers/of/base.c | 9 ++-
drivers/pci/Kconfig | 23 +++++++
drivers/pci/Makefile | 1 +
drivers/pci/of-dynamic.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 12 +++-
include/linux/pci.h | 14 ++++
include/of_pci.h | 6 ++
7 files changed, 235 insertions(+), 3 deletions(-)
---
base-commit: 6bde1c5bcd518f378189c2f4b41704126713f3c4
change-id: 20260521-pci-of-dynamic-15df50ff7905
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/4] of: fall back to parent-prefixed encoding when address translation fails 2026-05-21 8:36 [PATCH 0/4] PCI: populate PCI host controller device nodes Sascha Hauer @ 2026-05-21 8:36 ` Sascha Hauer 2026-05-21 8:36 ` [PATCH 2/4] pci: fix DT node matching when reg encodes a non-zero bus number Sascha Hauer ` (2 subsequent siblings) 3 siblings, 0 replies; 8+ messages in thread From: Sascha Hauer @ 2026-05-21 8:36 UTC (permalink / raw) To: BAREBOX of_get_reproducible_name() formatted the result of of_translate_address() as [0x%llx] without checking for OF_BAD_ADDR ((u64)-1). For any node whose reg can't be translated through the parent's ranges - notably PCI child nodes whose reg[0] encodes a config-space address (space=0), which host bridges don't list in ranges - this produced [0xffffffffffffffff] for every such node, collapsing distinct nodes onto the same name and making of_find_node_by_reproducible_name() return the wrong sibling. Fall through to the existing parent-prefixed {offset} branch when translation fails, so untranslatable siblings get disambiguated by their parent chain. Assisted-by: Claude Opus 4.7 Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- drivers/of/base.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 5297894f60..1244664827 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -3368,7 +3368,14 @@ char *of_get_reproducible_name(struct device_node *node) if (node->parent && of_get_property(node->parent, "ranges", NULL)) { addr = of_translate_address(node, reg); - return basprintf("[0x%llx]", addr); + if (addr != OF_BAD_ADDR) + return basprintf("[0x%llx]", addr); + /* + * Untranslatable - e.g. a PCI config-space address whose + * tag (space=0) doesn't appear in the parent's ranges. + * Fall through to the parent-prefixed encoding so distinct + * untranslatable nodes don't all collide on OF_BAD_ADDR. + */ } na = of_n_addr_cells(node); -- 2.47.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] pci: fix DT node matching when reg encodes a non-zero bus number 2026-05-21 8:36 [PATCH 0/4] PCI: populate PCI host controller device nodes Sascha Hauer 2026-05-21 8:36 ` [PATCH 1/4] of: fall back to parent-prefixed encoding when address translation fails Sascha Hauer @ 2026-05-21 8:36 ` Sascha Hauer 2026-05-21 8:36 ` [PATCH 3/4] pci: add pci_is_bridge() helper Sascha Hauer 2026-05-21 8:36 ` [PATCH 4/4] pci: synthesize devicetree nodes for enumerated devices Sascha Hauer 3 siblings, 0 replies; 8+ messages in thread From: Sascha Hauer @ 2026-05-21 8:36 UTC (permalink / raw) To: BAREBOX pci_of_match_device() compared (reg[0] >> 8) & 0xffff against devfn, but devfn is only 8 bits. The standard PCI DT binding encodes the bus number in bits [23:16] of reg[0], so any child node with a non-zero bus byte - which is the common upstream convention - yielded (bus << 8) | devfn and never matched a plain devfn. For a typical host -> root port -> endpoint DT nesting (e.g. pci@0,0 { reg = <0x300000 ...>; ethernet@0,0 { reg = <0x310000 ...>; }; }), the root port match failed and scanning never reached the endpoint, so endpoint properties like local-mac-address were never picked up. Mask with 0xff to match only the devfn byte, like Linux's of_pci_get_devfn(). Assisted-by: Claude Opus 4.7 Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 32624fe05b..8d18889109 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -558,7 +558,7 @@ pci_of_match_device(struct device *parent, unsigned int devfn) * address, other properties are defined by the * PCI/OF node topology. */ - reg = (reg >> 8) & 0xffff; + reg = (reg >> 8) & 0xff; if (reg == devfn) return np; } -- 2.47.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/4] pci: add pci_is_bridge() helper 2026-05-21 8:36 [PATCH 0/4] PCI: populate PCI host controller device nodes Sascha Hauer 2026-05-21 8:36 ` [PATCH 1/4] of: fall back to parent-prefixed encoding when address translation fails Sascha Hauer 2026-05-21 8:36 ` [PATCH 2/4] pci: fix DT node matching when reg encodes a non-zero bus number Sascha Hauer @ 2026-05-21 8:36 ` Sascha Hauer 2026-05-21 16:23 ` Bjorn Helgaas 2026-05-21 8:36 ` [PATCH 4/4] pci: synthesize devicetree nodes for enumerated devices Sascha Hauer 3 siblings, 1 reply; 8+ messages in thread From: Sascha Hauer @ 2026-05-21 8:36 UTC (permalink / raw) To: BAREBOX Mirror the Linux helper of the same name so callers don't have to open-code the header-type compare. Replace the open-coded site in pci_ea_init(). Assisted-by: Claude Opus 4.7 Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- drivers/pci/pci.c | 2 +- include/linux/pci.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8d18889109..fc00ec2249 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -334,7 +334,7 @@ static void pci_ea_init(struct pci_dev *dev) offset = ea + PCI_EA_FIRST_ENT; /* Skip DWORD 2 for type 1 functions */ - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + if (pci_is_bridge(dev)) offset += 4; /* parse each EA entry */ diff --git a/include/linux/pci.h b/include/linux/pci.h index f6511e0095..a2dbaf6ec2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -123,6 +123,20 @@ struct pci_dev { }; #define to_pci_dev(d) container_of(d, struct pci_dev, dev) +/** + * pci_is_bridge - check if the PCI device is a bridge + * @dev: PCI device + * + * Return true if the PCI device is a bridge of PCI-to-PCI type. Masks the + * multi-function flag so a multi-function bridge is still recognised. + */ +static inline bool pci_is_bridge(struct pci_dev *dev) +{ + u8 type = dev->hdr_type & PCI_HEADER_TYPE_MASK; + + return type == PCI_HEADER_TYPE_BRIDGE; +} + #define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) #define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end) #define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags) -- 2.47.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] pci: add pci_is_bridge() helper 2026-05-21 8:36 ` [PATCH 3/4] pci: add pci_is_bridge() helper Sascha Hauer @ 2026-05-21 16:23 ` Bjorn Helgaas 2026-05-21 19:46 ` Sascha Hauer 0 siblings, 1 reply; 8+ messages in thread From: Bjorn Helgaas @ 2026-05-21 16:23 UTC (permalink / raw) To: Sascha Hauer; +Cc: BAREBOX On Thu, May 21, 2026 at 10:36:57AM +0200, Sascha Hauer wrote: > Mirror the Linux helper of the same name so callers don't have to > open-code the header-type compare. > > Replace the open-coded site in pci_ea_init(). > > Assisted-by: Claude Opus 4.7 > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > drivers/pci/pci.c | 2 +- > include/linux/pci.h | 14 ++++++++++++++ > 2 files changed, 15 insertions(+), 1 deletion(-) > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 8d18889109..fc00ec2249 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -334,7 +334,7 @@ static void pci_ea_init(struct pci_dev *dev) > offset = ea + PCI_EA_FIRST_ENT; > > /* Skip DWORD 2 for type 1 functions */ > - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) > + if (pci_is_bridge(dev)) > offset += 4; > > /* parse each EA entry */ > diff --git a/include/linux/pci.h b/include/linux/pci.h > index f6511e0095..a2dbaf6ec2 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -123,6 +123,20 @@ struct pci_dev { > }; > #define to_pci_dev(d) container_of(d, struct pci_dev, dev) > > +/** > + * pci_is_bridge - check if the PCI device is a bridge > + * @dev: PCI device > + * > + * Return true if the PCI device is a bridge of PCI-to-PCI type. Masks the > + * multi-function flag so a multi-function bridge is still recognised. > + */ > +static inline bool pci_is_bridge(struct pci_dev *dev) > +{ > + u8 type = dev->hdr_type & PCI_HEADER_TYPE_MASK; > + > + return type == PCI_HEADER_TYPE_BRIDGE; > +} https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/pci.h?id=v7.0#n755 Am I missing something? > #define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) > #define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end) > #define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags) > > -- > 2.47.3 > > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] pci: add pci_is_bridge() helper 2026-05-21 16:23 ` Bjorn Helgaas @ 2026-05-21 19:46 ` Sascha Hauer 2026-05-21 20:53 ` Bjorn Helgaas 0 siblings, 1 reply; 8+ messages in thread From: Sascha Hauer @ 2026-05-21 19:46 UTC (permalink / raw) To: Bjorn Helgaas; +Cc: BAREBOX On 2026-05-21 11:23, Bjorn Helgaas wrote: > > diff --git a/include/linux/pci.h b/include/linux/pci.h > > index f6511e0095..a2dbaf6ec2 100644 > > --- a/include/linux/pci.h > > +++ b/include/linux/pci.h > > @@ -123,6 +123,20 @@ struct pci_dev { > > }; > > #define to_pci_dev(d) container_of(d, struct pci_dev, dev) > > > > +/** > > + * pci_is_bridge - check if the PCI device is a bridge > > + * @dev: PCI device > > + * > > + * Return true if the PCI device is a bridge of PCI-to-PCI type. Masks the > > + * multi-function flag so a multi-function bridge is still recognised. > > + */ > > +static inline bool pci_is_bridge(struct pci_dev *dev) > > +{ > > + u8 type = dev->hdr_type & PCI_HEADER_TYPE_MASK; > > + > > + return type == PCI_HEADER_TYPE_BRIDGE; > > +} > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/pci.h?id=v7.0#n755 > > Am I missing something? Yes. This is a barebox patch, not Linux. Is it a lei query that made you stumble upon this? Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] pci: add pci_is_bridge() helper 2026-05-21 19:46 ` Sascha Hauer @ 2026-05-21 20:53 ` Bjorn Helgaas 0 siblings, 0 replies; 8+ messages in thread From: Bjorn Helgaas @ 2026-05-21 20:53 UTC (permalink / raw) To: Sascha Hauer; +Cc: BAREBOX On Thu, May 21, 2026 at 07:46:54PM +0000, Sascha Hauer wrote: > On 2026-05-21 11:23, Bjorn Helgaas wrote: > > > diff --git a/include/linux/pci.h b/include/linux/pci.h > > > index f6511e0095..a2dbaf6ec2 100644 > > > --- a/include/linux/pci.h > > > +++ b/include/linux/pci.h > > > @@ -123,6 +123,20 @@ struct pci_dev { > > > }; > > > #define to_pci_dev(d) container_of(d, struct pci_dev, dev) > > > > > > +/** > > > + * pci_is_bridge - check if the PCI device is a bridge > > > + * @dev: PCI device > > > + * > > > + * Return true if the PCI device is a bridge of PCI-to-PCI type. Masks the > > > + * multi-function flag so a multi-function bridge is still recognised. > > > + */ > > > +static inline bool pci_is_bridge(struct pci_dev *dev) > > > +{ > > > + u8 type = dev->hdr_type & PCI_HEADER_TYPE_MASK; > > > + > > > + return type == PCI_HEADER_TYPE_BRIDGE; > > > +} > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/pci.h?id=v7.0#n755 > > > > Am I missing something? > > Yes. This is a barebox patch, not Linux. Is it a lei query that made you > stumble upon this? Oops, sorry. Indeed, I do read via lei. I notice I'm regularly getting tripped up by patches to uboot and now barebox. I guess I should update my lei query. Sorry for the noise. Bjorn ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/4] pci: synthesize devicetree nodes for enumerated devices 2026-05-21 8:36 [PATCH 0/4] PCI: populate PCI host controller device nodes Sascha Hauer ` (2 preceding siblings ...) 2026-05-21 8:36 ` [PATCH 3/4] pci: add pci_is_bridge() helper Sascha Hauer @ 2026-05-21 8:36 ` Sascha Hauer 3 siblings, 0 replies; 8+ messages in thread From: Sascha Hauer @ 2026-05-21 8:36 UTC (permalink / raw) To: BAREBOX Add an opt-in PCI_DYNAMIC_OF_NODES that creates a devicetree node for every PCI device discovered during bus scan that doesn't already have one in the static tree. Nodes are attached to the live tree under the host bridge / parent bridge, so they're visible both to barebox's own pci_of_match_device() and to the kernel devicetree handed off at boot. Inspired by Linux's CONFIG_PCI_DYNAMIC_OF_NODES, but trimmed to the bare minimum Linux actually consumes: a node with a "reg" property encoding bus/devfn so of_pci_find_child_device() can attach the node to the device it rediscovers from hardware. Everything else Linux would otherwise look at (compatible, bus-range, ranges, interrupts) is recomputed from PCI config space at probe time, so duplicating it here would just be state with no consumer and more surface for bugs. Linux's changeset wrapper is dropped: barebox's live tree is freely mutable via of_new_node() / of_set_property(). The primary motivation is letting board code stamp MAC addresses onto PCI Ethernet endpoints via of_eth_register_ethaddr() without having to hand-write the pci@D,F / dev@D,F hierarchy in the source DTS. Assisted-by: Claude Opus 4.7 Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- drivers/pci/Kconfig | 23 +++++++ drivers/pci/Makefile | 1 + drivers/pci/of-dynamic.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 8 +++ include/of_pci.h | 6 ++ 5 files changed, 211 insertions(+) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index f8e60c4ea5..a2ebf348d9 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -25,6 +25,29 @@ config PCI_DEBUG When in doubt, say N. +config PCI_DYNAMIC_OF_NODES + bool "Create devicetree nodes for runtime-enumerated PCI devices" + depends on PCI && OFDEVICE + help + Synthesize a devicetree node for every PCI device discovered during + bus scan that does not already have one in the static devicetree. + Nodes are attached to the live tree under the host-bridge / parent + bridge node, so they are visible to barebox itself and flow into the + devicetree passed to the kernel at boot. + + This lets consumers (e.g. of_eth_register_ethaddr() for stamping a + MAC address) reference PCI endpoints by node path without + hand-writing the pci@D,F / dev@D,F hierarchy in the source DTS. + + Only the bare minimum is generated: a node with a "reg" property + encoding the device/function so Linux's of_pci_find_child_device() + can attach the node to the device it rediscovers from hardware. + Linux recomputes everything else (compatible from VID/DID, bus-range + and ranges from config space, etc.) so adding it here would just be + duplicated state with no consumer. + + When in doubt, say N. + config PCIE_DW bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 69649fbcd2..803ff09f89 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -4,6 +4,7 @@ # obj-y += pci.o bus.o pci_iomap.o host-bridge.o obj-$(CONFIG_OFDEVICE) += of.o +obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of-dynamic.o ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG diff --git a/drivers/pci/of-dynamic.c b/drivers/pci/of-dynamic.c new file mode 100644 index 0000000000..2f6d7fb84e --- /dev/null +++ b/drivers/pci/of-dynamic.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synthesize the minimal devicetree nodes Linux needs to attach properties + * (most notably mac-address) to runtime-enumerated PCI devices. + * + * Loosely modelled on Linux's CONFIG_PCI_DYNAMIC_OF_NODES, but trimmed to + * just node creation + a "reg" property. Linux discovers PCI topology from + * hardware, so other properties it would otherwise read (compatible, + * bus-range, ranges, #address-cells/#size-cells, interrupts, ...) are + * either redundant or recomputed from config space at probe time. Keeping + * the generator small keeps the bug surface small. + * + * The only thing barebox must put in DT for Linux to find the node is: + * - a child of the parent bus' DT node, with + * - reg cell[0] = (bus << 16) | (devfn << 8) so of_pci_get_devfn() works. + * + * Linux uses of_changeset because its live kernel devicetree is treated + * as immutable; barebox is free to mutate the live tree directly, so the + * changeset layer is dropped. + */ + +#define pr_fmt(fmt) "PCI: OF: " fmt + +#include <common.h> +#include <init.h> +#include <of.h> +#include <of_pci.h> +#include <malloc.h> +#include <linux/pci.h> + +static int of_pci_fill_node(struct device_node *np, struct pci_dev *pdev) +{ + u32 reg[5] = { 0 }; + int ret; + + /* Config-space tag (space = 0); only bus/devfn matter for matching. */ + reg[0] = (pdev->bus->number << 16) | (pdev->devfn << 8); + ret = of_property_write_u32_array(np, "reg", reg, ARRAY_SIZE(reg)); + if (ret) + return ret; + + if (pci_is_bridge(pdev)) { + ret = of_property_write_u32(np, "#address-cells", 3); + if (ret) + return ret; + ret = of_property_write_u32(np, "#size-cells", 2); + if (ret) + return ret; + } + + return 0; +} + +void of_pci_make_dev_node(struct pci_dev *pdev) +{ + struct device_node *parent_np, *np; + struct device *parent_dev; + char *name; + + if (pdev->dev.of_node) + return; + + parent_dev = pdev->bus->self ? &pdev->bus->self->dev + : pdev->bus->host->parent; + if (!parent_dev || !parent_dev->of_node) + return; + parent_np = parent_dev->of_node; + + name = xasprintf("%s@%x,%x", + pci_is_bridge(pdev) ? "pci" : "dev", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + np = of_new_node(parent_np, name); + free(name); + if (!np) + return; + + if (of_pci_fill_node(np, pdev)) { + of_delete_node(np); + return; + } + + pdev->dev.of_node = np; + + dev_dbg(&pdev->dev, "created OF node %pOF\n", np); +} + +static struct device_node * +of_pci_fixup_dev_node(struct device_node *parent_np, struct pci_dev *pdev) +{ + struct device_node *np; + char *name; + u32 reg; + + /* + * Match by devfn before creating a new node: any existing child + * whose reg[0] devfn byte matches refers to the same hardware, + * regardless of node name. + */ + for_each_child_of_node(parent_np, np) { + if (of_property_read_u32_array(np, "reg", ®, 1)) + continue; + if (((reg >> 8) & 0xff) == pdev->devfn) + return np; + } + + name = xasprintf("%s@%x,%x", + pci_is_bridge(pdev) ? "pci" : "dev", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + np = of_new_node(parent_np, name); + free(name); + if (!np) + return NULL; + + if (of_pci_fill_node(np, pdev)) { + of_delete_node(np); + return NULL; + } + + return np; +} + +static void of_pci_fixup_bus(struct device_node *parent_np, struct pci_bus *bus) +{ + struct pci_dev *pdev; + struct device_node *np; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + np = of_pci_fixup_dev_node(parent_np, pdev); + if (np && pdev->subordinate) + of_pci_fixup_bus(np, pdev->subordinate); + } +} + +static int of_pci_fixup(struct device_node *root, void *ctx) +{ + struct pci_bus *bus; + + list_for_each_entry(bus, &pci_root_buses, node) { + struct device_node *bb_np, *host_np; + char *name; + + if (!bus->host || !bus->host->parent) + continue; + bb_np = bus->host->parent->of_node; + if (!bb_np) + continue; + + name = of_get_reproducible_name(bb_np); + host_np = of_find_node_by_reproducible_name(root, name); + free(name); + if (!host_np) { + pr_debug("no kernel-DT mirror of host bridge %pOF\n", bb_np); + continue; + } + + of_pci_fixup_bus(host_np, bus); + } + + return 0; +} + +static int of_pci_register_fixup(void) +{ + return of_register_fixup(of_pci_fixup, NULL); +} + +/* + * The PCI device OF fixup must run before other fixups want to modify the nodes + * we are creating here. As OF fixups are running in the order they are registered, + * register this one early. This might be the first sign that we need a dependency + * tracking or -EPROBE_DEFERRED mechanism for OF fixups. Keep an eye on it. + */ +core_initcall(of_pci_register_fixup); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fc00ec2249..ca19a03c20 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5,6 +5,7 @@ #include <linux/sizes.h> #include <linux/pci.h> #include <linux/bitfield.h> +#include <of_pci.h> static unsigned int pci_scan_bus(struct pci_bus *bus); @@ -672,6 +673,7 @@ static unsigned int pci_scan_bus(struct pci_bus *bus) pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); + of_pci_make_dev_node(dev); break; case PCI_HEADER_TYPE_BRIDGE: child_bus = pci_alloc_bus(); @@ -690,6 +692,12 @@ static unsigned int pci_scan_bus(struct pci_bus *bus) /* scan pci hierarchy behind bridge */ prescan_setup_bridge(dev); + /* + * Materialize the bridge's OF node before recursing so + * children below it can find their parent during their + * own of_pci_make_dev_node() call. + */ + of_pci_make_dev_node(dev); pci_scan_bus(child_bus); postscan_setup_bridge(dev); diff --git a/include/of_pci.h b/include/of_pci.h index c787150936..c44cc625f5 100644 --- a/include/of_pci.h +++ b/include/of_pci.h @@ -15,4 +15,10 @@ static inline int of_pci_get_devfn(struct device_node *np) #endif +#ifdef CONFIG_PCI_DYNAMIC_OF_NODES +void of_pci_make_dev_node(struct pci_dev *pdev); +#else +static inline void of_pci_make_dev_node(struct pci_dev *pdev) { } +#endif + #endif -- 2.47.3 ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-05-21 20:55 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-05-21 8:36 [PATCH 0/4] PCI: populate PCI host controller device nodes Sascha Hauer 2026-05-21 8:36 ` [PATCH 1/4] of: fall back to parent-prefixed encoding when address translation fails Sascha Hauer 2026-05-21 8:36 ` [PATCH 2/4] pci: fix DT node matching when reg encodes a non-zero bus number Sascha Hauer 2026-05-21 8:36 ` [PATCH 3/4] pci: add pci_is_bridge() helper Sascha Hauer 2026-05-21 16:23 ` Bjorn Helgaas 2026-05-21 19:46 ` Sascha Hauer 2026-05-21 20:53 ` Bjorn Helgaas 2026-05-21 8:36 ` [PATCH 4/4] pci: synthesize devicetree nodes for enumerated devices Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox