diff options
-rw-r--r-- | drivers/base/power/main.c | 3 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 43 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 8 |
3 files changed, 54 insertions, 0 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9f098a82cf04..10c3510d72a9 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/async.h> | 29 | #include <linux/async.h> |
30 | #include <linux/suspend.h> | 30 | #include <linux/suspend.h> |
31 | #include <trace/events/power.h> | 31 | #include <trace/events/power.h> |
32 | #include <linux/cpufreq.h> | ||
32 | #include <linux/cpuidle.h> | 33 | #include <linux/cpuidle.h> |
33 | #include "../base.h" | 34 | #include "../base.h" |
34 | #include "power.h" | 35 | #include "power.h" |
@@ -473,6 +474,7 @@ static void dpm_resume_noirq(pm_message_t state) | |||
473 | dpm_show_time(starttime, state, "noirq"); | 474 | dpm_show_time(starttime, state, "noirq"); |
474 | resume_device_irqs(); | 475 | resume_device_irqs(); |
475 | cpuidle_resume(); | 476 | cpuidle_resume(); |
477 | cpufreq_resume(); | ||
476 | } | 478 | } |
477 | 479 | ||
478 | /** | 480 | /** |
@@ -885,6 +887,7 @@ static int dpm_suspend_noirq(pm_message_t state) | |||
885 | ktime_t starttime = ktime_get(); | 887 | ktime_t starttime = ktime_get(); |
886 | int error = 0; | 888 | int error = 0; |
887 | 889 | ||
890 | cpufreq_suspend(); | ||
888 | cpuidle_pause(); | 891 | cpuidle_pause(); |
889 | suspend_device_irqs(); | 892 | suspend_device_irqs(); |
890 | mutex_lock(&dpm_list_mtx); | 893 | mutex_lock(&dpm_list_mtx); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 02d534da22dd..606224a8abc2 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/suspend.h> | ||
29 | #include <linux/syscore_ops.h> | 30 | #include <linux/syscore_ops.h> |
30 | #include <linux/tick.h> | 31 | #include <linux/tick.h> |
31 | #include <trace/events/power.h> | 32 | #include <trace/events/power.h> |
@@ -47,6 +48,9 @@ static LIST_HEAD(cpufreq_policy_list); | |||
47 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); | 48 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); |
48 | #endif | 49 | #endif |
49 | 50 | ||
51 | /* Flag to suspend/resume CPUFreq governors */ | ||
52 | static bool cpufreq_suspended; | ||
53 | |||
50 | static inline bool has_target(void) | 54 | static inline bool has_target(void) |
51 | { | 55 | { |
52 | return cpufreq_driver->target_index || cpufreq_driver->target; | 56 | return cpufreq_driver->target_index || cpufreq_driver->target; |
@@ -1462,6 +1466,41 @@ static struct subsys_interface cpufreq_interface = { | |||
1462 | .remove_dev = cpufreq_remove_dev, | 1466 | .remove_dev = cpufreq_remove_dev, |
1463 | }; | 1467 | }; |
1464 | 1468 | ||
1469 | void cpufreq_suspend(void) | ||
1470 | { | ||
1471 | struct cpufreq_policy *policy; | ||
1472 | |||
1473 | if (!has_target()) | ||
1474 | return; | ||
1475 | |||
1476 | pr_debug("%s: Suspending Governors\n", __func__); | ||
1477 | |||
1478 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) | ||
1479 | if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) | ||
1480 | pr_err("%s: Failed to stop governor for policy: %p\n", | ||
1481 | __func__, policy); | ||
1482 | |||
1483 | cpufreq_suspended = true; | ||
1484 | } | ||
1485 | |||
1486 | void cpufreq_resume(void) | ||
1487 | { | ||
1488 | struct cpufreq_policy *policy; | ||
1489 | |||
1490 | if (!has_target()) | ||
1491 | return; | ||
1492 | |||
1493 | pr_debug("%s: Resuming Governors\n", __func__); | ||
1494 | |||
1495 | cpufreq_suspended = false; | ||
1496 | |||
1497 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) | ||
1498 | if (__cpufreq_governor(policy, CPUFREQ_GOV_START) | ||
1499 | || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) | ||
1500 | pr_err("%s: Failed to start governor for policy: %p\n", | ||
1501 | __func__, policy); | ||
1502 | } | ||
1503 | |||
1465 | /** | 1504 | /** |
1466 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. | 1505 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. |
1467 | * | 1506 | * |
@@ -1764,6 +1803,10 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, | |||
1764 | struct cpufreq_governor *gov = NULL; | 1803 | struct cpufreq_governor *gov = NULL; |
1765 | #endif | 1804 | #endif |
1766 | 1805 | ||
1806 | /* Don't start any governor operations if we are entering suspend */ | ||
1807 | if (cpufreq_suspended) | ||
1808 | return 0; | ||
1809 | |||
1767 | if (policy->governor->max_transition_latency && | 1810 | if (policy->governor->max_transition_latency && |
1768 | policy->cpuinfo.transition_latency > | 1811 | policy->cpuinfo.transition_latency > |
1769 | policy->governor->max_transition_latency) { | 1812 | policy->governor->max_transition_latency) { |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 5bd6ab9b0c27..91716658e9a1 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -272,6 +272,14 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy) | |||
272 | policy->cpuinfo.max_freq); | 272 | policy->cpuinfo.max_freq); |
273 | } | 273 | } |
274 | 274 | ||
275 | #ifdef CONFIG_CPU_FREQ | ||
276 | void cpufreq_suspend(void); | ||
277 | void cpufreq_resume(void); | ||
278 | #else | ||
279 | static inline void cpufreq_suspend(void) {} | ||
280 | static inline void cpufreq_resume(void) {} | ||
281 | #endif | ||
282 | |||
275 | /********************************************************************* | 283 | /********************************************************************* |
276 | * CPUFREQ NOTIFIER INTERFACE * | 284 | * CPUFREQ NOTIFIER INTERFACE * |
277 | *********************************************************************/ | 285 | *********************************************************************/ |