diff options
-rw-r--r-- | drivers/base/power/main.c | 5 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 111 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 8 |
3 files changed, 69 insertions, 55 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca3d65a..c9fbb9d5484d 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 <linux/timer.h> | 34 | #include <linux/timer.h> |
34 | 35 | ||
@@ -789,6 +790,8 @@ void dpm_resume(pm_message_t state) | |||
789 | mutex_unlock(&dpm_list_mtx); | 790 | mutex_unlock(&dpm_list_mtx); |
790 | async_synchronize_full(); | 791 | async_synchronize_full(); |
791 | dpm_show_time(starttime, state, NULL); | 792 | dpm_show_time(starttime, state, NULL); |
793 | |||
794 | cpufreq_resume(); | ||
792 | } | 795 | } |
793 | 796 | ||
794 | /** | 797 | /** |
@@ -1259,6 +1262,8 @@ int dpm_suspend(pm_message_t state) | |||
1259 | 1262 | ||
1260 | might_sleep(); | 1263 | might_sleep(); |
1261 | 1264 | ||
1265 | cpufreq_suspend(); | ||
1266 | |||
1262 | mutex_lock(&dpm_list_mtx); | 1267 | mutex_lock(&dpm_list_mtx); |
1263 | pm_transition = state; | 1268 | pm_transition = state; |
1264 | async_error = 0; | 1269 | async_error = 0; |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2de2f1ddd95f..289a407a9207 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -26,7 +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/syscore_ops.h> | 29 | #include <linux/suspend.h> |
30 | #include <linux/tick.h> | 30 | #include <linux/tick.h> |
31 | #include <trace/events/power.h> | 31 | #include <trace/events/power.h> |
32 | 32 | ||
@@ -45,6 +45,9 @@ static LIST_HEAD(cpufreq_policy_list); | |||
45 | /* This one keeps track of the previously set governor of a removed CPU */ | 45 | /* This one keeps track of the previously set governor of a removed CPU */ |
46 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); | 46 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); |
47 | 47 | ||
48 | /* Flag to suspend/resume CPUFreq governors */ | ||
49 | static bool cpufreq_suspended; | ||
50 | |||
48 | static inline bool has_target(void) | 51 | static inline bool has_target(void) |
49 | { | 52 | { |
50 | return cpufreq_driver->target_index || cpufreq_driver->target; | 53 | return cpufreq_driver->target_index || cpufreq_driver->target; |
@@ -1565,82 +1568,77 @@ static struct subsys_interface cpufreq_interface = { | |||
1565 | }; | 1568 | }; |
1566 | 1569 | ||
1567 | /** | 1570 | /** |
1568 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. | 1571 | * cpufreq_suspend() - Suspend CPUFreq governors |
1569 | * | 1572 | * |
1570 | * This function is only executed for the boot processor. The other CPUs | 1573 | * Called during system wide Suspend/Hibernate cycles for suspending governors |
1571 | * have been put offline by means of CPU hotplug. | 1574 | * as some platforms can't change frequency after this point in suspend cycle. |
1575 | * Because some of the devices (like: i2c, regulators, etc) they use for | ||
1576 | * changing frequency are suspended quickly after this point. | ||
1572 | */ | 1577 | */ |
1573 | static int cpufreq_bp_suspend(void) | 1578 | void cpufreq_suspend(void) |
1574 | { | 1579 | { |
1575 | int ret = 0; | ||
1576 | |||
1577 | int cpu = smp_processor_id(); | ||
1578 | struct cpufreq_policy *policy; | 1580 | struct cpufreq_policy *policy; |
1579 | 1581 | ||
1580 | pr_debug("suspending cpu %u\n", cpu); | 1582 | if (!cpufreq_driver) |
1583 | return; | ||
1581 | 1584 | ||
1582 | /* If there's no policy for the boot CPU, we have nothing to do. */ | 1585 | if (!has_target()) |
1583 | policy = cpufreq_cpu_get(cpu); | 1586 | return; |
1584 | if (!policy) | ||
1585 | return 0; | ||
1586 | 1587 | ||
1587 | if (cpufreq_driver->suspend) { | 1588 | pr_debug("%s: Suspending Governors\n", __func__); |
1588 | ret = cpufreq_driver->suspend(policy); | 1589 | |
1589 | if (ret) | 1590 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { |
1590 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " | 1591 | if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) |
1591 | "step on CPU %u\n", policy->cpu); | 1592 | pr_err("%s: Failed to stop governor for policy: %p\n", |
1593 | __func__, policy); | ||
1594 | else if (cpufreq_driver->suspend | ||
1595 | && cpufreq_driver->suspend(policy)) | ||
1596 | pr_err("%s: Failed to suspend driver: %p\n", __func__, | ||
1597 | policy); | ||
1592 | } | 1598 | } |
1593 | 1599 | ||
1594 | cpufreq_cpu_put(policy); | 1600 | cpufreq_suspended = true; |
1595 | return ret; | ||
1596 | } | 1601 | } |
1597 | 1602 | ||
1598 | /** | 1603 | /** |
1599 | * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. | 1604 | * cpufreq_resume() - Resume CPUFreq governors |
1600 | * | 1605 | * |
1601 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) | 1606 | * Called during system wide Suspend/Hibernate cycle for resuming governors that |
1602 | * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are | 1607 | * are suspended with cpufreq_suspend(). |
1603 | * restored. It will verify that the current freq is in sync with | ||
1604 | * what we believe it to be. This is a bit later than when it | ||
1605 | * should be, but nonethteless it's better than calling | ||
1606 | * cpufreq_driver->get() here which might re-enable interrupts... | ||
1607 | * | ||
1608 | * This function is only executed for the boot CPU. The other CPUs have not | ||
1609 | * been turned on yet. | ||
1610 | */ | 1608 | */ |
1611 | static void cpufreq_bp_resume(void) | 1609 | void cpufreq_resume(void) |
1612 | { | 1610 | { |
1613 | int ret = 0; | ||
1614 | |||
1615 | int cpu = smp_processor_id(); | ||
1616 | struct cpufreq_policy *policy; | 1611 | struct cpufreq_policy *policy; |
1617 | 1612 | ||
1618 | pr_debug("resuming cpu %u\n", cpu); | 1613 | if (!cpufreq_driver) |
1614 | return; | ||
1619 | 1615 | ||
1620 | /* If there's no policy for the boot CPU, we have nothing to do. */ | 1616 | if (!has_target()) |
1621 | policy = cpufreq_cpu_get(cpu); | ||
1622 | if (!policy) | ||
1623 | return; | 1617 | return; |
1624 | 1618 | ||
1625 | if (cpufreq_driver->resume) { | 1619 | pr_debug("%s: Resuming Governors\n", __func__); |
1626 | ret = cpufreq_driver->resume(policy); | ||
1627 | if (ret) { | ||
1628 | printk(KERN_ERR "cpufreq: resume failed in ->resume " | ||
1629 | "step on CPU %u\n", policy->cpu); | ||
1630 | goto fail; | ||
1631 | } | ||
1632 | } | ||
1633 | 1620 | ||
1634 | schedule_work(&policy->update); | 1621 | cpufreq_suspended = false; |
1635 | 1622 | ||
1636 | fail: | 1623 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { |
1637 | cpufreq_cpu_put(policy); | 1624 | if (__cpufreq_governor(policy, CPUFREQ_GOV_START) |
1638 | } | 1625 | || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) |
1626 | pr_err("%s: Failed to start governor for policy: %p\n", | ||
1627 | __func__, policy); | ||
1628 | else if (cpufreq_driver->resume | ||
1629 | && cpufreq_driver->resume(policy)) | ||
1630 | pr_err("%s: Failed to resume driver: %p\n", __func__, | ||
1631 | policy); | ||
1639 | 1632 | ||
1640 | static struct syscore_ops cpufreq_syscore_ops = { | 1633 | /* |
1641 | .suspend = cpufreq_bp_suspend, | 1634 | * schedule call cpufreq_update_policy() for boot CPU, i.e. last |
1642 | .resume = cpufreq_bp_resume, | 1635 | * policy in list. It will verify that the current freq is in |
1643 | }; | 1636 | * sync with what we believe it to be. |
1637 | */ | ||
1638 | if (list_is_last(&policy->policy_list, &cpufreq_policy_list)) | ||
1639 | schedule_work(&policy->update); | ||
1640 | } | ||
1641 | } | ||
1644 | 1642 | ||
1645 | /** | 1643 | /** |
1646 | * cpufreq_get_current_driver - return current driver's name | 1644 | * cpufreq_get_current_driver - return current driver's name |
@@ -1857,6 +1855,10 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, | |||
1857 | struct cpufreq_governor *gov = NULL; | 1855 | struct cpufreq_governor *gov = NULL; |
1858 | #endif | 1856 | #endif |
1859 | 1857 | ||
1858 | /* Don't start any governor operations if we are entering suspend */ | ||
1859 | if (cpufreq_suspended) | ||
1860 | return 0; | ||
1861 | |||
1860 | if (policy->governor->max_transition_latency && | 1862 | if (policy->governor->max_transition_latency && |
1861 | policy->cpuinfo.transition_latency > | 1863 | policy->cpuinfo.transition_latency > |
1862 | policy->governor->max_transition_latency) { | 1864 | policy->governor->max_transition_latency) { |
@@ -2392,7 +2394,6 @@ static int __init cpufreq_core_init(void) | |||
2392 | 2394 | ||
2393 | cpufreq_global_kobject = kobject_create(); | 2395 | cpufreq_global_kobject = kobject_create(); |
2394 | BUG_ON(!cpufreq_global_kobject); | 2396 | BUG_ON(!cpufreq_global_kobject); |
2395 | register_syscore_ops(&cpufreq_syscore_ops); | ||
2396 | 2397 | ||
2397 | return 0; | 2398 | return 0; |
2398 | } | 2399 | } |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 4d89e0e6f9cc..94ed907c6999 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -296,6 +296,14 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy) | |||
296 | policy->cpuinfo.max_freq); | 296 | policy->cpuinfo.max_freq); |
297 | } | 297 | } |
298 | 298 | ||
299 | #ifdef CONFIG_CPU_FREQ | ||
300 | void cpufreq_suspend(void); | ||
301 | void cpufreq_resume(void); | ||
302 | #else | ||
303 | static inline void cpufreq_suspend(void) {} | ||
304 | static inline void cpufreq_resume(void) {} | ||
305 | #endif | ||
306 | |||
299 | /********************************************************************* | 307 | /********************************************************************* |
300 | * CPUFREQ NOTIFIER INTERFACE * | 308 | * CPUFREQ NOTIFIER INTERFACE * |
301 | *********************************************************************/ | 309 | *********************************************************************/ |