PCI: tegra: Handle failure cases in tegra_pcie_power_on() [Linux 5.3]

This Linux kernel change "PCI: tegra: Handle failure cases in tegra_pcie_power_on()" is included in the Linux 5.3 release. This change is authored by Manikanta Maddireddy <mmaddireddy [at] nvidia.com> on Tue Jun 18 23:31:41 2019 +0530. The commit for this change in Linux stable tree is 1056dda (patch).

PCI: tegra: Handle failure cases in tegra_pcie_power_on()

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>

There are 26 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/pci/controller/pci-tegra.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 464ba25..85c5e6a 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -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)

Leave a Reply

Your email address will not be published. Required fields are marked *