[PATCH] PCI: imx6: fix power domain leak on probe failure
hanzhijian <[email protected]>
| Newsgroups | org.kernel.vger.linux-pci,dev.linux.lists.imx,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| 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