|
@@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
|
|
|
- struct device *dev)
|
|
|
+ struct device *dev, bool frozen)
|
|
|
{
|
|
|
struct cpufreq_policy *policy;
|
|
|
int ret = 0, has_target = !!cpufreq_driver->target;
|
|
@@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
|
|
|
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
|
|
}
|
|
|
|
|
|
- ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
|
|
|
- if (ret) {
|
|
|
+ /* Don't touch sysfs links during light-weight init */
|
|
|
+ if (frozen) {
|
|
|
+ /* Drop the extra refcount that we took above */
|
|
|
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
|
|
|
|
|
@@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
|
|
|
kfree(policy);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 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)
|
|
|
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
|
|
+ bool frozen)
|
|
|
{
|
|
|
unsigned int j, cpu = dev->id;
|
|
|
int ret = -ENOMEM;
|
|
@@ -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);
|
|
|
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
|
|
|
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);
|
|
@@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|
|
}
|
|
|
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
|
|
|
|
|
- ret = cpufreq_add_dev_interface(cpu, policy, dev);
|
|
|
- if (ret)
|
|
|
- goto err_out_unregister;
|
|
|
+ if (!frozen) {
|
|
|
+ ret = cpufreq_add_dev_interface(cpu, policy, dev);
|
|
|
+ if (ret)
|
|
|
+ goto err_out_unregister;
|
|
|
+ }
|
|
|
|
|
|
cpufreq_init_policy(policy);
|
|
|
|
|
@@ -1112,6 +1112,20 @@ module_out:
|
|
|
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)
|
|
|
{
|
|
|
int j;
|
|
@@ -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,
|
|
|
- unsigned int old_cpu)
|
|
|
+ unsigned int old_cpu, bool frozen)
|
|
|
{
|
|
|
struct device *cpu_dev;
|
|
|
unsigned long flags;
|
|
@@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
|
|
|
|
|
|
/* first sibling now owns the new sysfs dir */
|
|
|
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");
|
|
|
ret = kobject_move(&data->kobj, &cpu_dev->kobj);
|
|
|
if (ret) {
|
|
@@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
|
|
|
* This routine frees the rwsem before returning.
|
|
|
*/
|
|
|
static int __cpufreq_remove_dev(struct device *dev,
|
|
|
- struct subsys_interface *sif)
|
|
|
+ struct subsys_interface *sif, bool frozen)
|
|
|
{
|
|
|
unsigned int cpu = dev->id, cpus;
|
|
|
int new_cpu;
|
|
@@ -1208,17 +1227,20 @@ static int __cpufreq_remove_dev(struct device *dev,
|
|
|
cpumask_clear_cpu(cpu, data->cpus);
|
|
|
unlock_policy_rwsem_write(cpu);
|
|
|
|
|
|
- if (cpu != data->cpu) {
|
|
|
+ if (cpu != data->cpu && !frozen) {
|
|
|
sysfs_remove_link(&dev->kobj, "cpufreq");
|
|
|
} 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) {
|
|
|
WARN_ON(lock_policy_rwsem_write(cpu));
|
|
|
update_policy_cpu(data, new_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)
|
|
|
if (cpu_is_offline(cpu))
|
|
|
return 0;
|
|
|
|
|
|
- retval = __cpufreq_remove_dev(dev, sif);
|
|
|
+ retval = __cpufreq_remove_dev(dev, sif, false);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -1992,7 +2014,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
|
|
|
break;
|
|
|
case CPU_DOWN_PREPARE:
|
|
|
case CPU_DOWN_PREPARE_FROZEN:
|
|
|
- __cpufreq_remove_dev(dev, NULL);
|
|
|
+ __cpufreq_remove_dev(dev, NULL, false);
|
|
|
break;
|
|
|
case CPU_DOWN_FAILED:
|
|
|
case CPU_DOWN_FAILED_FROZEN:
|