From fb2dd488fadb4816807b8c5c9e7f062fd1e03f01 Mon Sep 17 00:00:00 2001 From: Wei Deng Date: Mon, 7 Sep 2026 17:51:29 +0530 Subject: [PATCH] FROMGIT: power: sequencing: pwrseq-pcie-m2: Support PCIe switch topologies The PCI parent OF node check in pwrseq_pcie_m2_notify() and pwrseq_pcie_m2_create_serdev() only looks at the immediate parent of the PCI endpoint device. This fails when a PCIe switch inserts one or more intermediate bridges between the root port and the endpoint. For example, on lemans-evk with IFP Mezzanine board, the Toshiba TC9562 PCIe switch creates two bridge devices (upstream and downstream ports) without OF nodes, so the WCN6855 BT device appears at depth 3 and its immediate parent has of_node=NULL. Add a helper pwrseq_pcie_m2_pci_parent_matches() that walks the PCI parent chain upward until it finds a device whose OF node matches the expected connector port node, or reaches a non-PCI device. Replace both single-level checks with this helper to handle arbitrary PCIe switch depths. Signed-off-by: Wei Deng Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260907122129.1577279-1-wei.deng@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/power/sequencing/pwrseq-pcie-m2.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c index 0b03b231219a4..168ca7931d8ec 100644 --- a/drivers/power/sequencing/pwrseq-pcie-m2.c +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c @@ -373,6 +373,21 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx, mutex_unlock(&ctx->list_lock); } +static bool pwrseq_pcie_m2_pci_parent_matches(struct pci_dev *pdev, + struct device_node *pci_parent) +{ + struct device *dev = pdev->dev.parent; + + while (dev) { + if (dev->of_node == pci_parent) + return true; + if (!dev_is_pci(dev)) + break; + dev = dev->parent; + } + return false; +} + static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -387,7 +402,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action */ struct device_node *pci_parent __free(device_node) = of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0); - if (!pci_parent || (pci_parent != pdev->dev.parent->of_node)) + if (!pci_parent || !pwrseq_pcie_m2_pci_parent_matches(pdev, pci_parent)) return NOTIFY_DONE; switch (action) { @@ -473,7 +488,7 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx) /* Create serdev for existing PCI devices if required */ for_each_pci_dev(pdev) { - if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node) + if (!pwrseq_pcie_m2_pci_parent_matches(pdev, pci_parent)) continue; if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {