This is a note to let you know that I've just added the patch titled cpufreq: mediatek: fix KP caused by handler usage after regulator_put/clk_put to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: cpufreq-mediatek-fix-kp-caused-by-handler-usage-afte.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit 0786fea46a385d1b050cffe32ef365d730556275 Author: Jia-Wei Chang <jia-wei.chang@xxxxxxxxxxxx> Date: Fri Mar 24 18:11:28 2023 +0800 cpufreq: mediatek: fix KP caused by handler usage after regulator_put/clk_put [ Upstream commit d51e106240bc755cbe59634b70d567c192b045b2 ] Any kind of failure in mtk_cpu_dvfs_info_init() will lead to calling regulator_put() or clk_put() and the KP will occur since the regulator/clk handlers are used after released in mtk_cpu_dvfs_info_release(). To prevent the usage after regulator_put()/clk_put(), the regulator/clk handlers are addressed in a way of "Free the Last Thing Style". Signed-off-by: Jia-Wei Chang <jia-wei.chang@xxxxxxxxxxxx> Fixes: 4b9ceb757bbb ("cpufreq: mediatek: Enable clocks and regulators") Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@xxxxxxxxxxxxx> Suggested-by: Dan Carpenter <error27@xxxxxxxxx> Signed-off-by: Viresh Kumar <viresh.kumar@xxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 01d949707c373..6dc225546a8d6 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -420,7 +420,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) ret = PTR_ERR(info->inter_clk); dev_err_probe(cpu_dev, ret, "cpu%d: failed to get intermediate clk\n", cpu); - goto out_free_resources; + goto out_free_mux_clock; } info->proc_reg = regulator_get_optional(cpu_dev, "proc"); @@ -428,13 +428,13 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) ret = PTR_ERR(info->proc_reg); dev_err_probe(cpu_dev, ret, "cpu%d: failed to get proc regulator\n", cpu); - goto out_free_resources; + goto out_free_inter_clock; } ret = regulator_enable(info->proc_reg); if (ret) { dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu); - goto out_free_resources; + goto out_free_proc_reg; } /* Both presence and absence of sram regulator are valid cases. */ @@ -442,14 +442,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) if (IS_ERR(info->sram_reg)) { ret = PTR_ERR(info->sram_reg); if (ret == -EPROBE_DEFER) - goto out_free_resources; + goto out_disable_proc_reg; info->sram_reg = NULL; } else { ret = regulator_enable(info->sram_reg); if (ret) { dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu); - goto out_free_resources; + goto out_free_sram_reg; } } @@ -458,13 +458,13 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) if (ret) { dev_err(cpu_dev, "cpu%d: failed to get OPP-sharing information\n", cpu); - goto out_free_resources; + goto out_disable_sram_reg; } ret = dev_pm_opp_of_cpumask_add_table(&info->cpus); if (ret) { dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu); - goto out_free_resources; + goto out_disable_sram_reg; } ret = clk_prepare_enable(info->cpu_clk); @@ -533,43 +533,41 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) out_free_opp_table: dev_pm_opp_of_cpumask_remove_table(&info->cpus); -out_free_resources: - if (regulator_is_enabled(info->proc_reg)) - regulator_disable(info->proc_reg); - if (info->sram_reg && regulator_is_enabled(info->sram_reg)) +out_disable_sram_reg: + if (info->sram_reg) regulator_disable(info->sram_reg); - if (!IS_ERR(info->proc_reg)) - regulator_put(info->proc_reg); - if (!IS_ERR(info->sram_reg)) +out_free_sram_reg: + if (info->sram_reg) regulator_put(info->sram_reg); - if (!IS_ERR(info->cpu_clk)) - clk_put(info->cpu_clk); - if (!IS_ERR(info->inter_clk)) - clk_put(info->inter_clk); + +out_disable_proc_reg: + regulator_disable(info->proc_reg); + +out_free_proc_reg: + regulator_put(info->proc_reg); + +out_free_inter_clock: + clk_put(info->inter_clk); + +out_free_mux_clock: + clk_put(info->cpu_clk); return ret; } static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) { - if (!IS_ERR(info->proc_reg)) { - regulator_disable(info->proc_reg); - regulator_put(info->proc_reg); - } - if (!IS_ERR(info->sram_reg)) { + regulator_disable(info->proc_reg); + regulator_put(info->proc_reg); + if (info->sram_reg) { regulator_disable(info->sram_reg); regulator_put(info->sram_reg); } - if (!IS_ERR(info->cpu_clk)) { - clk_disable_unprepare(info->cpu_clk); - clk_put(info->cpu_clk); - } - if (!IS_ERR(info->inter_clk)) { - clk_disable_unprepare(info->inter_clk); - clk_put(info->inter_clk); - } - + clk_disable_unprepare(info->cpu_clk); + clk_put(info->cpu_clk); + clk_disable_unprepare(info->inter_clk); + clk_put(info->inter_clk); dev_pm_opp_of_cpumask_remove_table(&info->cpus); dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb); }