PCI: host-generic: Move legacy DT binding fallback decision to caller of pci_host_common_parse_ports()

pci_host_common_parse_ports() returns -ENODEV if the bridge nodes (RP) are
not present or PERST# is only found in the Root Complex node. Then the
callers (currently just pci-imx6) assume that they need to fall back to
parsing the legacy DT binding.

But this behavior won't scale across Root Complex designs because PERST#
is not the only optional property that the callers would need to consider
for falling back to legacy binding. There could be many properties and the
API cannot incorporate all of them.

So to keep the API implementation simple, just return 0 when bridge nodes
were not found. Then it is up to the caller to use its own logic to decide
whether to fall back to legacy binding or not.

Since there is only one caller now, update the caller to skip -ENODEV check
and check for the PERST# GPIO in any of the bridge nodes and fall back to
legacy binding if not found.

Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
[mani: squashed imx6 patch to avoid bisectability issue, commit message]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Richard Zhu <hongxing.zhu@nxp.com>
Link: https://patch.msgid.link/20260525065443.2338629-2-sherry.sun@oss.nxp.com
This commit is contained in:
Sherry Sun 2026-05-25 14:54:42 +08:00 committed by Bjorn Helgaas
parent dc59e4fea9
commit 3567bcf0e9
2 changed files with 22 additions and 32 deletions

View File

@ -1318,6 +1318,18 @@ static void imx_pcie_assert_perst(struct imx_pcie *imx_pcie, bool assert)
}
}
static bool imx_pcie_perst_found(struct pci_host_bridge *bridge)
{
struct pci_host_port *port;
list_for_each_entry(port, &bridge->ports, list) {
if (!list_empty(&port->perst))
return true;
}
return false;
}
static int imx_pcie_host_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@ -1330,15 +1342,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
/* Parse Root Port nodes if present */
ret = pci_host_common_parse_ports(dev, bridge);
if (ret) {
if (ret != -ENODEV) {
dev_err(dev, "Failed to parse Root Port nodes: %d\n", ret);
return ret;
}
dev_err(dev, "Failed to parse Root Port nodes: %d\n", ret);
return ret;
}
/*
* Fall back to legacy binding for DT backwards
* compatibility
*/
/* Fall back to legacy binding for DT backwards compatibility */
if (!imx_pcie_perst_found(bridge)) {
ret = imx_pcie_parse_legacy_binding(imx_pcie);
if (ret)
return ret;

View File

@ -108,8 +108,7 @@ static int pci_host_common_parse_perst(struct device *dev,
* dependencies and the driver may fail to operate if required resources
* are missing.
*
* Return: 0 on success, -ENODEV if PERST# found in RC node (legacy binding
* should be used), Other negative error codes on failure.
* Return: 0 on success, negative error codes on failure.
*/
static int pci_host_common_parse_port(struct device *dev,
struct pci_host_bridge *bridge,
@ -128,22 +127,6 @@ static int pci_host_common_parse_port(struct device *dev,
if (ret)
return ret;
/*
* 1. PERST# found in RP or its child nodes - list is not empty,
* continue
*
* 2. PERST# not found in RP/children, but found in RC node -
* return -ENODEV to fallback legacy binding
*
* 3. PERST# not found anywhere - list is empty, continue (optional
* PERST#)
*/
if (list_empty(&port->perst)) {
if (of_property_present(dev->of_node, "reset-gpios") ||
of_property_present(dev->of_node, "reset-gpio"))
return -ENODEV;
}
INIT_LIST_HEAD(&port->list);
list_add_tail(&port->list, &bridge->ports);
@ -158,13 +141,11 @@ static int pci_host_common_parse_port(struct device *dev,
* Iterate through child nodes of the host bridge and parse Root Port
* properties (currently only reset GPIOs).
*
* Return: 0 on success, -ENODEV if no ports found or PERST# found in RC
* node (legacy binding should be used), Other negative error codes on
* failure.
* Return: 0 on success or ports not found, negative error codes on failure.
*/
int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *bridge)
{
int ret = -ENODEV;
int ret = 0;
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
if (!of_node_is_type(of_port, "pci"))
@ -174,8 +155,8 @@ int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *brid
goto err_cleanup;
}
if (ret)
return ret;
if (list_empty(&bridge->ports))
return 0;
return devm_add_action_or_reset(dev, pci_host_common_delete_ports,
&bridge->ports);