Skip to content

Commit

Permalink
Merge branches 'pm-cpuidle' and 'pm-cpufreq'
Browse files Browse the repository at this point in the history
* pm-cpuidle:
  cpuidle: Check for dev before deregistering it.
  intel_idle: Fixed C6 state on Avoton/Rangeley processors

* pm-cpufreq:
  cpufreq: fix garbage kobjects on errors during suspend/resume
  cpufreq: suspend governors on system suspend/hibernate
  • Loading branch information
rafaeljw committed Dec 6, 2013
3 parents dc1ccc4 + 813e8e3 + 2167e23 commit 7cdcec9
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 6 deletions.
3 changes: 3 additions & 0 deletions drivers/base/power/main.c
Expand Up @@ -29,6 +29,7 @@
#include <linux/async.h>
#include <linux/suspend.h>
#include <trace/events/power.h>
#include <linux/cpufreq.h>
#include <linux/cpuidle.h>
#include <linux/timer.h>

Expand Down Expand Up @@ -540,6 +541,7 @@ static void dpm_resume_noirq(pm_message_t state)
dpm_show_time(starttime, state, "noirq");
resume_device_irqs();
cpuidle_resume();
cpufreq_resume();
}

/**
Expand Down Expand Up @@ -955,6 +957,7 @@ static int dpm_suspend_noirq(pm_message_t state)
ktime_t starttime = ktime_get();
int error = 0;

cpufreq_suspend();
cpuidle_pause();
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
Expand Down
46 changes: 43 additions & 3 deletions drivers/cpufreq/cpufreq.c
Expand Up @@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/tick.h>
#include <trace/events/power.h>
Expand All @@ -47,6 +48,9 @@ static LIST_HEAD(cpufreq_policy_list);
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)
{
return cpufreq_driver->target_index || cpufreq_driver->target;
Expand Down Expand Up @@ -1462,6 +1466,41 @@ static struct subsys_interface cpufreq_interface = {
.remove_dev = cpufreq_remove_dev,
};

void cpufreq_suspend(void)
{
struct cpufreq_policy *policy;

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);

cpufreq_suspended = true;
}

void cpufreq_resume(void)
{
struct cpufreq_policy *policy;

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);
}

/**
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
*
Expand Down Expand Up @@ -1764,6 +1803,10 @@ 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) {
Expand Down Expand Up @@ -2076,9 +2119,6 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpuidle/cpuidle.c
Expand Up @@ -400,7 +400,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
*/
void cpuidle_unregister_device(struct cpuidle_device *dev)
{
if (dev->registered == 0)
if (!dev || dev->registered == 0)
return;

cpuidle_pause_and_lock();
Expand Down
4 changes: 2 additions & 2 deletions drivers/idle/intel_idle.c
Expand Up @@ -329,7 +329,7 @@ static struct cpuidle_state atom_cstates[] __initdata = {
{
.enter = NULL }
};
static struct cpuidle_state avn_cstates[CPUIDLE_STATE_MAX] = {
static struct cpuidle_state avn_cstates[] __initdata = {
{
.name = "C1-AVN",
.desc = "MWAIT 0x00",
Expand All @@ -340,7 +340,7 @@ static struct cpuidle_state avn_cstates[CPUIDLE_STATE_MAX] = {
{
.name = "C6-AVN",
.desc = "MWAIT 0x51",
.flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 15,
.target_residency = 45,
.enter = &intel_idle },
Expand Down
8 changes: 8 additions & 0 deletions include/linux/cpufreq.h
Expand Up @@ -280,6 +280,14 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq);
}

#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 *
*********************************************************************/
Expand Down

0 comments on commit 7cdcec9

Please sign in to comment.