From: Rafael J. Wysocki <[email protected]>

To separate the CPU online interface from the CPU device removal
one, split cpufreq_dev_online() out of cpufreq_add_dev() and make
cpufreq_cpu_callback() call the former, while the latter will only
be used as the CPU device removal subsystem interface callback.

Suggested-by: Russell King <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
---
 drivers/cpufreq/cpufreq.c |  109 +++++++++++++++++++++++-----------------------
 1 file changed, 56 insertions(+), 53 deletions(-)

Index: linux-pm/drivers/cpufreq/cpufreq.c
===================================================================
--- linux-pm.orig/drivers/cpufreq/cpufreq.c
+++ linux-pm/drivers/cpufreq/cpufreq.c
@@ -1177,45 +1177,14 @@ static void cpufreq_policy_free(struct c
        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_dev_online(struct device *dev, bool recover_policy)
 {
        unsigned int j, cpu = dev->id;
        int ret = -ENOMEM;
        struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
        unsigned long flags;
-       bool recover_policy = !sif;
 
-       pr_debug("adding CPU %u\n", cpu);
-
-       /* sysfs links are only created on subsys callback */
-       if (sif && policy) {
-               pr_debug("%s: Adding symlink for CPU: %u\n", __func__, cpu);
-               ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
-               if (ret) {
-                       dev_dbg(dev, "%s: Failed to create link (%d)\n",
-                               __func__, ret);
-                       return ret;
-               }
-
-               /* Track CPUs for which sysfs links are created */
-               cpumask_set_cpu(cpu, policy->linked_cpus);
-       }
-
-       /*
-        * A hotplug notifier will follow and we will take care of rest
-        * of the initialization then.
-        */
-       if (cpu_is_offline(cpu))
-               return 0;
+       pr_debug("%s: bringing CPU%u online\n", __func__, cpu);
 
        if (!down_read_trylock(&cpufreq_rwsem))
                return 0;
@@ -1376,6 +1345,36 @@ out_release_rwsem:
        return ret;
 }
 
+/**
+ * cpufreq_add_dev - add a cpufreq interface to a CPU device.
+ * @dev: CPU device to add the interface to.
+ * @sif: Subsystem interface pointer.
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+{
+       unsigned int cpu = dev->id;
+       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+
+       pr_debug("%s: adding CPU %u\n", __func__, cpu);
+
+       if (policy && policy->kobj_cpu != cpu) {
+               int ret;
+
+               pr_debug("%s: Adding symlink for CPU: %u\n", __func__, cpu);
+               ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+               if (ret) {
+                       dev_dbg(dev, "%s: Failed to create link (%d)\n",
+                               __func__, ret);
+                       return ret;
+               }
+
+               /* Track CPUs for which sysfs links are created */
+               cpumask_set_cpu(cpu, policy->linked_cpus);
+       }
+
+       return cpu_online(cpu) ? cpufreq_dev_online(dev, false) : 0;
+}
+
 static void cpufreq_offline_prepare(unsigned int cpu)
 {
        struct cpufreq_policy *policy;
@@ -2344,31 +2343,35 @@ unlock:
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
+static void cpufreq_cpu_online(unsigned int cpu)
+{
+       struct device *dev = get_cpu_device(cpu);
+
+       if (dev)
+               cpufreq_dev_online(dev, true);
+}
+
 static int cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
-       struct device *dev;
 
-       dev = get_cpu_device(cpu);
-       if (dev) {
-               switch (action & ~CPU_TASKS_FROZEN) {
-               case CPU_ONLINE:
-                       cpufreq_add_dev(dev, NULL);
-                       break;
-
-               case CPU_DOWN_PREPARE:
-                       cpufreq_offline_prepare(cpu);
-                       break;
-
-               case CPU_POST_DEAD:
-                       cpufreq_offline_finish(cpu);
-                       break;
-
-               case CPU_DOWN_FAILED:
-                       cpufreq_add_dev(dev, NULL);
-                       break;
-               }
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_ONLINE:
+               cpufreq_cpu_online(cpu);
+               break;
+
+       case CPU_DOWN_PREPARE:
+               cpufreq_offline_prepare(cpu);
+               break;
+
+       case CPU_POST_DEAD:
+               cpufreq_offline_finish(cpu);
+               break;
+
+       case CPU_DOWN_FAILED:
+               cpufreq_cpu_online(cpu);
+               break;
        }
        return NOTIFY_OK;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to