aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/cpufreq/cpufreq.c111
-rw-r--r--include/linux/cpufreq.h8
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 */
46static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 46static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
47 47
48/* Flag to suspend/resume CPUFreq governors */
49static bool cpufreq_suspended;
50
48static inline bool has_target(void) 51static 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 */
1573static int cpufreq_bp_suspend(void) 1578void 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 */
1611static void cpufreq_bp_resume(void) 1609void 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
1636fail: 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
1640static 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
300void cpufreq_suspend(void);
301void cpufreq_resume(void);
302#else
303static inline void cpufreq_suspend(void) {}
304static inline void cpufreq_resume(void) {}
305#endif
306
299/********************************************************************* 307/*********************************************************************
300 * CPUFREQ NOTIFIER INTERFACE * 308 * CPUFREQ NOTIFIER INTERFACE *
301 *********************************************************************/ 309 *********************************************************************/