From nobody Tue Dec 2 00:26:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 78249314A99; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; cv=none; b=HhL47vRk6WSxVzyhPQgxlogxvFSdlwF47g8W/NHpxajIg3Ey8m3BW6uLYf30zjkOvXZ5irHPzP2ABXNpIDtN5mwkcw01kTmelPfUxaGovHeOmVcAB4KcHyW+ePRkMBHIeuNer5W+qA0P/MBpT6JAn/QjdM1pOBbe9fBAUZoP3U8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; c=relaxed/simple; bh=iVE1obRMnciMq20+t0E0Wgd8Gf0+fcO2/7lj1bhky3Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OCl/4TyqKeG7kJqaHipIEtrzUGM1+xekgEwOp8vJ4xCf5Jj6RXrsatfCPIuEpK+d1Vd1U478TFGe2t3Ih8wq1K6YXpc2iBEgUA/qkeTp9BGE+7qHJvP1Z8CSZl/tE3lCumN9OK0asIgBdlr9DVzKRPcU/j2xIhAtnQhM5DEUXJ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HPGLSOGi; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HPGLSOGi" Received: by smtp.kernel.org (Postfix) with ESMTPS id E08DDC116C6; Mon, 24 Nov 2025 16:21:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764001264; bh=iVE1obRMnciMq20+t0E0Wgd8Gf0+fcO2/7lj1bhky3Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=HPGLSOGiOYUsgaQWkQmj06b+f2vBryJMJNG5VNG5/c8U76UwvLjNF/AAahqhh1IYo ZyFZzRpAP1eYh88Njvb99vcdbzhJuv9DGvnayocYqJn8uERakCSNvhsADmhIkzTnsX t8EXqJviNhhMdzEsXcW59evaWW+7AYXH+kXixqpffGaPhoDX6r4JhvBZVIdyMRacVg UVG6gTHmQPVRX7SLcNyZ1QOtbvjYUGM+70ToeDUZ33pq8XpRn9cmuJLNrk8xHtbtXm UNQrll/O3TDCOTwRoFPnonTJCEsBU4KYbjkpoC5K0tLQnv2zW8+fHbF+wrxGXGsyYP 90SKxO7LT0uMw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE5E0CFD313; Mon, 24 Nov 2025 16:21:03 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Mon, 24 Nov 2025 21:50:44 +0530 Subject: [PATCH 1/5] PCI: qcom: Parse PERST# from all PCIe bridge nodes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251124-pci-pwrctrl-rework-v1-1-78a72627683d@oss.qualcomm.com> References: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> In-Reply-To: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Brian Norris , Krishna Chaitanya Chundru , Niklas Cassel , Alex Elder , Manivannan Sadhasivam X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7456; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=MCSBhbbg9vGMpjTEI8+dqcv0csxSz0v3Na25Cc4NhqQ=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBpJIXr9wE/ax/MgVsttiO9zRmORDEiQFQ7sdJLR 8msynOU2a6JATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaSSF6wAKCRBVnxHm/pHO 9cYYB/99atS90AZH4KZDkPaL0aUWjyDucZSceInRXLoTp4vI7nFPdr9yHTJ+pg25bPACyaS78gY AWu+wM0FAaMZnl2cLToHhM224T3/UnTh9Fy5aRDsYdxagyxo2oJGx7soaqmJHvfnaz0tAVgF+ev dWljCMEoKRkZCmH7RCPBPgSQa3AddMR+Bjjj620kMnrETpEVLEkqDA2vlBGt4Am+93wH1fMaWrb NichJXuGZz5dORUL6QdMMCIPDFFxfOkhwm1F3YRCDSxk7OXlXGMJOcJG1kLT+kM3sEDXN9D2cAb Rg0yZ6t8g2eVROzvjv6wKj9XWjKjFZPMlzE47JoEQOenoKbh X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam Devicetree schema allows the PERST# GPIO to be present in all PCIe bridge nodes, not just in Root Port node. But the current logic parses PERST# only from the Root Port nodes. Though it is not causing any issue on the current platforms, the upcoming platforms will have PERST# in PCIe switch downstream ports also. So this requires parsing all the PCIe bridge nodes for the PERST# GPIO. Hence, rework the parsing logic to extend to all PCIe bridge nodes starting from the Root Port node. If the 'reset-gpios' property is found for a PCI bridge node, the GPIO descriptor will be stored in qcom_pcie_perst::desc and added to the qcom_pcie_port::perst list. It should be noted that if more than one bridge node has the same GPIO for PERST# (shared PERST#), the driver will error out. This is due to the limitation in the GPIOLIB subsystem that allows only exclusive (non-shared) access to GPIOs from consumers. But this is soon going to get fixed. Once that happens, it will get incorporated in this driver. So for now, PERST# sharing is not supported. Signed-off-by: Manivannan Sadhasivam Tested-by: Chen-Yu Tsai --- drivers/pci/controller/dwc/pcie-qcom.c | 102 +++++++++++++++++++++++++++--= ---- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controlle= r/dwc/pcie-qcom.c index 805edbbfe7eb..7b6f4a391ce4 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -281,10 +281,15 @@ struct qcom_pcie_cfg { bool no_l0s; }; =20 +struct qcom_pcie_perst { + struct list_head list; + struct gpio_desc *desc; +}; + struct qcom_pcie_port { struct list_head list; - struct gpio_desc *reset; struct phy *phy; + struct list_head perst; }; =20 struct qcom_pcie { @@ -305,11 +310,14 @@ struct qcom_pcie { =20 static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) { + struct qcom_pcie_perst *perst; struct qcom_pcie_port *port; int val =3D assert ? 1 : 0; =20 - list_for_each_entry(port, &pcie->ports, list) - gpiod_set_value_cansleep(port->reset, val); + list_for_each_entry(port, &pcie->ports, list) { + list_for_each_entry(perst, &port->perst, list) + gpiod_set_value_cansleep(perst->desc, val); + } =20 usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } @@ -1710,18 +1718,58 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = =3D { } }; =20 -static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node= *node) +/* 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, + struct device_node *np) { struct device *dev =3D pcie->pci->dev; - struct qcom_pcie_port *port; + struct qcom_pcie_perst *perst; struct gpio_desc *reset; - struct phy *phy; int ret; =20 - reset =3D devm_fwnode_gpiod_get(dev, of_fwnode_handle(node), - "reset", GPIOD_OUT_HIGH, "PERST#"); - if (IS_ERR(reset)) + if (!of_find_property(np, "reset-gpios", NULL)) + goto parse_child_node; + + reset =3D devm_fwnode_gpiod_get(dev, of_fwnode_handle(np), "reset", + GPIOD_OUT_HIGH, "PERST#"); + if (IS_ERR(reset)) { + /* + * FIXME: GPIOLIB currently supports exclusive GPIO access only. + * Non exclusive access is broken. But shared PERST# requires + * non-exclusive access. So once GPIOLIB properly supports it, + * implement it here. + */ + if (PTR_ERR(reset) =3D=3D -EBUSY) + dev_err(dev, "Shared PERST# is not supported\n"); + return PTR_ERR(reset); + } + + perst =3D devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); + if (!perst) + return -ENOMEM; + + INIT_LIST_HEAD(&perst->list); + perst->desc =3D reset; + list_add_tail(&perst->list, &port->perst); + +parse_child_node: + for_each_available_child_of_node_scoped(np, child) { + ret =3D qcom_pcie_parse_perst(pcie, port, child); + if (ret) + return ret; + } + + return 0; +} + +static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node= *node) +{ + struct device *dev =3D pcie->pci->dev; + struct qcom_pcie_port *port; + struct phy *phy; + int ret; =20 phy =3D devm_of_phy_get(dev, node, NULL); if (IS_ERR(phy)) @@ -1735,7 +1783,12 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pc= ie, struct device_node *node if (ret) return ret; =20 - port->reset =3D reset; + INIT_LIST_HEAD(&port->perst); + + ret =3D qcom_pcie_parse_perst(pcie, port, node); + if (ret) + return ret; + port->phy =3D phy; INIT_LIST_HEAD(&port->list); list_add_tail(&port->list, &pcie->ports); @@ -1745,9 +1798,10 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pc= ie, struct device_node *node =20 static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) { + struct qcom_pcie_perst *perst, *tmp_perst; + struct qcom_pcie_port *port, *tmp_port; struct device *dev =3D pcie->pci->dev; - struct qcom_pcie_port *port, *tmp; - int ret =3D -ENOENT; + int ret =3D -ENODEV; =20 for_each_available_child_of_node_scoped(dev->of_node, of_port) { if (!of_node_is_type(of_port, "pci")) @@ -1760,7 +1814,9 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pc= ie) return ret; =20 err_port_del: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_del(&perst->list); phy_exit(port->phy); list_del(&port->list); } @@ -1771,6 +1827,7 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pc= ie) static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) { struct device *dev =3D pcie->pci->dev; + struct qcom_pcie_perst *perst; struct qcom_pcie_port *port; struct gpio_desc *reset; struct phy *phy; @@ -1792,19 +1849,28 @@ static int qcom_pcie_parse_legacy_binding(struct qc= om_pcie *pcie) if (!port) return -ENOMEM; =20 - port->reset =3D reset; + perst =3D devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); + if (!perst) + return -ENOMEM; + port->phy =3D phy; INIT_LIST_HEAD(&port->list); list_add_tail(&port->list, &pcie->ports); =20 + perst->desc =3D reset; + INIT_LIST_HEAD(&port->perst); + INIT_LIST_HEAD(&perst->list); + list_add_tail(&perst->list, &port->perst); + return 0; } =20 static int qcom_pcie_probe(struct platform_device *pdev) { + struct qcom_pcie_perst *perst, *tmp_perst; + struct qcom_pcie_port *port, *tmp_port; const struct qcom_pcie_cfg *pcie_cfg; unsigned long max_freq =3D ULONG_MAX; - struct qcom_pcie_port *port, *tmp; struct device *dev =3D &pdev->dev; struct dev_pm_opp *opp; struct qcom_pcie *pcie; @@ -1945,7 +2011,7 @@ static int qcom_pcie_probe(struct platform_device *pd= ev) =20 ret =3D qcom_pcie_parse_ports(pcie); if (ret) { - if (ret !=3D -ENOENT) { + if (ret !=3D -ENODEV) { dev_err_probe(pci->dev, ret, "Failed to parse Root Port: %d\n", ret); goto err_pm_runtime_put; @@ -2004,7 +2070,9 @@ static int qcom_pcie_probe(struct platform_device *pd= ev) err_host_deinit: dw_pcie_host_deinit(pp); err_phy_exit: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_del(&perst->list); phy_exit(port->phy); list_del(&port->list); } --=20 2.48.1 From nobody Tue Dec 2 00:26:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 781BF314A63; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; cv=none; b=O8Km9uKkr0H+8n8zZ5Nspp/VoADxzwnlC2bTe0gZN9GirebhW6lrH1VuFguawDWNhct6lpExuYpYr1trrWRESjkOg1k8iiufQh1Rf+VTbnWfgnUzR0Rlkq0fJzlvgBLg89BkQNoUsLcWqYyvzAg9wkGH84idru6SegggDBRdG8o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; c=relaxed/simple; bh=hj0W70plhEe4m1xw3Pm9LugNFa+BQ7eFwiLsZvfg92o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YiF2ueMNj40IZysS3MNrw46vbFTFLA5xOS6x8VDaXKcSxXkfAlPAhkloUFJpH2l779zmBKaVW7WytKOk2CnhOihM1k4JKKynQOc1j7JcyHGxYzMZTTXYxH86FVV9yHOjDhIntV2TgjsnkvNfsJQArVZTqIDsoEg8Y3VEh4np4zM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QVskwYr5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QVskwYr5" Received: by smtp.kernel.org (Postfix) with ESMTPS id EBF8CC19425; Mon, 24 Nov 2025 16:21:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764001264; bh=hj0W70plhEe4m1xw3Pm9LugNFa+BQ7eFwiLsZvfg92o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=QVskwYr5gJ6iejEbV9hfZ664itEqtii0Y5UD1jxvRN08XCBs0tcV4lEL2o+kYSC1i mtwAUMhGPO2E3Hm1Rru04IW8xwMc845pOqUKVf/ylDt3IOk23tWZY3bybj9RCIs+GO 0WmCJ2iN0b0TNPN2Edk4mFFlaVE0oLhJzO+OXLJtOyn/v23f44sRn1lYImxSFfbkLa WwxAPrtNMURu0sRB0hkPctzfmJ8cluIHD+L/xZHJw41egWK2RzcMcLPjEXCA4lj9Vv GiqBBAudilaSPuHuZYGrLUZOuYUJ8Xsvx3EGa69DmAu7Ob2o9LUMVC36aMgb4r1hbu 5GJLR4nbmQiWA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2C4BCFD31D; Mon, 24 Nov 2025 16:21:03 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Mon, 24 Nov 2025 21:50:45 +0530 Subject: [PATCH 2/5] PCI/pwrctrl: Add 'struct pci_pwrctrl::power_{on/off}' callbacks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251124-pci-pwrctrl-rework-v1-2-78a72627683d@oss.qualcomm.com> References: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> In-Reply-To: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Brian Norris , Krishna Chaitanya Chundru , Niklas Cassel , Alex Elder , Manivannan Sadhasivam X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6293; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=6deGnX1CPbvEiEx2HgwsKZt+v6TUHFgUyDrenVaupTY=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBpJIXrGXndG74cMO1Hd7xDpblwiN6OUVi/XKe+s DK2u/TK/I6JATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaSSF6wAKCRBVnxHm/pHO 9S6kB/sG1Cn+iSU+3yUfjQEfdBWW32DohrGeCJdphfyNPqVL2BzBtXVt9kfS8yf1xC2FVo14irO 19VlWJz4piCuxuUlHk1z/EtEnxdUJU6MckI4xRMtyOjoESTIO2V1nxSFuZxQj/d2BNkKC2d+s4q Zp1zBV3TBtv4gdx4M0TylqAl2sn/HZxMHULeGVKBl7Yazo6y/jVNVYlugr3gnUPqmWOAen6T8te EKrFKmvt7/hMgpzuUloWmnt6KPdxsN/srNw/M03qnSoK6UCKTof7C1IDs3siONISBm6+ZMHqQ7P EZPPRPOYzVp4DvPHCb8zG14y/TLbDjcfqL1u5ozQJKtohxkU X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam To allow the pwrctrl core to control the power on/off sequences of the pwrctrl drivers, add the 'struct pci_pwrctrl::power_{on/off}' callbacks and populate them in the respective pwrctrl drivers. The pwrctrl drivers still power on the resources on their own now. So there is no functional change. Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Tested-by: Chen-Yu Tsai --- drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 27 +++++++++++++++--- drivers/pci/pwrctrl/slot.c | 48 ++++++++++++++++++++++------= ---- include/linux/pci-pwrctrl.h | 4 +++ 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl= /pci-pwrctrl-pwrseq.c index 4e664e7b8dd2..0fb9038a1d18 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -52,11 +52,27 @@ static const struct pci_pwrctrl_pwrseq_pdata pci_pwrctr= l_pwrseq_qcom_wcn_pdata =3D .validate_device =3D pci_pwrctrl_pwrseq_qcm_wcn_validate_device, }; =20 +static int pci_pwrctrl_pwrseq_power_on(struct pci_pwrctrl *ctx) +{ + struct pci_pwrctrl_pwrseq_data *data =3D container_of(ctx, struct pci_pwr= ctrl_pwrseq_data, + ctx); + + return pwrseq_power_on(data->pwrseq); +} + +static void pci_pwrctrl_pwrseq_power_off(struct pci_pwrctrl *ctx) +{ + struct pci_pwrctrl_pwrseq_data *data =3D container_of(ctx, struct pci_pwr= ctrl_pwrseq_data, + ctx); + + pwrseq_power_off(data->pwrseq); +} + static void devm_pci_pwrctrl_pwrseq_power_off(void *data) { - struct pwrseq_desc *pwrseq =3D data; + struct pci_pwrctrl_pwrseq_data *pwrseq_data =3D data; =20 - pwrseq_power_off(pwrseq); + pci_pwrctrl_pwrseq_power_off(&pwrseq_data->ctx); } =20 static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) @@ -85,16 +101,19 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_de= vice *pdev) return dev_err_probe(dev, PTR_ERR(data->pwrseq), "Failed to get the power sequencer\n"); =20 - ret =3D pwrseq_power_on(data->pwrseq); + ret =3D pci_pwrctrl_pwrseq_power_on(&data->ctx); if (ret) return dev_err_probe(dev, ret, "Failed to power-on the device\n"); =20 ret =3D devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, - data->pwrseq); + data); if (ret) return ret; =20 + data->ctx.power_on =3D pci_pwrctrl_pwrseq_power_on; + data->ctx.power_off =3D pci_pwrctrl_pwrseq_power_off; + pci_pwrctrl_init(&data->ctx, dev); =20 ret =3D devm_pci_pwrctrl_device_set_ready(dev, &data->ctx); diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 3320494b62d8..14701f65f1f2 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -17,13 +17,36 @@ struct pci_pwrctrl_slot_data { struct pci_pwrctrl ctx; struct regulator_bulk_data *supplies; int num_supplies; + struct clk *clk; }; =20 -static void devm_pci_pwrctrl_slot_power_off(void *data) +static int pci_pwrctrl_slot_power_on(struct pci_pwrctrl *ctx) { - struct pci_pwrctrl_slot_data *slot =3D data; + struct pci_pwrctrl_slot_data *slot =3D container_of(ctx, struct pci_pwrct= rl_slot_data, ctx); + int ret; + + ret =3D regulator_bulk_enable(slot->num_supplies, slot->supplies); + if (ret < 0) { + dev_err(slot->ctx.dev, "Failed to enable slot regulators\n"); + return ret; + } + + return clk_prepare_enable(slot->clk); +} + +static void pci_pwrctrl_slot_power_off(struct pci_pwrctrl *ctx) +{ + struct pci_pwrctrl_slot_data *slot =3D container_of(ctx, struct pci_pwrct= rl_slot_data, ctx); =20 regulator_bulk_disable(slot->num_supplies, slot->supplies); + clk_disable_unprepare(slot->clk); +} + +static void devm_pci_pwrctrl_slot_release(void *data) +{ + struct pci_pwrctrl_slot_data *slot =3D data; + + pci_pwrctrl_slot_power_off(&slot->ctx); regulator_bulk_free(slot->num_supplies, slot->supplies); } =20 @@ -31,7 +54,6 @@ static int pci_pwrctrl_slot_probe(struct platform_device = *pdev) { struct pci_pwrctrl_slot_data *slot; struct device *dev =3D &pdev->dev; - struct clk *clk; int ret; =20 slot =3D devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); @@ -46,23 +68,21 @@ static int pci_pwrctrl_slot_probe(struct platform_devic= e *pdev) } =20 slot->num_supplies =3D ret; - ret =3D regulator_bulk_enable(slot->num_supplies, slot->supplies); - if (ret < 0) { - dev_err_probe(dev, ret, "Failed to enable slot regulators\n"); - regulator_bulk_free(slot->num_supplies, slot->supplies); - return ret; - } =20 - ret =3D devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, + ret =3D devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_release, slot); if (ret) return ret; =20 - clk =3D devm_clk_get_optional_enabled(dev, NULL); - if (IS_ERR(clk)) { - return dev_err_probe(dev, PTR_ERR(clk), + slot->clk =3D devm_clk_get_optional(dev, NULL); + if (IS_ERR(slot->clk)) + return dev_err_probe(dev, PTR_ERR(slot->clk), "Failed to enable slot clock\n"); - } + + pci_pwrctrl_slot_power_on(&slot->ctx); + + slot->ctx.power_on =3D pci_pwrctrl_slot_power_on; + slot->ctx.power_off =3D pci_pwrctrl_slot_power_off; =20 pci_pwrctrl_init(&slot->ctx, dev); =20 diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index 4aefc7901cd1..bd0ee9998125 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -31,6 +31,8 @@ struct device_link; /** * struct pci_pwrctrl - PCI device power control context. * @dev: Address of the power controlling device. + * @power_on: Callback to power on the power controlling device. + * @power_off: Callback to power off the power controlling device. * * An object of this type must be allocated by the PCI power control devic= e and * passed to the pwrctrl subsystem to trigger a bus rescan and setup a dev= ice @@ -38,6 +40,8 @@ struct device_link; */ struct pci_pwrctrl { struct device *dev; + int (*power_on)(struct pci_pwrctrl *pwrctrl); + void (*power_off)(struct pci_pwrctrl *pwrctrl); =20 /* private: internal use only */ struct notifier_block nb; --=20 2.48.1 From nobody Tue Dec 2 00:26:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FDA93164CE; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001265; cv=none; b=mjzxuBguVS3sLYMZIFGDQWtTpFehBY39d4Kc/KWAQmep+O0PxYQkoAcJmjJr07qauDNN+OIdOlRPnrrH9topYPFyiE+t1fYMs9Dg6ava579x6h5b45iE/N2OZxwypdVHs4c2QuG8ThZ3Q9wZq2S63c2zEpr5MbfsPJsSdLw4Kts= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001265; c=relaxed/simple; bh=zco2/BCviUfYxQpIBiOf3uIUke+Ln/UupZMf14cmwU4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dzNY/IhteYH3b1+Vs98qzbc4diCLP2keo0EEwudHZAqtIPZu1viacPa6qN250e8ZHodGiwYPMFpzz4CTW2BX6FmWUG7KllRft2a5JpXAqbZyn9y9ZJHo5qRN0x53hWoAsr3NGlqpwbJu2FIJ6dB0KA4T0Mc52nS0nt/xGrBHRDA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tX4AFWpI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tX4AFWpI" Received: by smtp.kernel.org (Postfix) with ESMTPS id 16375C2BC9E; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764001264; bh=zco2/BCviUfYxQpIBiOf3uIUke+Ln/UupZMf14cmwU4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=tX4AFWpI+CXU4SRPf0DAt9f7TVgF1FSZXjXwxbcwV+3vaV93QOAzv3Qu2HGQLX4Ed m6w1J2W6SdVlXQ2i59MVB4aAQ3SR3kIqehaLeHgY9jt/66J0tzuCVYiICmdqqNSdvE GG100GfK6C6uiRn3dazTxwb8NZz7PG0xpwGGpqLh32zitq8gEJ+46r2E9Vteyn1PKh ZbByLWxUO8ldnMRNq4Hgv7/3XzaNe9K5SwinuSHHn53qs7Sd3s7ra2gX1wRqKZ7bWx MvvN0taObU71dGfCmNRNn3Td6e3BtBSoXIPorkZZjUhkB5sY5oL/LxsDvi16zBDYW3 vXQvBxK+awPFQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 00F61CFD340; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Mon, 24 Nov 2025 21:50:46 +0530 Subject: [PATCH 3/5] PCI/pwrctrl: Add APIs for explicitly creating and destroying pwrctrl devices Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251124-pci-pwrctrl-rework-v1-3-78a72627683d@oss.qualcomm.com> References: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> In-Reply-To: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Brian Norris , Krishna Chaitanya Chundru , Niklas Cassel , Alex Elder , Manivannan Sadhasivam X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6941; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=/6Zt/61i3oECj3Xro/3od290T1IlBj1jROy08O6jXW0=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBpJIXsL9zARIZVQxKtfxwg02B6fFzC0iVDfYUnq jGgerdkXYuJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaSSF7AAKCRBVnxHm/pHO 9Q/NB/4n0J8WQEPs8xDJLfR+Aau9u8lhR55Y2gEhf6uhKpyRpZVQKC14U2+KSAWTLu96V6SCiUd nS5P3qha4D49yPFBWTbvoV0YJmlqVwOp1e24J51X+qroPmMl7uRRI9+7aCg9+aSXT1coTTQC0cT ZrUG7eU/rrPMVF9ZOEsZCS+x0C41O0j/c2qfiKKQViebMfEYCH9Eq61DLQz+c5JeCdvtOoyhHlN /fNTuYDXN7lRNUlTuDasE/1FsmEce2malKF9ZxxoQhmb4h4xIM+z+8UXsFyWoY4Qj8e/6fyQQWm SWobMaJAE+iV5nOxNIaiLqxnATDrMnIeg+9MsP6a0SbJwida X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Krishna Chaitanya Chundru Previously, the PCI core created pwrctrl devices during pci_scan_device() on its own and then skipped enumeration of those devices, hoping the pwrctrl driver would power them on and trigger a bus rescan. This approach works for endpoint devices directly connected to Root Ports, but it fails for PCIe switches acting as bus extenders. When the switch requires pwrctrl support, and the pwrctrl driver is not available during the pwrctrl device creation, it's enumeration will be skipped during the initial PCI bus scan. This premature scan leads the PCI core to allocate resources (bridge windows, bus numbers) for the upstream bridge based on available downstream buses at scan time. For non-hotplug capable bridges, PCI core typically allocates resources based on the number of buses available during the initial bus scan, which happens to be just one if the switch is not powered on and enumerated at that time. When the switch gets enumerated later on, it will fail due to the lack of upstream resources. As a result, a PCIe switch powered on by the pwrctrl driver cannot be reliably enumerated currently. Either the switch has to be enabled in the bootloader or the switch pwrctrl driver has to be loaded during the pwrctrl device creation time to workaround these issues. This commit introduces new APIs to explicitly create and destroy pwrctrl devices from controller drivers by recursively scanning the PCI child nodes of the controller. These APIs allow creating pwrctrl devices based on the original criteria and are intended to be called during controller probe and removal. These APIs, together with the upcoming APIs for power on/off will allow the controller drivers to power on all the devices before starting the initial bus scan, thereby solving the resource allocation issue. Signed-off-by: Krishna Chaitanya Chundru [mani: splitted the patch, cleaned up the code, and rewrote description] Signed-off-by: Manivannan Sadhasivam Tested-by: Chen-Yu Tsai --- drivers/pci/pwrctrl/core.c | 112 ++++++++++++++++++++++++++++++++++++++++= ++++ include/linux/pci-pwrctrl.h | 8 +++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 6bdbfed584d6..6eca54e0d540 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -3,14 +3,21 @@ * Copyright (C) 2024 Linaro Ltd. */ =20 +#define dev_fmt(fmt) "Pwrctrl: " fmt + #include #include #include +#include +#include #include #include +#include #include #include =20 +#include "../pci.h" + static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long act= ion, void *data) { @@ -145,6 +152,111 @@ int devm_pci_pwrctrl_device_set_ready(struct device *= dev, } EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); =20 +static int pci_pwrctrl_create_device(struct device_node *np, struct device= *parent) +{ + struct platform_device *pdev; + int ret; + + for_each_available_child_of_node_scoped(np, child) { + ret =3D pci_pwrctrl_create_device(child, parent); + if (ret) + return ret; + } + + /* Bail out if the platform device is already available for the node */ + pdev =3D of_find_device_by_node(np); + if (pdev) { + put_device(&pdev->dev); + return 0; + } + + /* + * Sanity check to make sure that the node has the compatible property + * to allow driver binding. + */ + if (!of_property_present(np, "compatible")) + return 0; + + /* + * Check whether the pwrctrl device really needs to be created or not. + * This is decided based on at least one of the power supplies being + * defined in the devicetree node of the device. + */ + if (!of_pci_supply_present(np)) { + dev_dbg(parent, "Skipping OF node: %s\n", np->name); + return 0; + } + + /* Now create the pwrctrl device */ + pdev =3D of_platform_device_create(np, NULL, parent); + if (!pdev) { + dev_err(parent, "Failed to create pwrctrl device for node: %s\n", np->na= me); + return -EINVAL; + } + + return 0; +} + +/** + * pci_pwrctrl_create_devices - Create pwrctrl devices + * + * @parent: Parent PCI device for which the pwrctrl devices need to be cre= ated. + * + * This function recursively creates pwrctrl devices for the child nodes + * of the specified PCI parent device in a depth first manner. + * + * Returns: 0 on success, negative error number on error. + */ +int pci_pwrctrl_create_devices(struct device *parent) +{ + int ret; + + for_each_available_child_of_node_scoped(parent->of_node, child) { + ret =3D pci_pwrctrl_create_device(child, parent); + if (ret) { + pci_pwrctrl_destroy_devices(parent); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_create_devices); + +static void pci_pwrctrl_destroy_device(struct device_node *np) +{ + struct platform_device *pdev; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_destroy_device(child); + + pdev =3D of_find_device_by_node(np); + if (!pdev) + return; + + of_device_unregister(pdev); + put_device(&pdev->dev); + + of_node_clear_flag(np, OF_POPULATED); +} + +/** + * pci_pwrctrl_destroy_devices - Destroy pwrctrl devices + * + * @parent: Parent PCI device for which the pwrctrl devices need to be des= troyed. + * + * This function recursively destroys pwrctrl devices for the child nodes + * of the specified PCI parent device in a depth first manner. + */ +void pci_pwrctrl_destroy_devices(struct device *parent) +{ + struct device_node *np =3D parent->of_node; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_destroy_device(child); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_destroy_devices); + MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_DESCRIPTION("PCI Device Power Control core driver"); MODULE_LICENSE("GPL"); diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index bd0ee9998125..5590ffec0bea 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -54,5 +54,11 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwr= ctrl); void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl); int devm_pci_pwrctrl_device_set_ready(struct device *dev, struct pci_pwrctrl *pwrctrl); - +#if IS_ENABLED(CONFIG_PCI_PWRCTRL) +int pci_pwrctrl_create_devices(struct device *parent); +void pci_pwrctrl_destroy_devices(struct device *parent); +#else +static inline int pci_pwrctrl_create_devices(struct device *parent) { retu= rn 0; } +static void pci_pwrctrl_destroy_devices(struct device *parent) { } +#endif #endif /* __PCI_PWRCTRL_H__ */ --=20 2.48.1 From nobody Tue Dec 2 00:26:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5EECC3148BB; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; cv=none; b=m+bWKSJrU88br/WYairvkbxEfzQr7e+yzorDQgq76wUqCO4Eroov3OoXUkG96nzd1tGlVw6EZSduTVgaZh+6AGedrrxVzG3wPf16sNRViKW3uVExOJAmBE0SogPwLYKo/ES09m3/A1CmPz+63M57hLwIDXytIRB3nvDtugqYKqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001264; c=relaxed/simple; bh=2/wSjlYlmesfAG0/zAvXE+XbKKwCVNRs5QkoifeUpB0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=siierCoVZANOAgsUjxNcCf8g5L0H/ZGReI20a1+wg3O4SDtCW6xNZ++vBNhzgezR6+p36p0a7pPc+N6Kw/SJJ+yqxZPA0Y7isriyvVHkkNUkKJkytXs8u2Q1bxq2j/lmcvide+F+1oBQIuNZcn3ayU3+s5aFr57O0kAYOSsZTms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kdWWtbSB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kdWWtbSB" Received: by smtp.kernel.org (Postfix) with ESMTPS id 2408FC2BCB3; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764001264; bh=2/wSjlYlmesfAG0/zAvXE+XbKKwCVNRs5QkoifeUpB0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=kdWWtbSBrAJVZ5V4n/3cPF7R60EDNjhTCVwolPQAaR+jL+F+bEZm+dPq40mAUo5UR JqUprs/4D9ABmetu9DV2pxVqW5lm21a8IYRIU6962f+XSt3kIwKqEup2nOCAJMcuCS Ofia37m8ZziaNoGBRFKMAU9P+utyjEjWL5o/RMe5X9R1QQbn6bP2+gc6Rax+BeLKjM f4TpAgIE5/rPgoAAR/exiP2dIZHuL6TbHIMeWhY4lkb+DsK1cc9qDyT8BGYBya14V8 ht3jaSQvKMOKmZ2CS5YP0n49EegSiN94slHO/NZ///IWr99AJqd3dGndTB3x6AXb/U svrYULLRJtGtQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1BB57CFD318; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Mon, 24 Nov 2025 21:50:47 +0530 Subject: [PATCH 4/5] PCI/pwrctrl: Add APIs to power on/off the pwrctrl devices Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251124-pci-pwrctrl-rework-v1-4-78a72627683d@oss.qualcomm.com> References: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> In-Reply-To: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Brian Norris , Krishna Chaitanya Chundru , Niklas Cassel , Alex Elder , Manivannan Sadhasivam X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6010; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=cTf/zTyNct49tnAIkI8rXW+P63X5Y4jjQ+JhAwnxQfc=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBpJIXsO9rD/aqEW0RypVmV8irmgBjyoBahPFk8m tpgvqsSyHyJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaSSF7AAKCRBVnxHm/pHO 9bpcB/4ziIXp+vpYF7OTtY8KxDXddG3PWy+86Gdi24L4BV/3N7YXekjVocK2ZxBfvnpa9wS/5J/ pR001gLV4LGV8zzZj0iedAt/MKEno91JVxZ90a64ViJcZJsREG4meNY3MXh4sJMzvvbHA7t4JDH wFLLGZ1ZF4+CD8Lq5IaPqZxvCjMUXA2S7D5IFiY9Ed2vvuyZxbT6jBuu/1mYEmuAPzZ/TxA5S3z rb5IKvMpBcQX7m3RbhuR2nmA8ZVw5veX7IRofrfwNyZgoRSjPjvm5qH5FGekPy/fk2jSUGPvtAX 91KzEafzULFaisrqcpQYuX8XOhVoPqVCMPUDlKHsPhOKbmb6 X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam To fix PCIe bridge resource allocation issues when powering PCIe switches with the pwrctrl driver, introduce APIs to explicitly power on and off all related devices simultaneously. Previously, the individual pwrctrl drivers powered on/off the PCIe devices autonomously, without any control from the controller drivers. But to enforce ordering w.r.t powering on the devices, these APIs will power on/off all the devices at the same time. The pci_pwrctrl_power_on_devices() API recursively scans the PCI child nodes, makes sure that pwrctrl drivers are bind to devices, and calls their power_on() callbacks. Similarly, pci_pwrctrl_power_off_devices() API powers off devices recursively via their power_off() callbacks. These APIs are expected to be called during the controller probe and suspend/resume time to power on/off the devices. But before calling these APIs, the pwrctrl devices should've been created beforehand using the pci_pwrctrl_{create/destroy}_devices() APIs. Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bartosz Golaszewski Tested-by: Chen-Yu Tsai --- drivers/pci/pwrctrl/core.c | 121 ++++++++++++++++++++++++++++++++++++++++= ++++ include/linux/pci-pwrctrl.h | 4 ++ 2 files changed, 125 insertions(+) diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 6eca54e0d540..e0a0cf015bd0 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -65,6 +65,7 @@ void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct= device *dev) { pwrctrl->dev =3D dev; INIT_WORK(&pwrctrl->work, rescan_work_func); + dev_set_drvdata(dev, pwrctrl); } EXPORT_SYMBOL_GPL(pci_pwrctrl_init); =20 @@ -152,6 +153,126 @@ int devm_pci_pwrctrl_device_set_ready(struct device *= dev, } EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); =20 +static int __pci_pwrctrl_power_on_device(struct device *dev) +{ + struct pci_pwrctrl *pwrctrl =3D dev_get_drvdata(dev); + + if (!pwrctrl) + return 0; + + return pwrctrl->power_on(pwrctrl); +} + +/* + * Power on the devices in a depth first manner. Before powering on the de= vice, + * make sure its driver is bound. + */ +static int pci_pwrctrl_power_on_device(struct device_node *np) +{ + struct platform_device *pdev; + int ret; + + for_each_available_child_of_node_scoped(np, child) { + ret =3D pci_pwrctrl_power_on_device(child); + if (ret) + return ret; + } + + pdev =3D of_find_device_by_node(np); + if (pdev) { + if (!device_is_bound(&pdev->dev)) { + dev_err(&pdev->dev, "driver is not bound\n"); + ret =3D -EPROBE_DEFER; + } else { + ret =3D __pci_pwrctrl_power_on_device(&pdev->dev); + } + put_device(&pdev->dev); + + if (ret) + return ret; + } + + return 0; +} + +/** + * pci_pwrctrl_power_on_devices - Power on the pwrctrl devices + * + * @parent: Parent PCI device for which the pwrctrl devices need to be pow= ered + * on. + * + * This function recursively traverses all pwrctrl devices for the child n= odes + * of the specified PCI parent device, and powers them on in a depth first + * manner. + * + * Returns: 0 on success, negative error number on error. + */ +int pci_pwrctrl_power_on_devices(struct device *parent) +{ + struct device_node *np =3D parent->of_node; + int ret; + + for_each_available_child_of_node_scoped(np, child) { + ret =3D pci_pwrctrl_power_on_device(child); + if (ret) { + pci_pwrctrl_power_off_devices(parent); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_power_on_devices); + +static void __pci_pwrctrl_power_off_device(struct device *dev) +{ + struct pci_pwrctrl *pwrctrl =3D dev_get_drvdata(dev); + + if (!pwrctrl) + return; + + return pwrctrl->power_off(pwrctrl); +} + +static int pci_pwrctrl_power_off_device(struct device_node *np) +{ + struct platform_device *pdev; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_power_off_device(child); + + pdev =3D of_find_device_by_node(np); + if (pdev) { + if (device_is_bound(&pdev->dev)) + __pci_pwrctrl_power_off_device(&pdev->dev); + + put_device(&pdev->dev); + } + + return 0; +} + +/** + * pci_pwrctrl_power_off_devices - Power off the pwrctrl devices + * + * @parent: Parent PCI device for which the pwrctrl devices need to be pow= ered + * off. + * + * This function recursively traverses all pwrctrl devices for the child n= odes + * of the specified PCI parent device, and powers them off in a depth first + * manner. + * + * Returns: 0 on success, negative error number on error. + */ +void pci_pwrctrl_power_off_devices(struct device *parent) +{ + struct device_node *np =3D parent->of_node; + + for_each_available_child_of_node_scoped(np, child) + pci_pwrctrl_power_off_device(child); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_power_off_devices); + static int pci_pwrctrl_create_device(struct device_node *np, struct device= *parent) { struct platform_device *pdev; diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h index 5590ffec0bea..1b77769eebbe 100644 --- a/include/linux/pci-pwrctrl.h +++ b/include/linux/pci-pwrctrl.h @@ -57,8 +57,12 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev, #if IS_ENABLED(CONFIG_PCI_PWRCTRL) int pci_pwrctrl_create_devices(struct device *parent); void pci_pwrctrl_destroy_devices(struct device *parent); +int pci_pwrctrl_power_on_devices(struct device *parent); +void pci_pwrctrl_power_off_devices(struct device *parent); #else static inline int pci_pwrctrl_create_devices(struct device *parent) { retu= rn 0; } static void pci_pwrctrl_destroy_devices(struct device *parent) { } +static inline int pci_pwrctrl_power_on_devices(struct device *parent) { re= turn 0; } +static void pci_pwrctrl_power_off_devices(struct device *parent) { } #endif #endif /* __PCI_PWRCTRL_H__ */ --=20 2.48.1 From nobody Tue Dec 2 00:26:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FD293164C7; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001265; cv=none; b=XD/LDwq8a2s2ICJ+V5NZmeSEwOCyF6kvowjV9kknD0ueFyEG93P9X261jbjqgWarhfoSuZjNDUnsXGqTdUQ9cm3SjAptJhJkzPqxIQlEl24YExemQrkCG1aTod6QaMAvTfhB0oaFmE3O+PdcQHgoxZtNsP8taQUGfil+4+PfQXo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764001265; c=relaxed/simple; bh=thA6EpEnjrSH7ZNxTMbFIvg+M/dmxUF6+YiplwO094U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=h5ipdSjf+Wq/rkRk1vLkFUu1xBCAEPZmMuqyWEWkqVbGQ7LoUmtQYHk22BnOOnjmCR9g3JbLF13A9ZQo4qOCYtr/On764rEfXnxjtxFO55LhvKTvgZt65nvD9/kJLOwFY8dKkEjiH7pW6Li8bFdQLTXGjsWdLUeXCo9QUyopWgY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=soMAjU3U; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="soMAjU3U" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3CE58C2BCAF; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764001264; bh=thA6EpEnjrSH7ZNxTMbFIvg+M/dmxUF6+YiplwO094U=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=soMAjU3U1wAY1x7SsJcEMrAUqf/1HAJALwGF08q5McGkEw8hLjOMi30Sp7t8f2VGu KA/87m393gTRjMqAUDcs5+Hv5wYCrgowTTqZN9dRhkzBt6iry+lPg6kcCNne46eq4s av7GZ4PrSbmkrnVU3p1K6wT/4nVa8Wj87m0DbztU1qzQ734J/tLNdnUolya5C0+Q7t onqAU+u/7jJ4gW7SxyiyZUFXV/YvJZL1Rhv8FK5QckjdfxrboJ9KczjET24ed085H0 0vzmcy+p+kXoTSxhjykKehejkc3Tclsfl5lkMQP2wB1SSoKvTq1Msf3C8l+N75w65N gVm0OJLFiT/oQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3368DCFD31F; Mon, 24 Nov 2025 16:21:04 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Mon, 24 Nov 2025 21:50:48 +0530 Subject: [PATCH 5/5] PCI/pwrctrl: Switch to the new pwrctrl APIs Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251124-pci-pwrctrl-rework-v1-5-78a72627683d@oss.qualcomm.com> References: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> In-Reply-To: <20251124-pci-pwrctrl-rework-v1-0-78a72627683d@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Brian Norris , Krishna Chaitanya Chundru , Niklas Cassel , Alex Elder , Manivannan Sadhasivam X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9435; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=mDB7xVX8LQeuezZL74Dh28IYQlR8cBKIJVcKC/1hNZ4=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBpJIXsuhRW0BQsoWAqXI8mAjW/5GwKVcDDKgBng rzrf95SHSqJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaSSF7AAKCRBVnxHm/pHO 9e30B/99wz7r2n/2zStJ2MN+cr4rCnXIFcs3JJXu2aXW7Pqn4TQWeizI3uJlHOO8JekYzyKf9Fm LXkrJcZH5GPw3Rxf0e5RbsaE0fFltZoyHaAPTf/hoiqxIBF20kq5D7oyT1Hvo8B8XPWYnh2fr4g 5jKbg61hAGSDkZ54/pYW1Pj8ACCG0yJ9iCiZ+pcJUDFZbgiZ4et1F59+Cp4Xc7ZlIuOMPIDpd+6 YUrM7NeZ4vVwfgYr+cXDWNJZt4m/3e/Gxxvg/3fAf3OI4U7Mfqqa+jFBERAFYtVgYnrwv4he1fL Wx2Z818e6zkq2/IxKRfg2fEeyZxqz4bH3sYKlKnFLzS9iU0J X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam Adopt the recently introduced pwrctrl APIs to create, power on, destroy, and power off pwrctrl devices. In qcom_pcie_host_init(), call pci_pwrctrl_create_devices() to create devices, then pci_pwrctrl_power_on_devices() to power them on, both after controller resource initialization. Once successful, deassert PERST# for all devices. In qcom_pcie_host_deinit(), call pci_pwrctrl_power_off_devices() after asserting PERST#. Note that pci_pwrctrl_destroy_devices() is not called here, as deinit is only invoked during system suspend where device destruction is unnecessary. If the driver becomes removable in future, pci_pwrctrl_destroy_devices() should be called in the remove() handler. At last, remove the old pwrctrl framework code from the PCI core, as the new APIs are now the sole consumer of pwrctrl functionality. And also do not power on the pwrctrl drivers during probe() as this is now handled by the APIs. Co-developed-by: Krishna Chaitanya Chundru Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Tested-by: Chen-Yu Tsai --- drivers/pci/controller/dwc/pcie-qcom.c | 22 ++++++++++-- drivers/pci/probe.c | 59 ----------------------------= ---- drivers/pci/pwrctrl/core.c | 15 -------- drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c | 5 --- drivers/pci/pwrctrl/slot.c | 2 -- drivers/pci/remove.c | 20 ----------- 6 files changed, 20 insertions(+), 103 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controlle= r/dwc/pcie-qcom.c index 7b6f4a391ce4..691ba4243342 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1352,10 +1353,18 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *p= p) if (ret) goto err_deinit; =20 + ret =3D pci_pwrctrl_create_devices(pci->dev); + if (ret) + goto err_disable_phy; + + ret =3D pci_pwrctrl_power_on_devices(pci->dev); + if (ret) + goto err_pwrctrl_destroy; + if (pcie->cfg->ops->post_init) { ret =3D pcie->cfg->ops->post_init(pcie); if (ret) - goto err_disable_phy; + goto err_pwrctrl_power_off; } =20 qcom_ep_reset_deassert(pcie); @@ -1370,6 +1379,10 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) =20 err_assert_reset: qcom_ep_reset_assert(pcie); +err_pwrctrl_power_off: + pci_pwrctrl_power_off_devices(pci->dev); +err_pwrctrl_destroy: + pci_pwrctrl_destroy_devices(pci->dev); err_disable_phy: qcom_pcie_phy_power_off(pcie); err_deinit: @@ -1384,6 +1397,11 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp = *pp) struct qcom_pcie *pcie =3D to_qcom_pcie(pci); =20 qcom_ep_reset_assert(pcie); + /* + * No need to destroy pwrctrl devices as this function only gets called + * during system suspend as of now. + */ + pci_pwrctrl_power_off_devices(pci->dev); qcom_pcie_phy_power_off(pcie); pcie->cfg->ops->deinit(pcie); } @@ -2035,7 +2053,7 @@ static int qcom_pcie_probe(struct platform_device *pd= ev) =20 ret =3D dw_pcie_host_init(pp); if (ret) { - dev_err(dev, "cannot initialize host\n"); + dev_err_probe(dev, ret, "cannot initialize host\n"); goto err_phy_exit; } =20 diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c83e75a0ec12..34033605adf3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2533,56 +2533,6 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus,= int devfn, u32 *l, } EXPORT_SYMBOL(pci_bus_read_dev_vendor_id); =20 -#if IS_ENABLED(CONFIG_PCI_PWRCTRL) -static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *b= us, int devfn) -{ - struct pci_host_bridge *host =3D pci_find_host_bridge(bus); - struct platform_device *pdev; - struct device_node *np; - - np =3D of_pci_find_child_device(dev_of_node(&bus->dev), devfn); - if (!np) - return NULL; - - pdev =3D of_find_device_by_node(np); - if (pdev) { - put_device(&pdev->dev); - goto err_put_of_node; - } - - /* - * First check whether the pwrctrl device really needs to be created or - * not. This is decided based on at least one of the power supplies - * being defined in the devicetree node of the device. - */ - if (!of_pci_supply_present(np)) { - pr_debug("PCI/pwrctrl: Skipping OF node: %s\n", np->name); - goto err_put_of_node; - } - - /* Now create the pwrctrl device */ - pdev =3D of_platform_device_create(np, NULL, &host->dev); - if (!pdev) { - pr_err("PCI/pwrctrl: Failed to create pwrctrl device for node: %s\n", np= ->name); - goto err_put_of_node; - } - - of_node_put(np); - - return pdev; - -err_put_of_node: - of_node_put(np); - - return NULL; -} -#else -static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *b= us, int devfn) -{ - return NULL; -} -#endif - /* * Read the config data for a PCI device, sanity-check it, * and fill in the dev structure. @@ -2592,15 +2542,6 @@ static struct pci_dev *pci_scan_device(struct pci_bu= s *bus, int devfn) struct pci_dev *dev; u32 l; =20 - /* - * Create pwrctrl device (if required) for the PCI device to handle the - * power state. If the pwrctrl device is created, then skip scanning - * further as the pwrctrl core will rescan the bus after powering on - * the device. - */ - if (pci_pwrctrl_create_device(bus, devfn)) - return NULL; - if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) return NULL; =20 diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index e0a0cf015bd0..69bf2514c420 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -45,16 +45,6 @@ static int pci_pwrctrl_notify(struct notifier_block *nb,= unsigned long action, return NOTIFY_DONE; } =20 -static void rescan_work_func(struct work_struct *work) -{ - struct pci_pwrctrl *pwrctrl =3D container_of(work, - struct pci_pwrctrl, work); - - pci_lock_rescan_remove(); - pci_rescan_bus(to_pci_host_bridge(pwrctrl->dev->parent)->bus); - pci_unlock_rescan_remove(); -} - /** * pci_pwrctrl_init() - Initialize the PCI power control context struct * @@ -64,7 +54,6 @@ static void rescan_work_func(struct work_struct *work) void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) { pwrctrl->dev =3D dev; - INIT_WORK(&pwrctrl->work, rescan_work_func); dev_set_drvdata(dev, pwrctrl); } EXPORT_SYMBOL_GPL(pci_pwrctrl_init); @@ -95,8 +84,6 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrc= trl) if (ret) return ret; =20 - schedule_work(&pwrctrl->work); - return 0; } EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); @@ -109,8 +96,6 @@ EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); */ void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) { - cancel_work_sync(&pwrctrl->work); - /* * We don't have to delete the link here. Typically, this function * is only called when the power control device is being detached. If diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl= /pci-pwrctrl-pwrseq.c index 0fb9038a1d18..7697a8a5cdde 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -101,11 +101,6 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_de= vice *pdev) return dev_err_probe(dev, PTR_ERR(data->pwrseq), "Failed to get the power sequencer\n"); =20 - ret =3D pci_pwrctrl_pwrseq_power_on(&data->ctx); - if (ret) - return dev_err_probe(dev, ret, - "Failed to power-on the device\n"); - ret =3D devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, data); if (ret) diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 14701f65f1f2..888300aeefec 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -79,8 +79,6 @@ static int pci_pwrctrl_slot_probe(struct platform_device = *pdev) return dev_err_probe(dev, PTR_ERR(slot->clk), "Failed to enable slot clock\n"); =20 - pci_pwrctrl_slot_power_on(&slot->ctx); - slot->ctx.power_on =3D pci_pwrctrl_slot_power_on; slot->ctx.power_off =3D pci_pwrctrl_slot_power_off; =20 diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index ce5c25adef55..2a22595f38af 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -17,25 +17,6 @@ static void pci_free_resources(struct pci_dev *dev) } } =20 -static void pci_pwrctrl_unregister(struct device *dev) -{ - struct device_node *np; - struct platform_device *pdev; - - np =3D dev_of_node(dev); - if (!np) - return; - - pdev =3D of_find_device_by_node(np); - if (!pdev) - return; - - of_device_unregister(pdev); - put_device(&pdev->dev); - - of_node_clear_flag(np, OF_POPULATED); -} - static void pci_stop_dev(struct pci_dev *dev) { pci_pme_active(dev, false); @@ -66,7 +47,6 @@ static void pci_destroy_dev(struct pci_dev *dev) pci_doe_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); - pci_pwrctrl_unregister(&dev->dev); pci_free_resources(dev); put_device(&dev->dev); } --=20 2.48.1