diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2014-11-25 05:34:18 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-29 17:53:20 -0500 |
commit | 38393409da345cd48d94a0e74c7bbc3402742882 (patch) | |
tree | acaf242fb38292ed5c4c401beb375126c40bb033 | |
parent | a7470db6fec481b14afea117846fce383671ba59 (diff) |
PM / OPP mark OPPs as 'static' or 'dynamic'
Static OPPs are the ones created from Device Tree entries and dynamic are the
ones created at runtime by calling dev_pm_opp_add().
There is a need to distinguish them as we need to free static OPPs from cpufreq
drivers when they are removed.
So, add another field 'dynamic' in 'struct dev_pm_opp' to keep this information.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/base/power/opp.c | 59 |
1 files changed, 34 insertions, 25 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index a333e2ef5cb2..b249b0127eff 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
@@ -49,6 +49,7 @@ | |||
49 | * are protected by the dev_opp_list_lock for integrity. | 49 | * are protected by the dev_opp_list_lock for integrity. |
50 | * IMPORTANT: the opp nodes should be maintained in increasing | 50 | * IMPORTANT: the opp nodes should be maintained in increasing |
51 | * order. | 51 | * order. |
52 | * @dynamic: not-created from static DT entries. | ||
52 | * @available: true/false - marks if this OPP as available or not | 53 | * @available: true/false - marks if this OPP as available or not |
53 | * @rate: Frequency in hertz | 54 | * @rate: Frequency in hertz |
54 | * @u_volt: Nominal voltage in microvolts corresponding to this OPP | 55 | * @u_volt: Nominal voltage in microvolts corresponding to this OPP |
@@ -61,6 +62,7 @@ struct dev_pm_opp { | |||
61 | struct list_head node; | 62 | struct list_head node; |
62 | 63 | ||
63 | bool available; | 64 | bool available; |
65 | bool dynamic; | ||
64 | unsigned long rate; | 66 | unsigned long rate; |
65 | unsigned long u_volt; | 67 | unsigned long u_volt; |
66 | 68 | ||
@@ -378,30 +380,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, | |||
378 | } | 380 | } |
379 | EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); | 381 | EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); |
380 | 382 | ||
381 | /** | 383 | static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq, |
382 | * dev_pm_opp_add() - Add an OPP table from a table definitions | 384 | unsigned long u_volt, bool dynamic) |
383 | * @dev: device for which we do this operation | ||
384 | * @freq: Frequency in Hz for this OPP | ||
385 | * @u_volt: Voltage in uVolts for this OPP | ||
386 | * | ||
387 | * This function adds an opp definition to the opp list and returns status. | ||
388 | * The opp is made available by default and it can be controlled using | ||
389 | * dev_pm_opp_enable/disable functions. | ||
390 | * | ||
391 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
392 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
393 | * to keep the integrity of the internal data structures. Callers should ensure | ||
394 | * that this function is *NOT* called under RCU protection or in contexts where | ||
395 | * mutex cannot be locked. | ||
396 | * | ||
397 | * Return: | ||
398 | * 0: On success OR | ||
399 | * Duplicate OPPs (both freq and volt are same) and opp->available | ||
400 | * -EEXIST: Freq are same and volt are different OR | ||
401 | * Duplicate OPPs (both freq and volt are same) and !opp->available | ||
402 | * -ENOMEM: Memory allocation failure | ||
403 | */ | ||
404 | int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | ||
405 | { | 385 | { |
406 | struct device_opp *dev_opp = NULL; | 386 | struct device_opp *dev_opp = NULL; |
407 | struct dev_pm_opp *opp, *new_opp; | 387 | struct dev_pm_opp *opp, *new_opp; |
@@ -422,6 +402,7 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | |||
422 | new_opp->rate = freq; | 402 | new_opp->rate = freq; |
423 | new_opp->u_volt = u_volt; | 403 | new_opp->u_volt = u_volt; |
424 | new_opp->available = true; | 404 | new_opp->available = true; |
405 | new_opp->dynamic = dynamic; | ||
425 | 406 | ||
426 | /* Check for existing list for 'dev' */ | 407 | /* Check for existing list for 'dev' */ |
427 | dev_opp = find_device_opp(dev); | 408 | dev_opp = find_device_opp(dev); |
@@ -487,6 +468,34 @@ list_add: | |||
487 | srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp); | 468 | srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp); |
488 | return 0; | 469 | return 0; |
489 | } | 470 | } |
471 | |||
472 | /** | ||
473 | * dev_pm_opp_add() - Add an OPP table from a table definitions | ||
474 | * @dev: device for which we do this operation | ||
475 | * @freq: Frequency in Hz for this OPP | ||
476 | * @u_volt: Voltage in uVolts for this OPP | ||
477 | * | ||
478 | * This function adds an opp definition to the opp list and returns status. | ||
479 | * The opp is made available by default and it can be controlled using | ||
480 | * dev_pm_opp_enable/disable functions. | ||
481 | * | ||
482 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
483 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
484 | * to keep the integrity of the internal data structures. Callers should ensure | ||
485 | * that this function is *NOT* called under RCU protection or in contexts where | ||
486 | * mutex cannot be locked. | ||
487 | * | ||
488 | * Return: | ||
489 | * 0: On success OR | ||
490 | * Duplicate OPPs (both freq and volt are same) and opp->available | ||
491 | * -EEXIST: Freq are same and volt are different OR | ||
492 | * Duplicate OPPs (both freq and volt are same) and !opp->available | ||
493 | * -ENOMEM: Memory allocation failure | ||
494 | */ | ||
495 | int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | ||
496 | { | ||
497 | return dev_pm_opp_add_dynamic(dev, freq, u_volt, true); | ||
498 | } | ||
490 | EXPORT_SYMBOL_GPL(dev_pm_opp_add); | 499 | EXPORT_SYMBOL_GPL(dev_pm_opp_add); |
491 | 500 | ||
492 | /** | 501 | /** |
@@ -669,7 +678,7 @@ int of_init_opp_table(struct device *dev) | |||
669 | unsigned long freq = be32_to_cpup(val++) * 1000; | 678 | unsigned long freq = be32_to_cpup(val++) * 1000; |
670 | unsigned long volt = be32_to_cpup(val++); | 679 | unsigned long volt = be32_to_cpup(val++); |
671 | 680 | ||
672 | if (dev_pm_opp_add(dev, freq, volt)) | 681 | if (dev_pm_opp_add_dynamic(dev, freq, volt, false)) |
673 | dev_warn(dev, "%s: Failed to add OPP %ld\n", | 682 | dev_warn(dev, "%s: Failed to add OPP %ld\n", |
674 | __func__, freq); | 683 | __func__, freq); |
675 | nr -= 2; | 684 | nr -= 2; |