RE: [PATCH V8 02/13] PCI: host-generic: Add common helpers for parsing Root Port properties
From: Sherry Sun
Date: Tue Mar 17 2026 - 04:04:01 EST
> On Fri, Mar 13, 2026 at 10:08:12AM +0800, Sherry Sun wrote:
> > Introduce generic helper functions to parse Root Port device tree
> > nodes and extract common properties like reset GPIOs. This allows
> > multiple PCI host controller drivers to share the same parsing logic.
> >
> > Define struct pci_host_port to hold common Root Port properties
> > (currently only reset GPIO descriptor) and add
> > pci_host_common_parse_ports() to parse Root Port nodes from device
> tree.
> >
> > Also add the 'ports' list to struct pci_host_bridge for better
> > maintain parsed Root Port information.
> >
> > Signed-off-by: Sherry Sun <sherry.sun@xxxxxxx>
> > ---
> > drivers/pci/controller/pci-host-common.c | 78
> > ++++++++++++++++++++++++ drivers/pci/controller/pci-host-common.h |
> 15 +++++
> > drivers/pci/probe.c | 1 +
> > include/linux/pci.h | 1 +
> > 4 files changed, 95 insertions(+)
> >
> > diff --git a/drivers/pci/controller/pci-host-common.c
> > b/drivers/pci/controller/pci-host-common.c
> > index d6258c1cffe5..2f012cf80463 100644
> > --- a/drivers/pci/controller/pci-host-common.c
> > +++ b/drivers/pci/controller/pci-host-common.c
> > @@ -9,6 +9,7 @@
> >
> > #include <linux/kernel.h>
> > #include <linux/module.h>
> > +#include <linux/gpio/consumer.h>
> > #include <linux/of.h>
> > #include <linux/of_address.h>
> > #include <linux/of_pci.h>
> > @@ -17,6 +18,83 @@
> >
> > #include "pci-host-common.h"
> >
> > +/**
> > + * pci_host_common_delete_ports - Cleanup function for port list
> > + * @data: Pointer to the port list head */ static void
> > +pci_host_common_delete_ports(void *data) {
> > + struct list_head *ports = data;
> > + struct pci_host_port *port, *tmp;
> > +
> > + list_for_each_entry_safe(port, tmp, ports, list)
> > + list_del(&port->list);
> > +}
> > +
> > +/**
> > + * pci_host_common_parse_port - Parse a single Root Port node
> > + * @dev: Device pointer
> > + * @bridge: PCI host bridge
> > + * @node: Device tree node of the Root Port
> > + *
> > + * Returns: 0 on success, negative error code on failure */ static
> > +int pci_host_common_parse_port(struct device *dev,
> > + struct pci_host_bridge *bridge,
> > + struct device_node *node)
> > +{
> > + struct pci_host_port *port;
> > + struct gpio_desc *reset;
> > +
> > + reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
> > + "reset", GPIOD_ASIS, "PERST#");
> > + if (IS_ERR(reset))
> > + return PTR_ERR(reset);
> > +
> > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > + if (!port)
> > + return -ENOMEM;
> > +
> > + port->reset = reset;
> > + INIT_LIST_HEAD(&port->list);
> > + list_add_tail(&port->list, &bridge->ports);
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * pci_host_common_parse_ports - Parse Root Port nodes from device
> > +tree
> > + * @dev: Device pointer
> > + * @bridge: PCI host bridge
> > + *
> > + * This function iterates through child nodes of the host bridge and
> > +parses
> > + * Root Port properties (currently only reset GPIO).
> > + *
> > + * Returns: 0 on success, -ENOENT if no ports found, other negative
> > +error codes
> > + * on failure
> > + */
> > +int pci_host_common_parse_ports(struct device *dev, struct
> > +pci_host_bridge *bridge) {
> > + int ret = -ENOENT;
> > + int err;
> > +
> > + for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> > + if (!of_node_is_type(of_port, "pci"))
> > + continue;
> > + ret = pci_host_common_parse_port(dev, bridge, of_port);
> > + if (ret)
> > + return ret;
> > + }
> > +
>
> I think you should just do:
>
> if (ret)
> return ret;
>
> and get rid of 'err'.
Hi Mani, do you mean the following method?
int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *bridge)
{
int ret = -ENOENT;
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
if (!of_node_is_type(of_port, "pci"))
continue;
ret = pci_host_common_parse_port(dev, bridge, of_port);
if (ret)
return ret;
}
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, pci_host_common_delete_ports,
&bridge->ports);
if (ret)
return ret;
return 0;
}
But the error path looks a bit redundant to me, how about check if (ret == 0) before
devm_add_action_or_reset() directly?
int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *bridge)
{
int ret = -ENOENT;
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
if (!of_node_is_type(of_port, "pci"))
continue;
ret = pci_host_common_parse_port(dev, bridge, of_port);
if (ret)
return ret;
}
if (ret == 0)
ret = devm_add_action_or_reset(dev, pci_host_common_delete_ports,
&bridge->ports);
return ret;
}
Best Regards
Sherry
>
> > + err = devm_add_action_or_reset(dev,
> pci_host_common_delete_ports,
> > + &bridge->ports);
> > + if (err)
> > + return err;
> > +
> > + return ret;
>
> return 0;
>
> - Mani
>
> --
> மணிவண்ணன் சதாசிவம்