aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2015-03-09 12:27:35 +0000
committerMark Brown <broonie@kernel.org>2015-03-09 12:27:35 +0000
commit165cb34cde45b13a5caca5dac528504a1cf5621f (patch)
tree2dd6133e8da76a116a4b50ed2d694b3a32545555
parent20fe0191dfddcb6fb8ade72e7f334d42fdb078cc (diff)
parentc810fcb930d9c705774427bb6eb551b2e1108adb (diff)
Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-rtlsk-v3.10-15.03-rt
-rw-r--r--drivers/base/power/main.c6
-rw-r--r--drivers/cpufreq/cpufreq.c114
-rw-r--r--include/linux/cpufreq.h12
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)