cpufreq: Save state for entire cluster when the last CPU goes offline

When the last CPU within a cluster goes offline its cpufreq limits and
the current governor are saved so that it can start with the same
state (cpufreq min/max limits and scaling governor) when it comes back
online later. However if a different CPU from the same cluster comes
online after this it will restore the state that it saved when it went
offline and which can be different from the state of the CPU last
offlined. This can leave the system in incorrect (i.e. not the latest)
state since the rest of the CPUs in the same cluster brought back
online later will be associated with the CPU that first came online.
To prevent such a scenario save the state for all CPUs in a cluster
when the last CPU goes offline (since the last CPU holds the latest
updates) so that it can be properly restored by any CPU that first
comes online in that cluster.

Change-Id: I67cd6bb219b7cc4fd18507ffb9b43ca37dcf0ae7
Signed-off-by: Rohit Gupta <rohgup@codeaurora.org>
This commit is contained in:
Rohit Gupta 2015-03-30 14:32:36 -07:00
parent 9b352820cb
commit d3884c7499
1 changed files with 24 additions and 10 deletions

View File

@ -1214,6 +1214,27 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
return cpu_dev->id;
}
#ifdef CONFIG_HOTPLUG_CPU
static void update_related_cpus(struct cpufreq_policy *policy)
{
unsigned int j;
for_each_cpu(j, policy->related_cpus) {
if (!cpufreq_driver->setpolicy)
strlcpy(per_cpu(cpufreq_policy_save, j).gov,
policy->governor->name, CPUFREQ_NAME_LEN);
per_cpu(cpufreq_policy_save, j).min = policy->user_policy.min;
per_cpu(cpufreq_policy_save, j).max = policy->user_policy.max;
pr_debug("Saving CPU%d user policy min %d and max %d\n",
j, policy->user_policy.min, policy->user_policy.max);
}
}
#else
static void update_related_cpus(struct cpufreq_policy *policy)
{
}
#endif
static int __cpufreq_remove_dev_prepare(struct device *dev,
struct subsys_interface *sif,
bool frozen)
@ -1249,20 +1270,13 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
}
}
#ifdef CONFIG_HOTPLUG_CPU
if (!cpufreq_driver->setpolicy)
strlcpy(per_cpu(cpufreq_policy_save, cpu).gov,
policy->governor->name, CPUFREQ_NAME_LEN);
per_cpu(cpufreq_policy_save, cpu).min = policy->user_policy.min;
per_cpu(cpufreq_policy_save, cpu).max = policy->user_policy.max;
pr_debug("Saving CPU%d user policy min %d and max %d\n",
cpu, policy->user_policy.min, policy->user_policy.max);
#endif
down_read(&policy->rwsem);
cpus = cpumask_weight(policy->cpus);
up_read(&policy->rwsem);
if (cpus == 1)
update_related_cpus(policy);
if (cpu != policy->cpu) {
sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {