drivers/pci/controller/dwc/pcie-qcom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
qcom_pcie_parse_perst() walks the PCIe hierarchy described in the device
tree below its root port and collects the PERST# GPIOs from each bridge
node so all PERST# lines can be driven in unison during controller
bring-up, reset and power sequencing.
However, the recursive device tree walk currently visits every available
child node without checking that it is a PCI bridge. This allows the walk
to leave the PCI hierarchy and collect reset lines from children of PCI
enfpoitn nodes, where those reset lines belong to other drivers.
This is reproducible on the Qualcomm RB3Gen2, where a Renesas uPD720201
USB host controller sits behind a PCIe switch downstream port. A Genesys
GL3590 USB hub connected to that controller is described as a child of
the PCI endpoint:
pcie@2,0 {
device_type = "pci";
usb-controller@0,0 {
compatible = "pci1912,0014";
hub@1 {
compatible = "usb5e3,610";
reset-gpios = <&tlmm 162 GPIO_ACTIVE_HIGH>;
};
};
};
The USB controller is a PCI endpoint, and not a bridge, but the PERST#
walk descends through it and incorrectly claims the hub's reset GPIO:
$ gpioinfo
line 162: unnamed output consumer=PERST#
As a result, the onboard-usb-dev driver cannot acquire its reset GPIO
during probe:
onboard-usb-dev 1c08000.pcie:...:usb-controller@0,0:hub@1: \
error -EBUSY: failed to get reset GPIO
onboard-usb-dev 1c08000.pcie:...:usb-controller@0,0:hub@1: \
probe with driver onboard-usb-dev failed with error -16
The GPIO is also added to the root port's PERST# list and is asserted
and deasserted as part of PCIe reset sequencing. On the RB3Gen2 this
causes the USB hub to repeatedly re-enumerate:
[ 116.479598] hub 2-1:1.0: USB hub found
[ 116.488601] hub 2-1:1.0: USB hub found
[ 116.496971] hub 2-1:1.0: USB hub found
...
This disrupts the hub and devices connected to it.
Restrict the recursive walk to children with device_type "pci", so
PERST# GPIOs are collected only from PCI bridge nodes and the walk
does not descend through endpoints.
qocm_pcie_parse_ports() has made the same distinction since
commit 45df22935bdc ("PCI: qcom: Restrict port parsing only to PCIe
bridge child nodes"), but the PERST# walk added later did not carry over
that check.
This bug is distinct from commit 3edb3a038d42 ("PCI: qcom: Skip PERST#
GPIOs provided by downstream PCIe devices"), which filters PERST# GPIOs
based on their provider. Here the GPIO is provided by the SoC TLMM; the
bug is that reset-gpios is consumed from a non-bridge node at all.
Fixes: 2fd60a2edb83 ("PCI: qcom: Parse PERST# from all PCIe bridge nodes")
Cc: stable@vger.kernel.org
Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
---
USB/Ethernet issue on RB3Gen2.
---
drivers/pci/controller/dwc/pcie-qcom.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index b58a607b713f..89a476c37098 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1953,7 +1953,7 @@ static bool qcom_pcie_is_child_node(struct device *dev,
return false;
}
-/* Parse PERST# from all nodes in depth first manner starting from @np */
+/* Collect PERST# GPIOs from PCI bridge nodes depth-first, starting at @np */
static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
struct qcom_pcie_port *port,
struct device_node *np)
@@ -2019,6 +2019,9 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
parse_child_node:
for_each_available_child_of_node_scoped(np, child) {
+ if (!of_node_is_type(child, "pci"))
+ continue;
+
ret = qcom_pcie_parse_perst(pcie, port, child);
if (ret)
return ret;
---
base-commit: 570f7e331f5febb30f1384817463c7e42b65ca7d
change-id: 20260829-wip-obbardc-drivers-pcie-qcom-rb3gen2-usb-fix-ef551ccc0a8d
Best regards,
--
Christopher Obbard <chris.obbard@oss.qualcomm.com>
On Sat, 29 Aug 2026 11:36:00 +0100, Christopher Obbard wrote:
> qcom_pcie_parse_perst() walks the PCIe hierarchy described in the device
> tree below its root port and collects the PERST# GPIOs from each bridge
> node so all PERST# lines can be driven in unison during controller
> bring-up, reset and power sequencing.
>
> However, the recursive device tree walk currently visits every available
> child node without checking that it is a PCI bridge. This allows the walk
> to leave the PCI hierarchy and collect reset lines from children of PCI
> enfpoitn nodes, where those reset lines belong to other drivers.
>
> [...]
Applied, thanks!
[1/1] PCI: qcom: Only check bridge nodes for PERST# GPIOs
commit: 1b3b0bc2b3672e928e06997444528f8797579eb2
Best regards,
--
மணிவண்ணன் சதாசிவம்
On 8/29/2026 4:06 PM, Christopher Obbard wrote:
> qcom_pcie_parse_perst() walks the PCIe hierarchy described in the device
> tree below its root port and collects the PERST# GPIOs from each bridge
> node so all PERST# lines can be driven in unison during controller
> bring-up, reset and power sequencing.
>
> However, the recursive device tree walk currently visits every available
> child node without checking that it is a PCI bridge. This allows the walk
> to leave the PCI hierarchy and collect reset lines from children of PCI
> enfpoitn nodes, where those reset lines belong to other drivers.
>
> This is reproducible on the Qualcomm RB3Gen2, where a Renesas uPD720201
> USB host controller sits behind a PCIe switch downstream port. A Genesys
> GL3590 USB hub connected to that controller is described as a child of
> the PCI endpoint:
>
> pcie@2,0 {
> device_type = "pci";
>
> usb-controller@0,0 {
> compatible = "pci1912,0014";
>
> hub@1 {
> compatible = "usb5e3,610";
> reset-gpios = <&tlmm 162 GPIO_ACTIVE_HIGH>;
> };
> };
> };
>
> The USB controller is a PCI endpoint, and not a bridge, but the PERST#
> walk descends through it and incorrectly claims the hub's reset GPIO:
>
> $ gpioinfo
> line 162: unnamed output consumer=PERST#
>
> As a result, the onboard-usb-dev driver cannot acquire its reset GPIO
> during probe:
>
> onboard-usb-dev 1c08000.pcie:...:usb-controller@0,0:hub@1: \
> error -EBUSY: failed to get reset GPIO
> onboard-usb-dev 1c08000.pcie:...:usb-controller@0,0:hub@1: \
> probe with driver onboard-usb-dev failed with error -16
>
> The GPIO is also added to the root port's PERST# list and is asserted
> and deasserted as part of PCIe reset sequencing. On the RB3Gen2 this
> causes the USB hub to repeatedly re-enumerate:
>
> [ 116.479598] hub 2-1:1.0: USB hub found
> [ 116.488601] hub 2-1:1.0: USB hub found
> [ 116.496971] hub 2-1:1.0: USB hub found
> ...
>
> This disrupts the hub and devices connected to it.
>
> Restrict the recursive walk to children with device_type "pci", so
> PERST# GPIOs are collected only from PCI bridge nodes and the walk
> does not descend through endpoints.
>
> qocm_pcie_parse_ports() has made the same distinction since
> commit 45df22935bdc ("PCI: qcom: Restrict port parsing only to PCIe
> bridge child nodes"), but the PERST# walk added later did not carry over
> that check.
>
> This bug is distinct from commit 3edb3a038d42 ("PCI: qcom: Skip PERST#
> GPIOs provided by downstream PCIe devices"), which filters PERST# GPIOs
> based on their provider. Here the GPIO is provided by the SoC TLMM; the
> bug is that reset-gpios is consumed from a non-bridge node at all.
>
> Fixes: 2fd60a2edb83 ("PCI: qcom: Parse PERST# from all PCIe bridge nodes")
> Cc: stable@vger.kernel.org
> Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Reviewed-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com> -
Krishna Chaitanya.
> ---
> USB/Ethernet issue on RB3Gen2.
> ---
> drivers/pci/controller/dwc/pcie-qcom.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index b58a607b713f..89a476c37098 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1953,7 +1953,7 @@ static bool qcom_pcie_is_child_node(struct device *dev,
> return false;
> }
>
> -/* Parse PERST# from all nodes in depth first manner starting from @np */
> +/* Collect PERST# GPIOs from PCI bridge nodes depth-first, starting at @np */
> static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
> struct qcom_pcie_port *port,
> struct device_node *np)
> @@ -2019,6 +2019,9 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
>
> parse_child_node:
> for_each_available_child_of_node_scoped(np, child) {
> + if (!of_node_is_type(child, "pci"))
> + continue;
> +
> ret = qcom_pcie_parse_perst(pcie, port, child);
> if (ret)
> return ret;
>
> ---
> base-commit: 570f7e331f5febb30f1384817463c7e42b65ca7d
> change-id: 20260829-wip-obbardc-drivers-pcie-qcom-rb3gen2-usb-fix-ef551ccc0a8d
>
> Best regards,
> --
> Christopher Obbard <chris.obbard@oss.qualcomm.com>
>
>
© 2016 - 2026 Red Hat, Inc.