From 3edb3a038d423480efeb204dbc6ddc9a292f8ecb Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 16 Jun 2026 21:45:19 +0530 Subject: [PATCH] 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: 2fd60a2edb83 ("PCI: qcom: Parse PERST# from all PCIe bridge nodes") Signed-off-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260616-pci-qcom-perst-fix-v1-1-27600d6ae357@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom.c | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 89ae006fb6c3..b193c989b2b8 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -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)) {