Merge back earlier 'pm-cpufreq' material.
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/tick.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
@@ -42,10 +42,11 @@ static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||
DEFINE_MUTEX(cpufreq_governor_lock);
|
||||
static LIST_HEAD(cpufreq_policy_list);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/* This one keeps track of the previously set governor of a removed CPU */
|
||||
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
|
||||
#endif
|
||||
|
||||
/* Flag to suspend/resume CPUFreq governors */
|
||||
static bool cpufreq_suspended;
|
||||
|
||||
static inline bool has_target(void)
|
||||
{
|
||||
@@ -181,8 +182,8 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
|
||||
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
||||
if (!policy || IS_ERR(policy->clk)) {
|
||||
pr_err("%s: No %s associated to cpu: %d\n", __func__,
|
||||
policy ? "clk" : "policy", cpu);
|
||||
pr_err("%s: No %s associated to cpu: %d\n",
|
||||
__func__, policy ? "clk" : "policy", cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -190,6 +191,12 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
|
||||
|
||||
/* Only for cpufreq core internal use */
|
||||
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
|
||||
{
|
||||
return per_cpu(cpufreq_cpu_data, cpu);
|
||||
}
|
||||
|
||||
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = NULL;
|
||||
@@ -254,15 +261,15 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
||||
if (!l_p_j_ref_freq) {
|
||||
l_p_j_ref = loops_per_jiffy;
|
||||
l_p_j_ref_freq = ci->old;
|
||||
pr_debug("saving %lu as reference value for loops_per_jiffy; "
|
||||
"freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
|
||||
pr_debug("saving %lu as reference value for loops_per_jiffy; freq is %u kHz\n",
|
||||
l_p_j_ref, l_p_j_ref_freq);
|
||||
}
|
||||
if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
|
||||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
|
||||
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
|
||||
ci->new);
|
||||
pr_debug("scaling loops_per_jiffy to %lu "
|
||||
"for frequency %u kHz\n", loops_per_jiffy, ci->new);
|
||||
pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
|
||||
loops_per_jiffy, ci->new);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -282,7 +289,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
|
||||
freqs->flags = cpufreq_driver->flags;
|
||||
pr_debug("notification %u of frequency transition to %u kHz\n",
|
||||
state, freqs->new);
|
||||
state, freqs->new);
|
||||
|
||||
switch (state) {
|
||||
|
||||
@@ -294,9 +301,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if ((policy) && (policy->cpu == freqs->cpu) &&
|
||||
(policy->cur) && (policy->cur != freqs->old)) {
|
||||
pr_debug("Warning: CPU frequency is"
|
||||
" %u, cpufreq assumed %u kHz.\n",
|
||||
freqs->old, policy->cur);
|
||||
pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
|
||||
freqs->old, policy->cur);
|
||||
freqs->old = policy->cur;
|
||||
}
|
||||
}
|
||||
@@ -307,8 +313,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
|
||||
case CPUFREQ_POSTCHANGE:
|
||||
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
|
||||
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
|
||||
(unsigned long)freqs->cpu);
|
||||
pr_debug("FREQ: %lu - CPU: %lu\n",
|
||||
(unsigned long)freqs->new, (unsigned long)freqs->cpu);
|
||||
trace_cpu_frequency(freqs->new, freqs->cpu);
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_POSTCHANGE, freqs);
|
||||
@@ -352,7 +358,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
|
||||
/*********************************************************************
|
||||
* SYSFS INTERFACE *
|
||||
*********************************************************************/
|
||||
ssize_t show_boost(struct kobject *kobj,
|
||||
static ssize_t show_boost(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
|
||||
@@ -368,13 +374,13 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
|
||||
return -EINVAL;
|
||||
|
||||
if (cpufreq_boost_trigger_state(enable)) {
|
||||
pr_err("%s: Cannot %s BOOST!\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
pr_err("%s: Cannot %s BOOST!\n",
|
||||
__func__, enable ? "enable" : "disable");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("%s: cpufreq BOOST %s\n", __func__,
|
||||
enable ? "enabled" : "disabled");
|
||||
pr_debug("%s: cpufreq BOOST %s\n",
|
||||
__func__, enable ? "enabled" : "disabled");
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -879,18 +885,25 @@ err_out_kobj_put:
|
||||
|
||||
static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_governor *gov = NULL;
|
||||
struct cpufreq_policy new_policy;
|
||||
int ret = 0;
|
||||
|
||||
memcpy(&new_policy, policy, sizeof(*policy));
|
||||
|
||||
/* Update governor of new_policy to the governor used before hotplug */
|
||||
gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
|
||||
if (gov)
|
||||
pr_debug("Restoring governor %s for cpu %d\n",
|
||||
policy->governor->name, policy->cpu);
|
||||
else
|
||||
gov = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
|
||||
new_policy.governor = gov;
|
||||
|
||||
/* Use the default policy if its valid. */
|
||||
if (cpufreq_driver->setpolicy)
|
||||
cpufreq_parse_governor(policy->governor->name,
|
||||
&new_policy.policy, NULL);
|
||||
|
||||
/* assure that the starting sequence is run in cpufreq_set_policy */
|
||||
policy->governor = NULL;
|
||||
cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
|
||||
|
||||
/* set default policy */
|
||||
ret = cpufreq_set_policy(policy, &new_policy);
|
||||
@@ -949,6 +962,8 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
|
||||
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
policy->governor = NULL;
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
@@ -1022,21 +1037,19 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
cpufreq_frequency_table_update_policy_cpu(policy);
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_UPDATE_POLICY_CPU, policy);
|
||||
}
|
||||
|
||||
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int j, cpu = dev->id;
|
||||
int ret = -ENOMEM;
|
||||
struct cpufreq_policy *policy;
|
||||
unsigned long flags;
|
||||
bool recover_policy = cpufreq_suspended;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpufreq_policy *tpolicy;
|
||||
struct cpufreq_governor *gov;
|
||||
#endif
|
||||
|
||||
if (cpu_is_offline(cpu))
|
||||
@@ -1075,9 +1088,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
* Restore the saved policy when doing light-weight init and fall back
|
||||
* to the full init if that fails.
|
||||
*/
|
||||
policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
|
||||
policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
|
||||
if (!policy) {
|
||||
frozen = false;
|
||||
recover_policy = false;
|
||||
policy = cpufreq_policy_alloc();
|
||||
if (!policy)
|
||||
goto nomem_out;
|
||||
@@ -1089,12 +1102,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
* the creation of a brand new one. So we need to perform this update
|
||||
* by invoking update_policy_cpu().
|
||||
*/
|
||||
if (frozen && cpu != policy->cpu)
|
||||
if (recover_policy && cpu != policy->cpu)
|
||||
update_policy_cpu(policy, cpu);
|
||||
else
|
||||
policy->cpu = cpu;
|
||||
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
cpumask_copy(policy->cpus, cpumask_of(cpu));
|
||||
|
||||
init_completion(&policy->kobj_unregister);
|
||||
@@ -1118,7 +1130,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
*/
|
||||
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
policy->user_policy.min = policy->min;
|
||||
policy->user_policy.max = policy->max;
|
||||
}
|
||||
@@ -1180,16 +1192,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_START, policy);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
|
||||
if (gov) {
|
||||
policy->governor = gov;
|
||||
pr_debug("Restoring governor %s for cpu %d\n",
|
||||
policy->governor->name, cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
ret = cpufreq_add_dev_interface(policy, dev);
|
||||
if (ret)
|
||||
goto err_out_unregister;
|
||||
@@ -1203,7 +1206,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
|
||||
cpufreq_init_policy(policy);
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
policy->user_policy.policy = policy->policy;
|
||||
policy->user_policy.governor = policy->governor;
|
||||
}
|
||||
@@ -1226,7 +1229,7 @@ err_get_freq:
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
err_set_policy_cpu:
|
||||
if (frozen) {
|
||||
if (recover_policy) {
|
||||
/* Do not leave stale fallback data behind. */
|
||||
per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
@@ -1250,7 +1253,7 @@ nomem_out:
|
||||
*/
|
||||
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
||||
{
|
||||
return __cpufreq_add_dev(dev, sif, false);
|
||||
return __cpufreq_add_dev(dev, sif);
|
||||
}
|
||||
|
||||
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
@@ -1265,7 +1268,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
|
||||
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to move kobj: %d", __func__, ret);
|
||||
pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
cpumask_set_cpu(old_cpu, policy->cpus);
|
||||
@@ -1281,8 +1284,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
}
|
||||
|
||||
static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int new_cpu, ret;
|
||||
@@ -1296,7 +1298,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
||||
/* Save the policy somewhere when doing a light-weight tear-down */
|
||||
if (frozen)
|
||||
if (cpufreq_suspended)
|
||||
per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
|
||||
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
@@ -1314,11 +1316,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!cpufreq_driver->setpolicy)
|
||||
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
|
||||
policy->governor->name, CPUFREQ_NAME_LEN);
|
||||
#endif
|
||||
|
||||
down_read(&policy->rwsem);
|
||||
cpus = cpumask_weight(policy->cpus);
|
||||
@@ -1331,9 +1331,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
if (new_cpu >= 0) {
|
||||
update_policy_cpu(policy, new_cpu);
|
||||
|
||||
if (!frozen) {
|
||||
if (!cpufreq_suspended) {
|
||||
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
|
||||
__func__, new_cpu, cpu);
|
||||
__func__, new_cpu, cpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1342,8 +1342,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
}
|
||||
|
||||
static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int ret;
|
||||
@@ -1373,12 +1372,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to exit governor\n",
|
||||
__func__);
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frozen)
|
||||
if (!cpufreq_suspended)
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
|
||||
/*
|
||||
@@ -1394,14 +1393,14 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
list_del(&policy->policy_list);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (!frozen)
|
||||
if (!cpufreq_suspended)
|
||||
cpufreq_policy_free(policy);
|
||||
} else {
|
||||
if (has_target()) {
|
||||
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
|
||||
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
|
||||
pr_err("%s: Failed to start governor\n",
|
||||
__func__);
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -1424,10 +1423,10 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
|
||||
if (cpu_is_offline(cpu))
|
||||
return 0;
|
||||
|
||||
ret = __cpufreq_remove_dev_prepare(dev, sif, false);
|
||||
ret = __cpufreq_remove_dev_prepare(dev, sif);
|
||||
|
||||
if (!ret)
|
||||
ret = __cpufreq_remove_dev_finish(dev, sif, false);
|
||||
ret = __cpufreq_remove_dev_finish(dev, sif);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1458,8 +1457,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
|
||||
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
|
||||
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
|
||||
old_freq, new_freq);
|
||||
|
||||
freqs.old = old_freq;
|
||||
freqs.new = new_freq;
|
||||
@@ -1570,83 +1569,104 @@ static struct subsys_interface cpufreq_interface = {
|
||||
.remove_dev = cpufreq_remove_dev,
|
||||
};
|
||||
|
||||
/**
|
||||
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
|
||||
*
|
||||
* This function is only executed for the boot processor. The other CPUs
|
||||
* have been put offline by means of CPU hotplug.
|
||||
/*
|
||||
* In case platform wants some specific frequency to be configured
|
||||
* during suspend..
|
||||
*/
|
||||
static int cpufreq_bp_suspend(void)
|
||||
int cpufreq_generic_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
pr_debug("suspending cpu %u\n", cpu);
|
||||
|
||||
/* If there's no policy for the boot CPU, we have nothing to do. */
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
return 0;
|
||||
|
||||
if (cpufreq_driver->suspend) {
|
||||
ret = cpufreq_driver->suspend(policy);
|
||||
if (ret)
|
||||
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
|
||||
"step on CPU %u\n", policy->cpu);
|
||||
if (!policy->suspend_freq) {
|
||||
pr_err("%s: suspend_freq can't be zero\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
pr_debug("%s: Setting suspend-freq: %u\n", __func__,
|
||||
policy->suspend_freq);
|
||||
|
||||
ret = __cpufreq_driver_target(policy, policy->suspend_freq,
|
||||
CPUFREQ_RELATION_H);
|
||||
if (ret)
|
||||
pr_err("%s: unable to set suspend-freq: %u. err: %d\n",
|
||||
__func__, policy->suspend_freq, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_generic_suspend);
|
||||
|
||||
/**
|
||||
* cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
|
||||
* cpufreq_suspend() - Suspend CPUFreq governors
|
||||
*
|
||||
* 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...
|
||||
*
|
||||
* This function is only executed for the boot CPU. The other CPUs have not
|
||||
* been turned on yet.
|
||||
* 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.
|
||||
*/
|
||||
static void cpufreq_bp_resume(void)
|
||||
void cpufreq_suspend(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
pr_debug("resuming cpu %u\n", cpu);
|
||||
|
||||
/* If there's no policy for the boot CPU, we have nothing to do. */
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
if (!cpufreq_driver)
|
||||
return;
|
||||
|
||||
if (cpufreq_driver->resume) {
|
||||
ret = cpufreq_driver->resume(policy);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "cpufreq: resume failed in ->resume "
|
||||
"step on CPU %u\n", policy->cpu);
|
||||
goto fail;
|
||||
}
|
||||
if (!has_target())
|
||||
return;
|
||||
|
||||
pr_debug("%s: Suspending Governors\n", __func__);
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
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);
|
||||
}
|
||||
|
||||
schedule_work(&policy->update);
|
||||
|
||||
fail:
|
||||
cpufreq_cpu_put(policy);
|
||||
cpufreq_suspended = true;
|
||||
}
|
||||
|
||||
static struct syscore_ops cpufreq_syscore_ops = {
|
||||
.suspend = cpufreq_bp_suspend,
|
||||
.resume = cpufreq_bp_resume,
|
||||
};
|
||||
/**
|
||||
* cpufreq_resume() - Resume CPUFreq governors
|
||||
*
|
||||
* Called during system wide Suspend/Hibernate cycle for resuming governors that
|
||||
* are suspended with cpufreq_suspend().
|
||||
*/
|
||||
void cpufreq_resume(void)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if (!cpufreq_driver)
|
||||
return;
|
||||
|
||||
if (!has_target())
|
||||
return;
|
||||
|
||||
pr_debug("%s: Resuming Governors\n", __func__);
|
||||
|
||||
cpufreq_suspended = false;
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
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 call cpufreq_update_policy() for boot CPU, i.e. last
|
||||
* policy in list. It will verify that the current freq is in
|
||||
* sync with what we believe it to be.
|
||||
*/
|
||||
if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
|
||||
schedule_work(&policy->update);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cpufreq_get_current_driver - return current driver's name
|
||||
@@ -1762,7 +1782,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
target_freq = policy->min;
|
||||
|
||||
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
|
||||
policy->cpu, target_freq, relation, old_target_freq);
|
||||
policy->cpu, target_freq, relation, old_target_freq);
|
||||
|
||||
/*
|
||||
* This might look like a redundant call as we are checking it again
|
||||
@@ -1807,8 +1827,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
freqs.flags = 0;
|
||||
|
||||
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
|
||||
__func__, policy->cpu, freqs.old,
|
||||
freqs.new);
|
||||
__func__, policy->cpu, freqs.old, freqs.new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs,
|
||||
CPUFREQ_PRECHANGE);
|
||||
@@ -1817,7 +1836,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
retval = cpufreq_driver->target_index(policy, index);
|
||||
if (retval)
|
||||
pr_err("%s: Failed to change cpu frequency: %d\n",
|
||||
__func__, retval);
|
||||
__func__, retval);
|
||||
|
||||
if (notify)
|
||||
cpufreq_notify_post_transition(policy, &freqs, retval);
|
||||
@@ -1863,17 +1882,18 @@ 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) {
|
||||
if (!gov)
|
||||
return -EINVAL;
|
||||
else {
|
||||
printk(KERN_WARNING "%s governor failed, too long"
|
||||
" transition latency of HW, fallback"
|
||||
" to %s governor\n",
|
||||
policy->governor->name,
|
||||
gov->name);
|
||||
pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
|
||||
policy->governor->name, gov->name);
|
||||
policy->governor = gov;
|
||||
}
|
||||
}
|
||||
@@ -1883,7 +1903,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
|
||||
policy->cpu, event);
|
||||
policy->cpu, event);
|
||||
|
||||
mutex_lock(&cpufreq_governor_lock);
|
||||
if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
|
||||
@@ -1950,9 +1970,7 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
|
||||
|
||||
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
||||
{
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int cpu;
|
||||
#endif
|
||||
|
||||
if (!governor)
|
||||
return;
|
||||
@@ -1960,14 +1978,12 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
||||
if (cpufreq_disabled())
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
for_each_present_cpu(cpu) {
|
||||
if (cpu_online(cpu))
|
||||
continue;
|
||||
if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
|
||||
strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
|
||||
}
|
||||
#endif
|
||||
|
||||
mutex_lock(&cpufreq_governor_mutex);
|
||||
list_del(&governor->governor_list);
|
||||
@@ -2012,22 +2028,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
|
||||
static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
struct cpufreq_policy *new_policy)
|
||||
{
|
||||
int ret = 0, failed = 1;
|
||||
struct cpufreq_governor *old_gov;
|
||||
int ret;
|
||||
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
|
||||
new_policy->min, new_policy->max);
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
|
||||
new_policy->cpu, new_policy->min, new_policy->max);
|
||||
|
||||
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
|
||||
|
||||
if (new_policy->min > policy->max || new_policy->max < policy->min) {
|
||||
ret = -EINVAL;
|
||||
goto error_out;
|
||||
}
|
||||
if (new_policy->min > policy->max || new_policy->max < policy->min)
|
||||
return -EINVAL;
|
||||
|
||||
/* verify the cpu speed can be set within this limit */
|
||||
ret = cpufreq_driver->verify(new_policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
return ret;
|
||||
|
||||
/* adjust if necessary - all reasons */
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
@@ -2043,7 +2058,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
*/
|
||||
ret = cpufreq_driver->verify(new_policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
return ret;
|
||||
|
||||
/* notification of the new policy */
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
@@ -2053,63 +2068,53 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
policy->max = new_policy->max;
|
||||
|
||||
pr_debug("new min and max freqs are %u - %u kHz\n",
|
||||
policy->min, policy->max);
|
||||
policy->min, policy->max);
|
||||
|
||||
if (cpufreq_driver->setpolicy) {
|
||||
policy->policy = new_policy->policy;
|
||||
pr_debug("setting range\n");
|
||||
ret = cpufreq_driver->setpolicy(new_policy);
|
||||
} else {
|
||||
if (new_policy->governor != policy->governor) {
|
||||
/* save old, working values */
|
||||
struct cpufreq_governor *old_gov = policy->governor;
|
||||
|
||||
pr_debug("governor switch\n");
|
||||
|
||||
/* end old governor */
|
||||
if (policy->governor) {
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* start new governor */
|
||||
policy->governor = new_policy->governor;
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
|
||||
failed = 0;
|
||||
} else {
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
/* new governor failed, so re-start old one */
|
||||
pr_debug("starting governor %s failed\n",
|
||||
policy->governor->name);
|
||||
if (old_gov) {
|
||||
policy->governor = old_gov;
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_INIT);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_START);
|
||||
}
|
||||
ret = -EINVAL;
|
||||
goto error_out;
|
||||
}
|
||||
/* might be a policy change, too, so fall through */
|
||||
}
|
||||
pr_debug("governor: change or update limits\n");
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
return cpufreq_driver->setpolicy(new_policy);
|
||||
}
|
||||
|
||||
error_out:
|
||||
return ret;
|
||||
if (new_policy->governor == policy->governor)
|
||||
goto out;
|
||||
|
||||
pr_debug("governor switch\n");
|
||||
|
||||
/* save old, working values */
|
||||
old_gov = policy->governor;
|
||||
/* end old governor */
|
||||
if (old_gov) {
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy,CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* start new governor */
|
||||
policy->governor = new_policy->governor;
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
|
||||
goto out;
|
||||
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* new governor failed, so re-start old one */
|
||||
pr_debug("starting governor %s failed\n", policy->governor->name);
|
||||
if (old_gov) {
|
||||
policy->governor = old_gov;
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
out:
|
||||
pr_debug("governor: change or update limits\n");
|
||||
return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2145,8 +2150,13 @@ int cpufreq_update_policy(unsigned int cpu)
|
||||
*/
|
||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
|
||||
new_policy.cur = cpufreq_driver->get(cpu);
|
||||
if (WARN_ON(!new_policy.cur)) {
|
||||
ret = -EIO;
|
||||
goto no_policy;
|
||||
}
|
||||
|
||||
if (!policy->cur) {
|
||||
pr_debug("Driver did not initialize current freq");
|
||||
pr_debug("Driver did not initialize current freq\n");
|
||||
policy->cur = new_policy.cur;
|
||||
} else {
|
||||
if (policy->cur != new_policy.cur && has_target())
|
||||
@@ -2170,30 +2180,24 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
struct device *dev;
|
||||
bool frozen = false;
|
||||
|
||||
dev = get_cpu_device(cpu);
|
||||
if (dev) {
|
||||
|
||||
if (action & CPU_TASKS_FROZEN)
|
||||
frozen = true;
|
||||
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
case CPU_ONLINE:
|
||||
__cpufreq_add_dev(dev, NULL, frozen);
|
||||
cpufreq_update_policy(cpu);
|
||||
__cpufreq_add_dev(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_PREPARE:
|
||||
__cpufreq_remove_dev_prepare(dev, NULL, frozen);
|
||||
__cpufreq_remove_dev_prepare(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_POST_DEAD:
|
||||
__cpufreq_remove_dev_finish(dev, NULL, frozen);
|
||||
__cpufreq_remove_dev_finish(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_FAILED:
|
||||
__cpufreq_add_dev(dev, NULL, frozen);
|
||||
__cpufreq_add_dev(dev, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2249,8 +2253,8 @@ int cpufreq_boost_trigger_state(int state)
|
||||
cpufreq_driver->boost_enabled = !state;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
pr_err("%s: Cannot %s BOOST\n", __func__,
|
||||
state ? "enable" : "disable");
|
||||
pr_err("%s: Cannot %s BOOST\n",
|
||||
__func__, state ? "enable" : "disable");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -2322,7 +2326,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
ret = cpufreq_sysfs_create_file(&boost.attr);
|
||||
if (ret) {
|
||||
pr_err("%s: cannot register global BOOST sysfs file\n",
|
||||
__func__);
|
||||
__func__);
|
||||
goto err_null_driver;
|
||||
}
|
||||
}
|
||||
@@ -2345,7 +2349,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
/* if all ->init() calls failed, unregister */
|
||||
if (ret) {
|
||||
pr_debug("no CPU initialized for driver %s\n",
|
||||
driver_data->name);
|
||||
driver_data->name);
|
||||
goto err_if_unreg;
|
||||
}
|
||||
}
|
||||
@@ -2409,7 +2413,6 @@ static int __init cpufreq_core_init(void)
|
||||
|
||||
cpufreq_global_kobject = kobject_create();
|
||||
BUG_ON(!cpufreq_global_kobject);
|
||||
register_syscore_ops(&cpufreq_syscore_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Verwijs in nieuw issue
Block a user