PCI: qcom: Skip PERST# GPIOs provided by downstream PCIe devices

Currently, the pcie-qcom driver recursively parses the PERST# GPIO from all
child nodes defined in DT and acquires them. But this creates issues with
PERST# GPIO provided by one of the child devices like the PCIe switch port.
In this case, the RC driver cannot acquire the PERST# GPIO since it will be
provided by the child PCIe device which was not yet enumerated during RC
driver probe.

Fix this by checking if the GPIO provider is a child of the RC's DT node
(i.e., sits behind this PCIe controller). If so, skip it, as PERST#
should be controlled by the respective PCIe client driver implementation.
GPIOs provided by external GPIO controllers (e.g., TLMM in Qcom SoCs)
continue to be handled normally.

Fixes: 2fd60a2edb ("PCI: qcom: Parse PERST# from all PCIe bridge nodes")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20260616-pci-qcom-perst-fix-v1-1-27600d6ae357@oss.qualcomm.com
This commit is contained in:
Manivannan Sadhasivam 2026-06-16 21:45:19 +05:30 committed by Manivannan Sadhasivam
parent 5331711738
commit 3edb3a038d

View File

@ -1820,6 +1820,23 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = {
}
};
/* Check if @node is a child of @dev in DT */
static bool qcom_pcie_is_child_node(struct device *dev,
struct device_node *node)
{
struct device_node *parent;
for (parent = of_get_parent(node); parent;
parent = of_get_next_parent(parent)) {
if (parent == dev->of_node) {
of_node_put(parent);
return true;
}
}
return false;
}
/* Parse PERST# from all nodes in depth first manner starting from @np */
static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
struct qcom_pcie_port *port,
@ -1827,6 +1844,7 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
{
struct device *dev = pcie->pci->dev;
struct qcom_pcie_perst *perst;
struct device_node *gpio_np;
struct gpio_desc *reset;
int ret;
@ -1840,6 +1858,25 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
if (!of_find_property(np, "reset-gpios", NULL))
goto parse_child_node;
/*
* Skip GPIOs provided by a PCIe device which is a child of the Root
* Complex (e.g., a PCIe switch with GPIO controller capability). Such
* controllers won't be available at RC probe time and their PERST#
* should be controlled by the respective PCI client driver
* implementation.
*/
gpio_np = of_parse_phandle(np, "reset-gpios", 0);
if (!gpio_np) {
dev_err(dev, "Failed to parse GPIO provider\n");
return -EINVAL;
}
if (qcom_pcie_is_child_node(dev, gpio_np)) {
of_node_put(gpio_np);
goto parse_child_node;
}
of_node_put(gpio_np);
reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(np), "reset",
GPIOD_OUT_HIGH, "PERST#");
if (IS_ERR(reset)) {