* [PATCH 1/4] PCI: of: drop the reg_num argument to of_pci_set_address()
2026-08-07 19:40 [PATCH 0/4] PCI: of: warn on bogus device_type property Alex Elder
@ 2026-08-07 19:40 ` Alex Elder
2026-08-07 19:40 ` [PATCH 2/4] PCI: of: don't zero flags in of_pci_get_addr_flags() Alex Elder
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Alex Elder @ 2026-08-07 19:40 UTC (permalink / raw)
To: bhelgaas, robh
Cc: daniel, mohd.anwar, lorenzo.bianconi, linux-pci, devicetree,
linux-kernel, Herve Codina
The reg_num argument passed to of_pci_set_address() is always zero,
so get rid of it.
Reviewed-by: Herve Codina <herve.codina@bootlin.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
drivers/pci/of_property.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
index 75a358f73e694..505226b876c56 100644
--- a/drivers/pci/of_property.c
+++ b/drivers/pci/of_property.c
@@ -52,7 +52,7 @@ enum of_pci_prop_compatible {
};
static void of_pci_set_address(struct pci_dev *pdev, u32 *prop, u64 addr,
- u32 reg_num, u32 flags, bool reloc)
+ u32 flags, bool reloc)
{
if (pdev) {
prop[0] = FIELD_PREP(OF_PCI_ADDR_FIELD_BUS, pdev->bus->number) |
@@ -61,7 +61,7 @@ static void of_pci_set_address(struct pci_dev *pdev, u32 *prop, u64 addr,
} else
prop[0] = 0;
- prop[0] |= flags | reg_num;
+ prop[0] |= flags;
if (!reloc) {
prop[0] |= OF_PCI_ADDR_FIELD_NONRELOC;
prop[1] = upper_32_bits(addr);
@@ -131,7 +131,7 @@ static int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset *ocs,
continue;
val64 = pci_bus_address(pdev, &res[j] - pdev->resource);
- of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, flags,
+ of_pci_set_address(pdev, rp[i].parent_addr, val64, flags,
false);
if (pci_is_bridge(pdev)) {
memcpy(rp[i].child_addr, rp[i].parent_addr,
@@ -164,7 +164,7 @@ static int of_pci_prop_reg(struct pci_dev *pdev, struct of_changeset *ocs,
struct of_pci_addr_pair reg = { 0 };
/* configuration space */
- of_pci_set_address(pdev, reg.phys_addr, 0, 0, 0, true);
+ of_pci_set_address(pdev, reg.phys_addr, 0, 0, true);
return of_changeset_add_prop_u32_array(ocs, np, "reg", (u32 *)®,
sizeof(reg) / sizeof(u32));
@@ -458,7 +458,7 @@ static int of_pci_host_bridge_prop_ranges(struct pci_host_bridge *bridge,
/* PCI bus address */
val64 = res->start;
of_pci_set_address(NULL, &ranges[ranges_sz],
- val64 - window->offset, 0, flags, false);
+ val64 - window->offset, flags, false);
ranges_sz += OF_PCI_ADDRESS_CELLS;
/* Host bus address */
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/4] PCI: of: don't zero flags in of_pci_get_addr_flags()
2026-08-07 19:40 [PATCH 0/4] PCI: of: warn on bogus device_type property Alex Elder
2026-08-07 19:40 ` [PATCH 1/4] PCI: of: drop the reg_num argument to of_pci_set_address() Alex Elder
@ 2026-08-07 19:40 ` Alex Elder
2026-08-07 19:40 ` [PATCH 3/4] PCI: of: make a flags argument optional Alex Elder
2026-08-07 19:40 ` [PATCH 4/4] PCI: of: introduce of_pci_verify_node() Alex Elder
3 siblings, 0 replies; 5+ messages in thread
From: Alex Elder @ 2026-08-07 19:40 UTC (permalink / raw)
To: bhelgaas, robh
Cc: daniel, mohd.anwar, lorenzo.bianconi, linux-pci, devicetree,
linux-kernel, Herve Codina
The flags variable whose address is passed to of_pci_get_addr_flags()
is zeroed before assigning a value to it. Skip the zeroing and just
assign it instead.
Reviewed-by: Herve Codina <herve.codina@bootlin.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
drivers/pci/of_property.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
index 505226b876c56..22fea1905a080 100644
--- a/drivers/pci/of_property.c
+++ b/drivers/pci/of_property.c
@@ -82,12 +82,10 @@ static int of_pci_get_addr_flags(const struct resource *res, u32 *flags)
else
return -EINVAL;
- *flags = 0;
+ *flags = FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss);
if (res->flags & IORESOURCE_PREFETCH)
*flags |= OF_PCI_ADDR_FIELD_PREFETCH;
- *flags |= FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss);
-
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] PCI: of: make a flags argument optional
2026-08-07 19:40 [PATCH 0/4] PCI: of: warn on bogus device_type property Alex Elder
2026-08-07 19:40 ` [PATCH 1/4] PCI: of: drop the reg_num argument to of_pci_set_address() Alex Elder
2026-08-07 19:40 ` [PATCH 2/4] PCI: of: don't zero flags in of_pci_get_addr_flags() Alex Elder
@ 2026-08-07 19:40 ` Alex Elder
2026-08-07 19:40 ` [PATCH 4/4] PCI: of: introduce of_pci_verify_node() Alex Elder
3 siblings, 0 replies; 5+ messages in thread
From: Alex Elder @ 2026-08-07 19:40 UTC (permalink / raw)
To: bhelgaas, robh
Cc: daniel, mohd.anwar, lorenzo.bianconi, linux-pci, devicetree,
linux-kernel
The address of a u32 object is passed to of_pci_get_addr_flags() so
it can be filled with the computed flags value.
Allow a null pointer to be passed, so that the validity of the
resource's flags can be checked without filling in the flags value.
Signed-off-by: Alex Elder <elder@riscstar.com>
---
drivers/pci/of_property.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
index 22fea1905a080..5e1820b8bb79b 100644
--- a/drivers/pci/of_property.c
+++ b/drivers/pci/of_property.c
@@ -82,9 +82,11 @@ static int of_pci_get_addr_flags(const struct resource *res, u32 *flags)
else
return -EINVAL;
- *flags = FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss);
- if (res->flags & IORESOURCE_PREFETCH)
- *flags |= OF_PCI_ADDR_FIELD_PREFETCH;
+ if (flags) {
+ *flags = FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss);
+ if (res->flags & IORESOURCE_PREFETCH)
+ *flags |= OF_PCI_ADDR_FIELD_PREFETCH;
+ }
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 4/4] PCI: of: introduce of_pci_verify_node()
2026-08-07 19:40 [PATCH 0/4] PCI: of: warn on bogus device_type property Alex Elder
` (2 preceding siblings ...)
2026-08-07 19:40 ` [PATCH 3/4] PCI: of: make a flags argument optional Alex Elder
@ 2026-08-07 19:40 ` Alex Elder
3 siblings, 0 replies; 5+ messages in thread
From: Alex Elder @ 2026-08-07 19:40 UTC (permalink / raw)
To: bhelgaas, robh
Cc: daniel, mohd.anwar, lorenzo.bianconi, linux-pci, devicetree,
linux-kernel
Commit 407d1a51921e9 ("PCI: Create device tree node for bridge") linked
the PCI enumeration process together with devicetree, creating a devicetree
node for discovered PCI bridges. Its successor commit ae9813db1dc5a ("PCI:
Add quirks to generate device tree node for Xilinx Alveo U50") shows how
to use a PCI final fixup quirk to also create a devicetree node for a
non-bridge PCI device. These changes allowed devicetree overlays to
describe components downstream of a PCI device, by providing a place to
attach the overlay.
Note that the dynamic devicetree node is only created if the device didn't
already have an assigned node.
Later, commit aa7b4bbcb3a1d ("arm64: dts: qcom: qcs6490-rb3gen2: Add
TC9563 PCIe switch node") *pre-defined* devicetree nodes to represent the
PCI device nodes that would (also) be discovered via the PCI enumeration
process. The devicetree node in this case is created with the content
from the DTS file. So when a (host) bridge is done being initialized
during PCI enumeration, no node is dynamically created (the commits
mentioned above do not apply).
Ideally, any pre-defined PCI devicetree node would contain exactly the
same information as whatever the dynamic creation process would produce
(though it could include more).
However that is not the case for the pre-defined Qualcomm RB3gen2 nodes.
And in particular, the endpoint (function) nodes include this property:
device_type = "pci";
This is simply wrong; that property is meant only for bridge nodes.
Rob Herring requested that a runtime check to be added to spot this
specific error, only for non-bridge PCI devices.
(There are many things that could be verified for statically-defined
devicetree nodes, but this is all we'll do for now.)
Signed-off-by: Alex Elder <elder@riscstar.com>
---
drivers/pci/bus.c | 1 +
drivers/pci/of.c | 27 +++++++++++++++++++++++++++
drivers/pci/pci.h | 2 ++
3 files changed, 30 insertions(+)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 655ed53436d3e..679afbc6d3109 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -351,6 +351,7 @@ void pci_bus_add_device(struct pci_dev *dev)
* are not assigned yet for some devices.
*/
pcibios_bus_add_device(dev);
+ of_pci_verify_node(dev);
pci_fixup_device(pci_fixup_final, dev);
if (pci_is_bridge(dev))
of_pci_make_dev_node(dev);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 8b18c4ba845cf..b51bb14857e9e 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -663,6 +663,33 @@ void of_pci_remove_node(struct pci_dev *pdev)
of_node_put(np);
}
+void of_pci_verify_node(struct pci_dev *pdev)
+{
+ struct device_node *np = pci_device_to_OF_node(pdev);
+
+ /* If there's no pre-existing node, there's nothing to check */
+ if (!np)
+ return;
+
+ /*
+ * Check a pre-existing devicetree node for errors. The PCI
+ * enumeration process gathered a lot of information about
+ * the device, and ideally it matches what the devicetree
+ * node says.
+ */
+ if (pci_is_bridge(pdev))
+ return;
+
+ /*
+ * Currently we just verify that non-bridges don't contain a
+ * device_type = "pci" property.
+ */
+ if (!of_node_is_type(np, "pci"))
+ return;
+
+ dev_err(&pdev->dev, "\"pci\" device_type NOT VALID for PCI endpoint\n");
+}
+
void of_pci_make_dev_node(struct pci_dev *pdev)
{
struct device_node *ppnode, *np = NULL;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4469e1a77f3c1..6c19895c14914 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1265,6 +1265,7 @@ static inline int of_pci_get_equalization_presets(struct device *dev,
struct of_changeset;
#ifdef CONFIG_PCI_DYNAMIC_OF_NODES
+void of_pci_verify_node(struct pci_dev *pdev);
void of_pci_make_dev_node(struct pci_dev *pdev);
void of_pci_remove_node(struct pci_dev *pdev);
int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs,
@@ -1275,6 +1276,7 @@ int of_pci_add_host_bridge_properties(struct pci_host_bridge *bridge,
struct of_changeset *ocs,
struct device_node *np);
#else
+static inline void of_pci_verify_node(struct pci_dev *pdev) { }
static inline void of_pci_make_dev_node(struct pci_dev *pdev) { }
static inline void of_pci_remove_node(struct pci_dev *pdev) { }
static inline void of_pci_make_host_bridge_node(struct pci_host_bridge *bridge) { }
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread