PCI: tegra: Handle failure cases in tegra_pcie_power_on()
authorManikanta Maddireddy <mmaddireddy@nvidia.com>
Tue, 18 Jun 2019 18:01:41 +0000 (23:31 +0530)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Thu, 20 Jun 2019 16:12:45 +0000 (17:12 +0100)
Unroll the PCIe power on sequence if any one of the steps fails in
tegra_pcie_power_on().

Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Thierry Reding <treding@nvidia.com>
drivers/pci/controller/pci-tegra.c

index 464ba2538d52606eff261d6982455734f5724838..85c5e6a1e529b95d06509ec1b9e976514999b684 100644 (file)
@@ -1052,7 +1052,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
                err = clk_prepare_enable(pcie->pex_clk);
                if (err) {
                        dev_err(dev, "failed to enable PEX clock: %d\n", err);
-                       return err;
+                       goto regulator_disable;
                }
                reset_control_deassert(pcie->pex_rst);
        } else {
@@ -1061,7 +1061,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
                                                        pcie->pex_rst);
                if (err) {
                        dev_err(dev, "powerup sequence failed: %d\n", err);
-                       return err;
+                       goto regulator_disable;
                }
        }
 
@@ -1070,24 +1070,40 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
        err = clk_prepare_enable(pcie->afi_clk);
        if (err < 0) {
                dev_err(dev, "failed to enable AFI clock: %d\n", err);
-               return err;
+               goto powergate;
        }
 
        if (soc->has_cml_clk) {
                err = clk_prepare_enable(pcie->cml_clk);
                if (err < 0) {
                        dev_err(dev, "failed to enable CML clock: %d\n", err);
-                       return err;
+                       goto disable_afi_clk;
                }
        }
 
        err = clk_prepare_enable(pcie->pll_e);
        if (err < 0) {
                dev_err(dev, "failed to enable PLLE clock: %d\n", err);
-               return err;
+               goto disable_cml_clk;
        }
 
        return 0;
+
+disable_cml_clk:
+       if (soc->has_cml_clk)
+               clk_disable_unprepare(pcie->cml_clk);
+disable_afi_clk:
+       clk_disable_unprepare(pcie->afi_clk);
+powergate:
+       reset_control_assert(pcie->afi_rst);
+       reset_control_assert(pcie->pex_rst);
+       clk_disable_unprepare(pcie->pex_clk);
+       if (!dev->pm_domain)
+               tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+regulator_disable:
+       regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
+
+       return err;
 }
 
 static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)