61531d38ad29106f65e63bf7037a5a5c3c846025
[openwrt/staging/ansuel.git] /
1 From fced531b7c7e18192e7982637c8e8f20c29aad64 Mon Sep 17 00:00:00 2001
2 From: Jia-Wei Chang <jia-wei.chang@mediatek.com>
3 Date: Fri, 24 Mar 2023 18:11:28 +0800
4 Subject: [PATCH 18/21] cpufreq: mediatek: fix KP caused by handler usage after
5 regulator_put/clk_put
6
7 Any kind of failure in mtk_cpu_dvfs_info_init() will lead to calling
8 regulator_put() or clk_put() and the KP will occur since the regulator/clk
9 handlers are used after released in mtk_cpu_dvfs_info_release().
10
11 To prevent the usage after regulator_put()/clk_put(), the regulator/clk
12 handlers are addressed in a way of "Free the Last Thing Style".
13
14 Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
15 Fixes: 4b9ceb757bbb ("cpufreq: mediatek: Enable clocks and regulators")
16 Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
17 Suggested-by: Dan Carpenter <error27@gmail.com>
18 Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
19 ---
20 drivers/cpufreq/mediatek-cpufreq.c | 62 +++++++++++++++---------------
21 1 file changed, 30 insertions(+), 32 deletions(-)
22
23 --- a/drivers/cpufreq/mediatek-cpufreq.c
24 +++ b/drivers/cpufreq/mediatek-cpufreq.c
25 @@ -420,7 +420,7 @@ static int mtk_cpu_dvfs_info_init(struct
26 ret = PTR_ERR(info->inter_clk);
27 dev_err_probe(cpu_dev, ret,
28 "cpu%d: failed to get intermediate clk\n", cpu);
29 - goto out_free_resources;
30 + goto out_free_mux_clock;
31 }
32
33 info->proc_reg = regulator_get_optional(cpu_dev, "proc");
34 @@ -428,13 +428,13 @@ static int mtk_cpu_dvfs_info_init(struct
35 ret = PTR_ERR(info->proc_reg);
36 dev_err_probe(cpu_dev, ret,
37 "cpu%d: failed to get proc regulator\n", cpu);
38 - goto out_free_resources;
39 + goto out_free_inter_clock;
40 }
41
42 ret = regulator_enable(info->proc_reg);
43 if (ret) {
44 dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu);
45 - goto out_free_resources;
46 + goto out_free_proc_reg;
47 }
48
49 /* Both presence and absence of sram regulator are valid cases. */
50 @@ -442,14 +442,14 @@ static int mtk_cpu_dvfs_info_init(struct
51 if (IS_ERR(info->sram_reg)) {
52 ret = PTR_ERR(info->sram_reg);
53 if (ret == -EPROBE_DEFER)
54 - goto out_free_resources;
55 + goto out_disable_proc_reg;
56
57 info->sram_reg = NULL;
58 } else {
59 ret = regulator_enable(info->sram_reg);
60 if (ret) {
61 dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
62 - goto out_free_resources;
63 + goto out_free_sram_reg;
64 }
65 }
66
67 @@ -458,13 +458,13 @@ static int mtk_cpu_dvfs_info_init(struct
68 if (ret) {
69 dev_err(cpu_dev,
70 "cpu%d: failed to get OPP-sharing information\n", cpu);
71 - goto out_free_resources;
72 + goto out_disable_sram_reg;
73 }
74
75 ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
76 if (ret) {
77 dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu);
78 - goto out_free_resources;
79 + goto out_disable_sram_reg;
80 }
81
82 ret = clk_prepare_enable(info->cpu_clk);
83 @@ -533,43 +533,41 @@ out_disable_mux_clock:
84 out_free_opp_table:
85 dev_pm_opp_of_cpumask_remove_table(&info->cpus);
86
87 -out_free_resources:
88 - if (regulator_is_enabled(info->proc_reg))
89 - regulator_disable(info->proc_reg);
90 - if (info->sram_reg && regulator_is_enabled(info->sram_reg))
91 +out_disable_sram_reg:
92 + if (info->sram_reg)
93 regulator_disable(info->sram_reg);
94
95 - if (!IS_ERR(info->proc_reg))
96 - regulator_put(info->proc_reg);
97 - if (!IS_ERR(info->sram_reg))
98 +out_free_sram_reg:
99 + if (info->sram_reg)
100 regulator_put(info->sram_reg);
101 - if (!IS_ERR(info->cpu_clk))
102 - clk_put(info->cpu_clk);
103 - if (!IS_ERR(info->inter_clk))
104 - clk_put(info->inter_clk);
105 +
106 +out_disable_proc_reg:
107 + regulator_disable(info->proc_reg);
108 +
109 +out_free_proc_reg:
110 + regulator_put(info->proc_reg);
111 +
112 +out_free_inter_clock:
113 + clk_put(info->inter_clk);
114 +
115 +out_free_mux_clock:
116 + clk_put(info->cpu_clk);
117
118 return ret;
119 }
120
121 static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
122 {
123 - if (!IS_ERR(info->proc_reg)) {
124 - regulator_disable(info->proc_reg);
125 - regulator_put(info->proc_reg);
126 - }
127 - if (!IS_ERR(info->sram_reg)) {
128 + regulator_disable(info->proc_reg);
129 + regulator_put(info->proc_reg);
130 + if (info->sram_reg) {
131 regulator_disable(info->sram_reg);
132 regulator_put(info->sram_reg);
133 }
134 - if (!IS_ERR(info->cpu_clk)) {
135 - clk_disable_unprepare(info->cpu_clk);
136 - clk_put(info->cpu_clk);
137 - }
138 - if (!IS_ERR(info->inter_clk)) {
139 - clk_disable_unprepare(info->inter_clk);
140 - clk_put(info->inter_clk);
141 - }
142 -
143 + clk_disable_unprepare(info->cpu_clk);
144 + clk_put(info->cpu_clk);
145 + clk_disable_unprepare(info->inter_clk);
146 + clk_put(info->inter_clk);
147 dev_pm_opp_of_cpumask_remove_table(&info->cpus);
148 dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb);
149 }