aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-29 15:46:33 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-29 15:46:33 -0500
commit26ab93438fbacc653c60ea4d148b6ca16919ab1b (patch)
tree7f95470de4a37770b80f510b5fb4e807b494c0ab
parent9ee71f513c698b05f67e74f7ce66ba4f23f9073f (diff)
parentea83f81b489be3be268ed7fabfe8dd94bdc45a29 (diff)
Merge branch 'pm-opp'
* pm-opp: PM / OPP: using kfree_rcu() to simplify the code PM / OPP: predictable fail results for opp_find* functions, v2 PM / OPP: Export symbols for module usage. PM / OPP: RCU reclaim
-rw-r--r--drivers/base/power/opp.c44
-rw-r--r--drivers/devfreq/devfreq.c4
2 files changed, 33 insertions, 15 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d9468642fc41..50b2831e027d 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
23#include <linux/rcupdate.h> 23#include <linux/rcupdate.h>
24#include <linux/opp.h> 24#include <linux/opp.h>
25#include <linux/of.h> 25#include <linux/of.h>
26#include <linux/export.h>
26 27
27/* 28/*
28 * Internal data structure organization with the OPP layer library is as 29 * Internal data structure organization with the OPP layer library is as
@@ -65,6 +66,7 @@ struct opp {
65 unsigned long u_volt; 66 unsigned long u_volt;
66 67
67 struct device_opp *dev_opp; 68 struct device_opp *dev_opp;
69 struct rcu_head head;
68}; 70};
69 71
70/** 72/**
@@ -160,6 +162,7 @@ unsigned long opp_get_voltage(struct opp *opp)
160 162
161 return v; 163 return v;
162} 164}
165EXPORT_SYMBOL(opp_get_voltage);
163 166
164/** 167/**
165 * opp_get_freq() - Gets the frequency corresponding to an available opp 168 * opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -189,6 +192,7 @@ unsigned long opp_get_freq(struct opp *opp)
189 192
190 return f; 193 return f;
191} 194}
195EXPORT_SYMBOL(opp_get_freq);
192 196
193/** 197/**
194 * opp_get_opp_count() - Get number of opps available in the opp list 198 * opp_get_opp_count() - Get number of opps available in the opp list
@@ -221,6 +225,7 @@ int opp_get_opp_count(struct device *dev)
221 225
222 return count; 226 return count;
223} 227}
228EXPORT_SYMBOL(opp_get_opp_count);
224 229
225/** 230/**
226 * opp_find_freq_exact() - search for an exact frequency 231 * opp_find_freq_exact() - search for an exact frequency
@@ -230,7 +235,10 @@ int opp_get_opp_count(struct device *dev)
230 * 235 *
231 * Searches for exact match in the opp list and returns pointer to the matching 236 * Searches for exact match in the opp list and returns pointer to the matching
232 * opp if found, else returns ERR_PTR in case of error and should be handled 237 * opp if found, else returns ERR_PTR in case of error and should be handled
233 * using IS_ERR. 238 * using IS_ERR. Error return values can be:
239 * EINVAL: for bad pointer
240 * ERANGE: no match found for search
241 * ENODEV: if device not found in list of registered devices
234 * 242 *
235 * Note: available is a modifier for the search. if available=true, then the 243 * Note: available is a modifier for the search. if available=true, then the
236 * match is for exact matching frequency and is available in the stored OPP 244 * match is for exact matching frequency and is available in the stored OPP
@@ -249,7 +257,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
249 bool available) 257 bool available)
250{ 258{
251 struct device_opp *dev_opp; 259 struct device_opp *dev_opp;
252 struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); 260 struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
253 261
254 dev_opp = find_device_opp(dev); 262 dev_opp = find_device_opp(dev);
255 if (IS_ERR(dev_opp)) { 263 if (IS_ERR(dev_opp)) {
@@ -268,6 +276,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
268 276
269 return opp; 277 return opp;
270} 278}
279EXPORT_SYMBOL(opp_find_freq_exact);
271 280
272/** 281/**
273 * opp_find_freq_ceil() - Search for an rounded ceil freq 282 * opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -278,7 +287,11 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
278 * for a device. 287 * for a device.
279 * 288 *
280 * Returns matching *opp and refreshes *freq accordingly, else returns 289 * Returns matching *opp and refreshes *freq accordingly, else returns
281 * ERR_PTR in case of error and should be handled using IS_ERR. 290 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
291 * values can be:
292 * EINVAL: for bad pointer
293 * ERANGE: no match found for search
294 * ENODEV: if device not found in list of registered devices
282 * 295 *
283 * Locking: This function must be called under rcu_read_lock(). opp is a rcu 296 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
284 * protected pointer. The reason for the same is that the opp pointer which is 297 * protected pointer. The reason for the same is that the opp pointer which is
@@ -289,7 +302,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
289struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) 302struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
290{ 303{
291 struct device_opp *dev_opp; 304 struct device_opp *dev_opp;
292 struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); 305 struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
293 306
294 if (!dev || !freq) { 307 if (!dev || !freq) {
295 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); 308 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -298,7 +311,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
298 311
299 dev_opp = find_device_opp(dev); 312 dev_opp = find_device_opp(dev);
300 if (IS_ERR(dev_opp)) 313 if (IS_ERR(dev_opp))
301 return opp; 314 return ERR_CAST(dev_opp);
302 315
303 list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { 316 list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
304 if (temp_opp->available && temp_opp->rate >= *freq) { 317 if (temp_opp->available && temp_opp->rate >= *freq) {
@@ -310,6 +323,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
310 323
311 return opp; 324 return opp;
312} 325}
326EXPORT_SYMBOL(opp_find_freq_ceil);
313 327
314/** 328/**
315 * opp_find_freq_floor() - Search for a rounded floor freq 329 * opp_find_freq_floor() - Search for a rounded floor freq
@@ -320,7 +334,11 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
320 * for a device. 334 * for a device.
321 * 335 *
322 * Returns matching *opp and refreshes *freq accordingly, else returns 336 * Returns matching *opp and refreshes *freq accordingly, else returns
323 * ERR_PTR in case of error and should be handled using IS_ERR. 337 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
338 * values can be:
339 * EINVAL: for bad pointer
340 * ERANGE: no match found for search
341 * ENODEV: if device not found in list of registered devices
324 * 342 *
325 * Locking: This function must be called under rcu_read_lock(). opp is a rcu 343 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
326 * protected pointer. The reason for the same is that the opp pointer which is 344 * protected pointer. The reason for the same is that the opp pointer which is
@@ -331,7 +349,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
331struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) 349struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
332{ 350{
333 struct device_opp *dev_opp; 351 struct device_opp *dev_opp;
334 struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); 352 struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
335 353
336 if (!dev || !freq) { 354 if (!dev || !freq) {
337 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); 355 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -340,7 +358,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
340 358
341 dev_opp = find_device_opp(dev); 359 dev_opp = find_device_opp(dev);
342 if (IS_ERR(dev_opp)) 360 if (IS_ERR(dev_opp))
343 return opp; 361 return ERR_CAST(dev_opp);
344 362
345 list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { 363 list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
346 if (temp_opp->available) { 364 if (temp_opp->available) {
@@ -356,6 +374,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
356 374
357 return opp; 375 return opp;
358} 376}
377EXPORT_SYMBOL(opp_find_freq_floor);
359 378
360/** 379/**
361 * opp_add() - Add an OPP table from a table definitions 380 * opp_add() - Add an OPP table from a table definitions
@@ -512,7 +531,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
512 531
513 list_replace_rcu(&opp->node, &new_opp->node); 532 list_replace_rcu(&opp->node, &new_opp->node);
514 mutex_unlock(&dev_opp_list_lock); 533 mutex_unlock(&dev_opp_list_lock);
515 synchronize_rcu(); 534 kfree_rcu(opp, head);
516 535
517 /* Notify the change of the OPP availability */ 536 /* Notify the change of the OPP availability */
518 if (availability_req) 537 if (availability_req)
@@ -522,13 +541,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
522 srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, 541 srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
523 new_opp); 542 new_opp);
524 543
525 /* clean up old opp */ 544 return 0;
526 new_opp = opp;
527 goto out;
528 545
529unlock: 546unlock:
530 mutex_unlock(&dev_opp_list_lock); 547 mutex_unlock(&dev_opp_list_lock);
531out:
532 kfree(new_opp); 548 kfree(new_opp);
533 return r; 549 return r;
534} 550}
@@ -552,6 +568,7 @@ int opp_enable(struct device *dev, unsigned long freq)
552{ 568{
553 return opp_set_availability(dev, freq, true); 569 return opp_set_availability(dev, freq, true);
554} 570}
571EXPORT_SYMBOL(opp_enable);
555 572
556/** 573/**
557 * opp_disable() - Disable a specific OPP 574 * opp_disable() - Disable a specific OPP
@@ -573,6 +590,7 @@ int opp_disable(struct device *dev, unsigned long freq)
573{ 590{
574 return opp_set_availability(dev, freq, false); 591 return opp_set_availability(dev, freq, false);
575} 592}
593EXPORT_SYMBOL(opp_disable);
576 594
577#ifdef CONFIG_CPU_FREQ 595#ifdef CONFIG_CPU_FREQ
578/** 596/**
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index b146d76f04cf..4fa1a22c55ea 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -656,14 +656,14 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
656 opp = opp_find_freq_floor(dev, freq); 656 opp = opp_find_freq_floor(dev, freq);
657 657
658 /* If not available, use the closest opp */ 658 /* If not available, use the closest opp */
659 if (opp == ERR_PTR(-ENODEV)) 659 if (opp == ERR_PTR(-ERANGE))
660 opp = opp_find_freq_ceil(dev, freq); 660 opp = opp_find_freq_ceil(dev, freq);
661 } else { 661 } else {
662 /* The freq is an lower bound. opp should be higher */ 662 /* The freq is an lower bound. opp should be higher */
663 opp = opp_find_freq_ceil(dev, freq); 663 opp = opp_find_freq_ceil(dev, freq);
664 664
665 /* If not available, use the closest opp */ 665 /* If not available, use the closest opp */
666 if (opp == ERR_PTR(-ENODEV)) 666 if (opp == ERR_PTR(-ERANGE))
667 opp = opp_find_freq_floor(dev, freq); 667 opp = opp_find_freq_floor(dev, freq);
668 } 668 }
669 669