[PATCH] PCI: imx6: fix power domain leak on probe failure

hanzhijian <[email protected]>
Newsgroups dev.linux.lists.imx,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <[email protected]>
imx_pcie_attach_pd() attaches the "pcie" and "pcie_phy" power domains
and creates device links to them, but nothing detaches them when
imx_pcie_probe() subsequently fails or defers.  This leaks the power
domains and device links on every probe failure or deferral.

Save the device links and add imx_pcie_detach_pd() to release them,
calling it from the probe error paths.

Reported-by: [email protected]
Link: https://lore.kernel.org/all/[email protected]/
Signed-off-by: hanzhijian <[email protected]>
---
 drivers/pci/controller/dwc/pci-imx6.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 39790e66b..4df548679 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -182,6 +182,9 @@ struct imx_pcie {
 	struct device		*pd_pcie;
 	/* power domain for pcie phy */
 	struct device		*pd_pcie_phy;
+	/* device links for the power domains */
+	struct device_link	*pd_link;
+	struct device_link	*pd_phy_link;
 	struct phy		*phy;
 	const struct imx_pcie_drvdata *drvdata;
 
@@ -662,6 +665,7 @@ static int imx_pcie_attach_pd(struct device *dev)
 		dev_err(dev, "Failed to add device_link to pcie pd\n");
 		return -EINVAL;
 	}
+	imx_pcie->pd_link = link;
 
 	imx_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy");
 	if (IS_ERR(imx_pcie->pd_pcie_phy))
@@ -675,10 +679,24 @@ static int imx_pcie_attach_pd(struct device *dev)
 		dev_err(dev, "Failed to add device_link to pcie_phy pd\n");
 		return -EINVAL;
 	}
+	imx_pcie->pd_phy_link = link;
 
 	return 0;
 }
 
+static void imx_pcie_detach_pd(struct imx_pcie *imx_pcie)
+{
+	if (imx_pcie->pd_link)
+		device_link_del(imx_pcie->pd_link);
+	if (imx_pcie->pd_pcie)
+		dev_pm_domain_detach(imx_pcie->pd_pcie, true);
+
+	if (imx_pcie->pd_phy_link)
+		device_link_del(imx_pcie->pd_phy_link);
+	if (imx_pcie->pd_pcie_phy)
+		dev_pm_domain_detach(imx_pcie->pd_pcie_phy, true);
+}
+
 static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
 {
 	if (enable)
@@ -1956,8 +1974,10 @@ static int imx_pcie_probe(struct platform_device *pdev)
 		return ret;
 
 	ret = pci_pwrctrl_create_devices(dev);
-	if (ret)
+	if (ret) {
+		imx_pcie_detach_pd(imx_pcie);
 		return dev_err_probe(dev, ret, "failed to create pwrctrl devices\n");
+	}
 
 	pci->use_parent_dt_ranges = true;
 	if (imx_pcie->drvdata->mode == DW_PCIE_EP_TYPE) {
@@ -1999,6 +2019,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
 	return 0;
 
 err_pwrctrl_destroy:
+	imx_pcie_detach_pd(imx_pcie);
 	if (ret != -EPROBE_DEFER)
 		pci_pwrctrl_destroy_devices(dev);
 	return ret;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.