summaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/exynos-bus.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2016-12-01 05:25:40 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-12-07 19:46:06 -0500
commitc8ce82b9b9c40d66709cce588f6281dd47cc3922 (patch)
tree8734984b6eb9c2043e519d95e4e6906b96943953 /drivers/devfreq/exynos-bus.c
parentc261e4c7153f307cd5f78ac6492da21ce7004310 (diff)
devfreq: exynos: Don't use OPP structures outside of RCU locks
The OPP structures are abused to the best here, without understanding how the OPP core and RCU locks work. In short, the OPP pointer saved 'struct exynos_bus' can become invalid under your nose, as the OPP core may free it. Fix various abuses around OPP structures and calls. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Acked-by: Chanwoo Choi <cw00.choi@samsung.com> Tested-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/devfreq/exynos-bus.c')
-rw-r--r--drivers/devfreq/exynos-bus.c29
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c
index 29866f7e6d7e..a8ed7792ece2 100644
--- a/drivers/devfreq/exynos-bus.c
+++ b/drivers/devfreq/exynos-bus.c
@@ -35,7 +35,7 @@ struct exynos_bus {
35 unsigned int edev_count; 35 unsigned int edev_count;
36 struct mutex lock; 36 struct mutex lock;
37 37
38 struct dev_pm_opp *curr_opp; 38 unsigned long curr_freq;
39 39
40 struct regulator *regulator; 40 struct regulator *regulator;
41 struct clk *clk; 41 struct clk *clk;
@@ -99,7 +99,7 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
99{ 99{
100 struct exynos_bus *bus = dev_get_drvdata(dev); 100 struct exynos_bus *bus = dev_get_drvdata(dev);
101 struct dev_pm_opp *new_opp; 101 struct dev_pm_opp *new_opp;
102 unsigned long old_freq, new_freq, old_volt, new_volt, tol; 102 unsigned long old_freq, new_freq, new_volt, tol;
103 int ret = 0; 103 int ret = 0;
104 104
105 /* Get new opp-bus instance according to new bus clock */ 105 /* Get new opp-bus instance according to new bus clock */
@@ -113,8 +113,7 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
113 113
114 new_freq = dev_pm_opp_get_freq(new_opp); 114 new_freq = dev_pm_opp_get_freq(new_opp);
115 new_volt = dev_pm_opp_get_voltage(new_opp); 115 new_volt = dev_pm_opp_get_voltage(new_opp);
116 old_freq = dev_pm_opp_get_freq(bus->curr_opp); 116 old_freq = bus->curr_freq;
117 old_volt = dev_pm_opp_get_voltage(bus->curr_opp);
118 rcu_read_unlock(); 117 rcu_read_unlock();
119 118
120 if (old_freq == new_freq) 119 if (old_freq == new_freq)
@@ -146,7 +145,7 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
146 goto out; 145 goto out;
147 } 146 }
148 } 147 }
149 bus->curr_opp = new_opp; 148 bus->curr_freq = new_freq;
150 149
151 dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", 150 dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
152 old_freq/1000, new_freq/1000); 151 old_freq/1000, new_freq/1000);
@@ -163,9 +162,7 @@ static int exynos_bus_get_dev_status(struct device *dev,
163 struct devfreq_event_data edata; 162 struct devfreq_event_data edata;
164 int ret; 163 int ret;
165 164
166 rcu_read_lock(); 165 stat->current_frequency = bus->curr_freq;
167 stat->current_frequency = dev_pm_opp_get_freq(bus->curr_opp);
168 rcu_read_unlock();
169 166
170 ret = exynos_bus_get_event(bus, &edata); 167 ret = exynos_bus_get_event(bus, &edata);
171 if (ret < 0) { 168 if (ret < 0) {
@@ -226,7 +223,7 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
226 } 223 }
227 224
228 new_freq = dev_pm_opp_get_freq(new_opp); 225 new_freq = dev_pm_opp_get_freq(new_opp);
229 old_freq = dev_pm_opp_get_freq(bus->curr_opp); 226 old_freq = bus->curr_freq;
230 rcu_read_unlock(); 227 rcu_read_unlock();
231 228
232 if (old_freq == new_freq) 229 if (old_freq == new_freq)
@@ -242,7 +239,7 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
242 } 239 }
243 240
244 *freq = new_freq; 241 *freq = new_freq;
245 bus->curr_opp = new_opp; 242 bus->curr_freq = new_freq;
246 243
247 dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", 244 dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
248 old_freq/1000, new_freq/1000); 245 old_freq/1000, new_freq/1000);
@@ -335,6 +332,7 @@ static int exynos_bus_parse_of(struct device_node *np,
335 struct exynos_bus *bus) 332 struct exynos_bus *bus)
336{ 333{
337 struct device *dev = bus->dev; 334 struct device *dev = bus->dev;
335 struct dev_pm_opp *opp;
338 unsigned long rate; 336 unsigned long rate;
339 int ret; 337 int ret;
340 338
@@ -352,22 +350,23 @@ static int exynos_bus_parse_of(struct device_node *np,
352 } 350 }
353 351
354 /* Get the freq and voltage from OPP table to scale the bus freq */ 352 /* Get the freq and voltage from OPP table to scale the bus freq */
355 rcu_read_lock();
356 ret = dev_pm_opp_of_add_table(dev); 353 ret = dev_pm_opp_of_add_table(dev);
357 if (ret < 0) { 354 if (ret < 0) {
358 dev_err(dev, "failed to get OPP table\n"); 355 dev_err(dev, "failed to get OPP table\n");
359 rcu_read_unlock();
360 goto err_clk; 356 goto err_clk;
361 } 357 }
362 358
363 rate = clk_get_rate(bus->clk); 359 rate = clk_get_rate(bus->clk);
364 bus->curr_opp = devfreq_recommended_opp(dev, &rate, 0); 360
365 if (IS_ERR(bus->curr_opp)) { 361 rcu_read_lock();
362 opp = devfreq_recommended_opp(dev, &rate, 0);
363 if (IS_ERR(opp)) {
366 dev_err(dev, "failed to find dev_pm_opp\n"); 364 dev_err(dev, "failed to find dev_pm_opp\n");
367 rcu_read_unlock(); 365 rcu_read_unlock();
368 ret = PTR_ERR(bus->curr_opp); 366 ret = PTR_ERR(opp);
369 goto err_opp; 367 goto err_opp;
370 } 368 }
369 bus->curr_freq = dev_pm_opp_get_freq(opp);
371 rcu_read_unlock(); 370 rcu_read_unlock();
372 371
373 return 0; 372 return 0;