diff options
author | Mark Brown <broonie@kernel.org> | 2015-03-09 12:27:35 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-03-09 12:27:35 +0000 |
commit | 165cb34cde45b13a5caca5dac528504a1cf5621f (patch) | |
tree | 2dd6133e8da76a116a4b50ed2d694b3a32545555 | |
parent | 20fe0191dfddcb6fb8ade72e7f334d42fdb078cc (diff) | |
parent | c810fcb930d9c705774427bb6eb551b2e1108adb (diff) |
Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-rtlsk-v3.10-15.03-rt
-rw-r--r-- | drivers/base/power/main.c | 6 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 114 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 12 |
3 files changed, 56 insertions, 76 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 220ec3a3ca75..5a9b6569dd74 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -28,8 +28,6 @@ #include <linux/sched.h> #include <linux/async.h> #include <linux/suspend.h> -#include <trace/events/power.h> -#include <linux/cpufreq.h> #include <linux/cpuidle.h> #include "../base.h" #include "power.h" @@ -715,8 +713,6 @@ void dpm_resume(pm_message_t state) mutex_unlock(&dpm_list_mtx); async_synchronize_full(); dpm_show_time(starttime, state, NULL); - - cpufreq_resume(); } /** @@ -1181,8 +1177,6 @@ int dpm_suspend(pm_message_t state) might_sleep(); - cpufreq_suspend(); - mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index df9a2427c233..66f6cf5064ec 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -31,8 +31,6 @@ #include <linux/completion.h> #include <linux/mutex.h> #include <linux/syscore_ops.h> -#include <linux/suspend.h> -#include <linux/tick.h> #include <trace/events/power.h> @@ -50,14 +48,6 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); static DEFINE_RWLOCK(cpufreq_driver_lock); static DEFINE_MUTEX(cpufreq_governor_lock); -/* Flag to suspend/resume CPUFreq governors */ -static bool cpufreq_suspended; - -static inline bool has_target(void) -{ - return cpufreq_driver->target; -} - /* * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure * all cpufreq/hotplug/workqueue/etc related lock issues. @@ -1285,72 +1275,83 @@ static struct subsys_interface cpufreq_interface = { /** - * cpufreq_suspend() - Suspend CPUFreq governors + * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. * - * Called during system wide Suspend/Hibernate cycles for suspending governors - * as some platforms can't change frequency after this point in suspend cycle. - * Because some of the devices (like: i2c, regulators, etc) they use for - * changing frequency are suspended quickly after this point. + * This function is only executed for the boot processor. The other CPUs + * have been put offline by means of CPU hotplug. */ -void cpufreq_suspend(void) +static int cpufreq_bp_suspend(void) { - struct cpufreq_policy *policy; - - if (!cpufreq_driver) - return; + int ret = 0; - if (!has_target()) - return; + int cpu = smp_processor_id(); + struct cpufreq_policy *cpu_policy; - pr_debug("%s: Suspending Governors\n", __func__); + pr_debug("suspending cpu %u\n", cpu); - policy = cpufreq_cpu_get(0); + /* If there's no policy for the boot CPU, we have nothing to do. */ + cpu_policy = cpufreq_cpu_get(cpu); + if (!cpu_policy) + return 0; - if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) - pr_err("%s: Failed to stop governor for policy: %p\n", - __func__, policy); - else if (cpufreq_driver->suspend - && cpufreq_driver->suspend(policy)) - pr_err("%s: Failed to suspend driver: %p\n", __func__, - policy); + if (cpufreq_driver->suspend) { + ret = cpufreq_driver->suspend(cpu_policy); + if (ret) + printk(KERN_ERR "cpufreq: suspend failed in ->suspend " + "step on CPU %u\n", cpu_policy->cpu); + } - cpufreq_suspended = true; + cpufreq_cpu_put(cpu_policy); + return ret; } /** - * cpufreq_resume() - Resume CPUFreq governors + * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. + * + * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) + * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are + * restored. It will verify that the current freq is in sync with + * what we believe it to be. This is a bit later than when it + * should be, but nonethteless it's better than calling + * cpufreq_driver->get() here which might re-enable interrupts... * - * Called during system wide Suspend/Hibernate cycle for resuming governors that - * are suspended with cpufreq_suspend(). + * This function is only executed for the boot CPU. The other CPUs have not + * been turned on yet. */ -void cpufreq_resume(void) +static void cpufreq_bp_resume(void) { - struct cpufreq_policy *policy; - - if (!cpufreq_driver) - return; + int ret = 0; - if (!has_target()) - return; + int cpu = smp_processor_id(); + struct cpufreq_policy *cpu_policy; - pr_debug("%s: Resuming Governors\n", __func__); + pr_debug("resuming cpu %u\n", cpu); - cpufreq_suspended = false; + /* If there's no policy for the boot CPU, we have nothing to do. */ + cpu_policy = cpufreq_cpu_get(cpu); + if (!cpu_policy) + return; - policy = cpufreq_cpu_get(0); + if (cpufreq_driver->resume) { + ret = cpufreq_driver->resume(cpu_policy); + if (ret) { + printk(KERN_ERR "cpufreq: resume failed in ->resume " + "step on CPU %u\n", cpu_policy->cpu); + goto fail; + } + } - if (__cpufreq_governor(policy, CPUFREQ_GOV_START) - || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) - pr_err("%s: Failed to start governor for policy: %p\n", - __func__, policy); - else if (cpufreq_driver->resume - && cpufreq_driver->resume(policy)) - pr_err("%s: Failed to resume driver: %p\n", __func__, - policy); + schedule_work(&cpu_policy->update); - schedule_work(&policy->update); +fail: + cpufreq_cpu_put(cpu_policy); } +static struct syscore_ops cpufreq_syscore_ops = { + .suspend = cpufreq_bp_suspend, + .resume = cpufreq_bp_resume, +}; + /** * cpufreq_get_current_driver - return current driver's name * @@ -1543,10 +1544,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, struct cpufreq_governor *gov = NULL; #endif - /* Don't start any governor operations if we are entering suspend */ - if (cpufreq_suspended) - return 0; - if (policy->governor->max_transition_latency && policy->cpuinfo.transition_latency > policy->governor->max_transition_latency) { @@ -2004,6 +2001,7 @@ static int __init cpufreq_core_init(void) cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); BUG_ON(!cpufreq_global_kobject); + register_syscore_ops(&cpufreq_syscore_ops); return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 69cb5cc81013..1a81b7470bc4 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -307,18 +307,6 @@ struct freq_attr { static struct freq_attr _name = \ __ATTR(_name, 0444, show_##_name, NULL) -#ifdef CONFIG_CPU_FREQ -void cpufreq_suspend(void); -void cpufreq_resume(void); -#else -static inline void cpufreq_suspend(void) {} -static inline void cpufreq_resume(void) {} -#endif - -/********************************************************************* - * CPUFREQ NOTIFIER INTERFACE * - *********************************************************************/ - #define cpufreq_freq_attr_ro_perm(_name, _perm) \ static struct freq_attr _name = \ __ATTR(_name, _perm, show_##_name, NULL) |