Commit a82fab29 authored by Srivatsa S. Bhat's avatar Srivatsa S. Bhat Committed by Rafael J. Wysocki

cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown

During suspend/resume we would like to do a light-weight init/teardown of
CPUs in the cpufreq subsystem and preserve certain things such as sysfs files
etc across suspend/resume transitions. Add a flag called 'frozen' to help
distinguish the full init/teardown sequence from the light-weight one.
Signed-off-by: default avatarSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent f9ba680d
...@@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) ...@@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
struct device *dev) struct device *dev, bool frozen)
{ {
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
int ret = 0, has_target = !!cpufreq_driver->target; int ret = 0, has_target = !!cpufreq_driver->target;
...@@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, ...@@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
} }
ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); /* Don't touch sysfs links during light-weight init */
if (ret) { if (frozen) {
/* Drop the extra refcount that we took above */
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
return ret; return 0;
} }
return 0; ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
if (ret)
cpufreq_cpu_put(policy);
return ret;
} }
#endif #endif
...@@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) ...@@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
kfree(policy); kfree(policy);
} }
/** static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
* cpufreq_add_dev - add a CPU device bool frozen)
*
* Adds the cpufreq interface for a CPU device.
*
* The Oracle says: try running cpufreq registration/unregistration concurrently
* with with cpu hotplugging and all hell will break loose. Tried to clean this
* mess up, but more thorough testing is needed. - Mathieu
*/
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{ {
unsigned int j, cpu = dev->id; unsigned int j, cpu = dev->id;
int ret = -ENOMEM; int ret = -ENOMEM;
...@@ -1013,7 +1010,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1013,7 +1010,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
read_unlock_irqrestore(&cpufreq_driver_lock, flags); read_unlock_irqrestore(&cpufreq_driver_lock, flags);
return cpufreq_add_policy_cpu(cpu, sibling, dev); return cpufreq_add_policy_cpu(cpu, sibling, dev,
frozen);
} }
} }
read_unlock_irqrestore(&cpufreq_driver_lock, flags); read_unlock_irqrestore(&cpufreq_driver_lock, flags);
...@@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
} }
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = cpufreq_add_dev_interface(cpu, policy, dev); if (!frozen) {
if (ret) ret = cpufreq_add_dev_interface(cpu, policy, dev);
goto err_out_unregister; if (ret)
goto err_out_unregister;
}
cpufreq_init_policy(policy); cpufreq_init_policy(policy);
...@@ -1112,6 +1112,20 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1112,6 +1112,20 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return ret; return ret;
} }
/**
* cpufreq_add_dev - add a CPU device
*
* Adds the cpufreq interface for a CPU device.
*
* The Oracle says: try running cpufreq registration/unregistration concurrently
* with with cpu hotplugging and all hell will break loose. Tried to clean this
* mess up, but more thorough testing is needed. - Mathieu
*/
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
return __cpufreq_add_dev(dev, sif, false);
}
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
{ {
int j; int j;
...@@ -1130,7 +1144,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) ...@@ -1130,7 +1144,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
} }
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
unsigned int old_cpu) unsigned int old_cpu, bool frozen)
{ {
struct device *cpu_dev; struct device *cpu_dev;
unsigned long flags; unsigned long flags;
...@@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, ...@@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
/* first sibling now owns the new sysfs dir */ /* first sibling now owns the new sysfs dir */
cpu_dev = get_cpu_device(cpumask_first(data->cpus)); cpu_dev = get_cpu_device(cpumask_first(data->cpus));
/* Don't touch sysfs files during light-weight tear-down */
if (frozen)
return cpu_dev->id;
sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
ret = kobject_move(&data->kobj, &cpu_dev->kobj); ret = kobject_move(&data->kobj, &cpu_dev->kobj);
if (ret) { if (ret) {
...@@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, ...@@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
* This routine frees the rwsem before returning. * This routine frees the rwsem before returning.
*/ */
static int __cpufreq_remove_dev(struct device *dev, static int __cpufreq_remove_dev(struct device *dev,
struct subsys_interface *sif) struct subsys_interface *sif, bool frozen)
{ {
unsigned int cpu = dev->id, cpus; unsigned int cpu = dev->id, cpus;
int new_cpu; int new_cpu;
...@@ -1208,17 +1227,20 @@ static int __cpufreq_remove_dev(struct device *dev, ...@@ -1208,17 +1227,20 @@ static int __cpufreq_remove_dev(struct device *dev,
cpumask_clear_cpu(cpu, data->cpus); cpumask_clear_cpu(cpu, data->cpus);
unlock_policy_rwsem_write(cpu); unlock_policy_rwsem_write(cpu);
if (cpu != data->cpu) { if (cpu != data->cpu && !frozen) {
sysfs_remove_link(&dev->kobj, "cpufreq"); sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) { } else if (cpus > 1) {
new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu); new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen);
if (new_cpu >= 0) { if (new_cpu >= 0) {
WARN_ON(lock_policy_rwsem_write(cpu)); WARN_ON(lock_policy_rwsem_write(cpu));
update_policy_cpu(data, new_cpu); update_policy_cpu(data, new_cpu);
unlock_policy_rwsem_write(cpu); unlock_policy_rwsem_write(cpu);
pr_debug("%s: policy Kobject moved to cpu: %d "
"from: %d\n",__func__, new_cpu, cpu); if (!frozen) {
pr_debug("%s: policy Kobject moved to cpu: %d "
"from: %d\n",__func__, new_cpu, cpu);
}
} }
} }
...@@ -1266,7 +1288,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1266,7 +1288,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu)) if (cpu_is_offline(cpu))
return 0; return 0;
retval = __cpufreq_remove_dev(dev, sif); retval = __cpufreq_remove_dev(dev, sif, false);
return retval; return retval;
} }
...@@ -1992,7 +2014,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, ...@@ -1992,7 +2014,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break; break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN: case CPU_DOWN_PREPARE_FROZEN:
__cpufreq_remove_dev(dev, NULL); __cpufreq_remove_dev(dev, NULL, false);
break; break;
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN: case CPU_DOWN_FAILED_FROZEN:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment