UBUNTU: SAUCE: Allow filtering of cpufreq drivers
[linux-flexiantxendom0.git] / drivers / cpufreq / cpufreq.c
index b90eda8..fe63d01 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/cpu.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
+#include <linux/syscore_ops.h>
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
-                                               "cpufreq-core", msg)
+#include <trace/events/power.h>
 
 /**
  * The "cpufreq driver" - the arch- or hardware-dependent low
@@ -41,7 +41,7 @@ static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
 #ifdef CONFIG_HOTPLUG_CPU
 /* This one keeps track of the previously set governor of a removed CPU */
-static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor);
+static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
 #endif
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
@@ -61,15 +61,17 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
  *   are concerned with are online after they get the lock.
  * - Governor routines that can be called in cpufreq hotplug path should not
  *   take this sem as top level hotplug notifier handler takes this.
+ * - Lock should not be held across
+ *     __cpufreq_governor(data, CPUFREQ_GOV_STOP);
  */
-static DEFINE_PER_CPU(int, policy_cpu);
+static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
 static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
 
 #define lock_policy_rwsem(mode, cpu)                                   \
-int lock_policy_rwsem_##mode                                           \
+static int lock_policy_rwsem_##mode                                    \
 (int cpu)                                                              \
 {                                                                      \
-       int policy_cpu = per_cpu(policy_cpu, cpu);                      \
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);              \
        BUG_ON(policy_cpu == -1);                                       \
        down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));            \
        if (unlikely(!cpu_online(cpu))) {                               \
@@ -81,26 +83,22 @@ int lock_policy_rwsem_##mode                                                \
 }
 
 lock_policy_rwsem(read, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_read);
 
 lock_policy_rwsem(write, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
 
-void unlock_policy_rwsem_read(int cpu)
+static void unlock_policy_rwsem_read(int cpu)
 {
-       int policy_cpu = per_cpu(policy_cpu, cpu);
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
        BUG_ON(policy_cpu == -1);
        up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
 
-void unlock_policy_rwsem_write(int cpu)
+static void unlock_policy_rwsem_write(int cpu)
 {
-       int policy_cpu = per_cpu(policy_cpu, cpu);
+       int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
        BUG_ON(policy_cpu == -1);
        up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
 
 
 /* internal prototypes */
@@ -180,93 +178,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
 
 /*********************************************************************
- *                     UNIFIED DEBUG HELPERS                         *
- *********************************************************************/
-#ifdef CONFIG_CPU_FREQ_DEBUG
-
-/* what part(s) of the CPUfreq subsystem are debugged? */
-static unsigned int debug;
-
-/* is the debug output ratelimit'ed using printk_ratelimit? User can
- * set or modify this value.
- */
-static unsigned int debug_ratelimit = 1;
-
-/* is the printk_ratelimit'ing enabled? It's enabled after a successful
- * loading of a cpufreq driver, temporarily disabled when a new policy
- * is set, and disabled upon cpufreq driver removal
- */
-static unsigned int disable_ratelimit = 1;
-static DEFINE_SPINLOCK(disable_ratelimit_lock);
-
-static void cpufreq_debug_enable_ratelimit(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&disable_ratelimit_lock, flags);
-       if (disable_ratelimit)
-               disable_ratelimit--;
-       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-static void cpufreq_debug_disable_ratelimit(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&disable_ratelimit_lock, flags);
-       disable_ratelimit++;
-       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-void cpufreq_debug_printk(unsigned int type, const char *prefix,
-                       const char *fmt, ...)
-{
-       char s[256];
-       va_list args;
-       unsigned int len;
-       unsigned long flags;
-
-       WARN_ON(!prefix);
-       if (type & debug) {
-               spin_lock_irqsave(&disable_ratelimit_lock, flags);
-               if (!disable_ratelimit && debug_ratelimit
-                                       && !printk_ratelimit()) {
-                       spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-                       return;
-               }
-               spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-
-               len = snprintf(s, 256, KERN_DEBUG "%s: ", prefix);
-
-               va_start(args, fmt);
-               len += vsnprintf(&s[len], (256 - len), fmt, args);
-               va_end(args);
-
-               printk(s);
-
-               WARN_ON(len < 5);
-       }
-}
-EXPORT_SYMBOL(cpufreq_debug_printk);
-
-
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core,"
-                       " 2 to debug drivers, and 4 to debug governors.");
-
-module_param(debug_ratelimit, uint, 0644);
-MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:"
-                                       " set to 0 to disable ratelimiting.");
-
-#else /* !CONFIG_CPU_FREQ_DEBUG */
-
-static inline void cpufreq_debug_enable_ratelimit(void) { return; }
-static inline void cpufreq_debug_disable_ratelimit(void) { return; }
-
-#endif /* CONFIG_CPU_FREQ_DEBUG */
-
-
-/*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
  *********************************************************************/
 
@@ -290,7 +201,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
        if (!l_p_j_ref_freq) {
                l_p_j_ref = loops_per_jiffy;
                l_p_j_ref_freq = ci->old;
-               dprintk("saving %lu as reference value for loops_per_jiffy; "
+               pr_debug("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
        if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
@@ -298,7 +209,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
-               dprintk("scaling loops_per_jiffy to %lu "
+               pr_debug("scaling loops_per_jiffy to %lu "
                        "for frequency %u kHz\n", loops_per_jiffy, ci->new);
        }
 }
@@ -325,7 +236,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
        BUG_ON(irqs_disabled());
 
        freqs->flags = cpufreq_driver->flags;
-       dprintk("notification %u of frequency transition to %u kHz\n",
+       pr_debug("notification %u of frequency transition to %u kHz\n",
                state, freqs->new);
 
        policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
@@ -339,7 +250,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
                if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
                        if ((policy) && (policy->cpu == freqs->cpu) &&
                            (policy->cur) && (policy->cur != freqs->old)) {
-                               dprintk("Warning: CPU frequency is"
+                               pr_debug("Warning: CPU frequency is"
                                        " %u, cpufreq assumed %u kHz.\n",
                                        freqs->old, policy->cur);
                                freqs->old = policy->cur;
@@ -352,6 +263,10 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
 
        case CPUFREQ_POSTCHANGE:
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+               pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
+                       (unsigned long)freqs->cpu);
+               trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
+               trace_cpu_frequency(freqs->new, freqs->cpu);
                srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
                                CPUFREQ_POSTCHANGE, freqs);
                if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -406,21 +321,14 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
                t = __find_governor(str_governor);
 
                if (t == NULL) {
-                       char *name = kasprintf(GFP_KERNEL, "cpufreq_%s",
-                                                               str_governor);
-
-                       if (name) {
-                               int ret;
+                       int ret;
 
-                               mutex_unlock(&cpufreq_governor_mutex);
-                               ret = request_module("%s", name);
-                               mutex_lock(&cpufreq_governor_mutex);
+                       mutex_unlock(&cpufreq_governor_mutex);
+                       ret = request_module("cpufreq_%s", str_governor);
+                       mutex_lock(&cpufreq_governor_mutex);
 
-                               if (ret == 0)
-                                       t = __find_governor(str_governor);
-                       }
-
-                       kfree(name);
+                       if (ret == 0)
+                               t = __find_governor(str_governor);
                }
 
                if (t != NULL) {
@@ -645,31 +553,35 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
        return policy->governor->show_setspeed(policy, buf);
 }
 
-#define define_one_ro(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-#define define_one_ro0400(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0400, show_##_name, NULL)
-
-#define define_one_rw(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_ro0400(cpuinfo_cur_freq);
-define_one_ro(cpuinfo_min_freq);
-define_one_ro(cpuinfo_max_freq);
-define_one_ro(cpuinfo_transition_latency);
-define_one_ro(scaling_available_governors);
-define_one_ro(scaling_driver);
-define_one_ro(scaling_cur_freq);
-define_one_ro(related_cpus);
-define_one_ro(affected_cpus);
-define_one_rw(scaling_min_freq);
-define_one_rw(scaling_max_freq);
-define_one_rw(scaling_governor);
-define_one_rw(scaling_setspeed);
+/**
+ * show_scaling_driver - show the current cpufreq HW/BIOS limitation
+ */
+static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf)
+{
+       unsigned int limit;
+       int ret;
+       if (cpufreq_driver->bios_limit) {
+               ret = cpufreq_driver->bios_limit(policy->cpu, &limit);
+               if (!ret)
+                       return sprintf(buf, "%u\n", limit);
+       }
+       return sprintf(buf, "%u\n", policy->cpuinfo.max_freq);
+}
+
+cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400);
+cpufreq_freq_attr_ro(cpuinfo_min_freq);
+cpufreq_freq_attr_ro(cpuinfo_max_freq);
+cpufreq_freq_attr_ro(cpuinfo_transition_latency);
+cpufreq_freq_attr_ro(scaling_available_governors);
+cpufreq_freq_attr_ro(scaling_driver);
+cpufreq_freq_attr_ro(scaling_cur_freq);
+cpufreq_freq_attr_ro(bios_limit);
+cpufreq_freq_attr_ro(related_cpus);
+cpufreq_freq_attr_ro(affected_cpus);
+cpufreq_freq_attr_rw(scaling_min_freq);
+cpufreq_freq_attr_rw(scaling_max_freq);
+cpufreq_freq_attr_rw(scaling_governor);
+cpufreq_freq_attr_rw(scaling_setspeed);
 
 static struct attribute *default_attrs[] = {
        &cpuinfo_min_freq.attr,
@@ -686,6 +598,9 @@ static struct attribute *default_attrs[] = {
        NULL
 };
 
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
 #define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
 #define to_attr(a) container_of(a, struct freq_attr, attr)
 
@@ -741,11 +656,11 @@ no_policy:
 static void cpufreq_sysfs_release(struct kobject *kobj)
 {
        struct cpufreq_policy *policy = to_policy(kobj);
-       dprintk("last reference is dropped\n");
+       pr_debug("last reference is dropped\n");
        complete(&policy->kobj_unregister);
 }
 
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
        .show   = show,
        .store  = store,
 };
@@ -756,96 +671,27 @@ static struct kobj_type ktype_cpufreq = {
        .release        = cpufreq_sysfs_release,
 };
 
-
-/**
- * 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
+/*
+ * Returns:
+ *   Negative: Failure
+ *   0:        Success
+ *   Positive: When we have a managed CPU and the sysfs got symlinked
  */
-static int cpufreq_add_dev(struct sys_device *sys_dev)
+static int cpufreq_add_dev_policy(unsigned int cpu,
+                                 struct cpufreq_policy *policy,
+                                 struct sys_device *sys_dev)
 {
-       unsigned int cpu = sys_dev->id;
        int ret = 0;
-       struct cpufreq_policy new_policy;
-       struct cpufreq_policy *policy;
-       struct freq_attr **drv_attr;
-       struct sys_device *cpu_sys_dev;
+#ifdef CONFIG_SMP
        unsigned long flags;
        unsigned int j;
-
-       if (cpu_is_offline(cpu))
-               return 0;
-
-       cpufreq_debug_disable_ratelimit();
-       dprintk("adding CPU %u\n", cpu);
-
-#ifdef CONFIG_SMP
-       /* check whether a different CPU already registered this
-        * CPU because it is in the same boat. */
-       policy = cpufreq_cpu_get(cpu);
-       if (unlikely(policy)) {
-               cpufreq_cpu_put(policy);
-               cpufreq_debug_enable_ratelimit();
-               return 0;
-       }
-#endif
-
-       if (!try_module_get(cpufreq_driver->owner)) {
-               ret = -EINVAL;
-               goto module_out;
-       }
-
-       policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
-       if (!policy) {
-               ret = -ENOMEM;
-               goto nomem_out;
-       }
-       if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto err_free_policy;
-       }
-       if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto err_free_cpumask;
-       }
-
-       policy->cpu = cpu;
-       cpumask_copy(policy->cpus, cpumask_of(cpu));
-
-       /* Initially set CPU itself as the policy_cpu */
-       per_cpu(policy_cpu, cpu) = cpu;
-       ret = (lock_policy_rwsem_write(cpu) < 0);
-       WARN_ON(ret);
-
-       init_completion(&policy->kobj_unregister);
-       INIT_WORK(&policy->update, handle_update);
-
-       /* Set governor before ->init, so that driver could check it */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-       /* call driver. From then on the cpufreq must be able
-        * to accept all calls to ->verify and ->setpolicy for this CPU
-        */
-       ret = cpufreq_driver->init(policy);
-       if (ret) {
-               dprintk("initialization failed\n");
-               goto err_unlock_policy;
-       }
-       policy->user_policy.min = policy->min;
-       policy->user_policy.max = policy->max;
-
-       blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-                                    CPUFREQ_START, policy);
-
-#ifdef CONFIG_SMP
-
 #ifdef CONFIG_HOTPLUG_CPU
-       if (per_cpu(cpufreq_cpu_governor, cpu)) {
-               policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
-               dprintk("Restoring governor %s for cpu %d\n",
+       struct cpufreq_governor *gov;
+
+       gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
+       if (gov) {
+               policy->governor = gov;
+               pr_debug("Restoring governor %s for cpu %d\n",
                       policy->governor->name, cpu);
        }
 #endif
@@ -858,21 +704,22 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
                /* Check for existing affected CPUs.
                 * They may not be aware of it due to CPU Hotplug.
+                * cpufreq_cpu_put is called when the device is removed
+                * in __cpufreq_remove_dev()
                 */
                managed_policy = cpufreq_cpu_get(j);
                if (unlikely(managed_policy)) {
 
                        /* Set proper policy_cpu */
                        unlock_policy_rwsem_write(cpu);
-                       per_cpu(policy_cpu, cpu) = managed_policy->cpu;
+                       per_cpu(cpufreq_policy_cpu, cpu) = managed_policy->cpu;
 
                        if (lock_policy_rwsem_write(cpu) < 0) {
                                /* Should not go through policy unlock path */
                                if (cpufreq_driver->exit)
                                        cpufreq_driver->exit(policy);
-                               ret = -EBUSY;
                                cpufreq_cpu_put(managed_policy);
-                               goto err_free_cpumask;
+                               return -EBUSY;
                        }
 
                        spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -880,28 +727,75 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
                        per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
                        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-                       dprintk("CPU already managed, adding link\n");
+                       pr_debug("CPU already managed, adding link\n");
                        ret = sysfs_create_link(&sys_dev->kobj,
                                                &managed_policy->kobj,
                                                "cpufreq");
-                       if (!ret)
+                       if (ret)
                                cpufreq_cpu_put(managed_policy);
                        /*
                         * Success. We only needed to be added to the mask.
                         * Call driver->exit() because only the cpu parent of
                         * the kobj needed to call init().
                         */
-                       goto out_driver_exit; /* call driver->exit() */
+                       if (cpufreq_driver->exit)
+                               cpufreq_driver->exit(policy);
+
+                       if (!ret)
+                               return 1;
+                       else
+                               return ret;
                }
        }
 #endif
-       memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+       return ret;
+}
+
+
+/* symlink affected CPUs */
+static int cpufreq_add_dev_symlink(unsigned int cpu,
+                                  struct cpufreq_policy *policy)
+{
+       unsigned int j;
+       int ret = 0;
+
+       for_each_cpu(j, policy->cpus) {
+               struct cpufreq_policy *managed_policy;
+               struct sys_device *cpu_sys_dev;
+
+               if (j == cpu)
+                       continue;
+               if (!cpu_online(j))
+                       continue;
+
+               pr_debug("CPU %u already managed, adding link\n", j);
+               managed_policy = cpufreq_cpu_get(cpu);
+               cpu_sys_dev = get_cpu_sysdev(j);
+               ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
+                                       "cpufreq");
+               if (ret) {
+                       cpufreq_cpu_put(managed_policy);
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+static int cpufreq_add_dev_interface(unsigned int cpu,
+                                    struct cpufreq_policy *policy,
+                                    struct sys_device *sys_dev)
+{
+       struct cpufreq_policy new_policy;
+       struct freq_attr **drv_attr;
+       unsigned long flags;
+       int ret = 0;
+       unsigned int j;
 
        /* prepare interface data */
-       ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
-                                  "cpufreq");
+       ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+                                  &sys_dev->kobj, "cpufreq");
        if (ret)
-               goto out_driver_exit;
+               return ret;
 
        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
@@ -921,36 +815,28 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
                if (ret)
                        goto err_out_kobj_put;
        }
+       if (cpufreq_driver->bios_limit) {
+               ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
+               if (ret)
+                       goto err_out_kobj_put;
+       }
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu(j, policy->cpus) {
+               if (!cpu_online(j))
+                       continue;
                per_cpu(cpufreq_cpu_data, j) = policy;
-               per_cpu(policy_cpu, j) = policy->cpu;
+               per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       /* symlink affected CPUs */
-       for_each_cpu(j, policy->cpus) {
-               struct cpufreq_policy *managed_policy;
-
-               if (j == cpu)
-                       continue;
-               if (!cpu_online(j))
-                       continue;
-
-               dprintk("CPU %u already managed, adding link\n", j);
-               managed_policy = cpufreq_cpu_get(cpu);
-               cpu_sys_dev = get_cpu_sysdev(j);
-               ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
-                                       "cpufreq");
-               if (ret) {
-                       cpufreq_cpu_put(managed_policy);
-                       goto err_out_unregister;
-               }
-       }
+       ret = cpufreq_add_dev_symlink(cpu, policy);
+       if (ret)
+               goto err_out_kobj_put;
 
-       policy->governor = NULL; /* to assure that the starting sequence is
-                                 * run in cpufreq_set_policy */
+       memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+       /* assure that the starting sequence is run in __cpufreq_set_policy */
+       policy->governor = NULL;
 
        /* set default policy */
        ret = __cpufreq_set_policy(policy, &new_policy);
@@ -958,16 +844,127 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
        policy->user_policy.governor = policy->governor;
 
        if (ret) {
-               dprintk("setting policy failed\n");
-               goto err_out_unregister;
+               pr_debug("setting policy failed\n");
+               if (cpufreq_driver->exit)
+                       cpufreq_driver->exit(policy);
        }
+       return ret;
+
+err_out_kobj_put:
+       kobject_put(&policy->kobj);
+       wait_for_completion(&policy->kobj_unregister);
+       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 sys_device *sys_dev)
+{
+       unsigned int cpu = sys_dev->id;
+       int ret = 0, found = 0;
+       struct cpufreq_policy *policy;
+       unsigned long flags;
+       unsigned int j;
+#ifdef CONFIG_HOTPLUG_CPU
+       int sibling;
+#endif
+
+       if (cpu_is_offline(cpu))
+               return 0;
+
+       pr_debug("adding CPU %u\n", cpu);
+
+#ifdef CONFIG_SMP
+       /* check whether a different CPU already registered this
+        * CPU because it is in the same boat. */
+       policy = cpufreq_cpu_get(cpu);
+       if (unlikely(policy)) {
+               cpufreq_cpu_put(policy);
+               return 0;
+       }
+#endif
+
+       if (!try_module_get(cpufreq_driver->owner)) {
+               ret = -EINVAL;
+               goto module_out;
+       }
+
+       ret = -ENOMEM;
+       policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+       if (!policy)
+               goto nomem_out;
+
+       if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+               goto err_free_policy;
+
+       if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+               goto err_free_cpumask;
+
+       policy->cpu = cpu;
+       cpumask_copy(policy->cpus, cpumask_of(cpu));
+
+       /* Initially set CPU itself as the policy_cpu */
+       per_cpu(cpufreq_policy_cpu, cpu) = cpu;
+       ret = (lock_policy_rwsem_write(cpu) < 0);
+       WARN_ON(ret);
+
+       init_completion(&policy->kobj_unregister);
+       INIT_WORK(&policy->update, handle_update);
+
+       /* Set governor before ->init, so that driver could check it */
+#ifdef CONFIG_HOTPLUG_CPU
+       for_each_online_cpu(sibling) {
+               struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+               if (cp && cp->governor &&
+                   (cpumask_test_cpu(cpu, cp->related_cpus))) {
+                       policy->governor = cp->governor;
+                       found = 1;
+                       break;
+               }
+       }
+#endif
+       if (!found)
+               policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+       /* call driver. From then on the cpufreq must be able
+        * to accept all calls to ->verify and ->setpolicy for this CPU
+        */
+       ret = cpufreq_driver->init(policy);
+       if (ret) {
+               pr_debug("initialization failed\n");
+               goto err_unlock_policy;
+       }
+       policy->user_policy.min = policy->min;
+       policy->user_policy.max = policy->max;
+
+       blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+                                    CPUFREQ_START, policy);
+
+       ret = cpufreq_add_dev_policy(cpu, policy, sys_dev);
+       if (ret) {
+               if (ret > 0)
+                       /* This is a managed cpu, symlink created,
+                          exit with 0 */
+                       ret = 0;
+               goto err_unlock_policy;
+       }
+
+       ret = cpufreq_add_dev_interface(cpu, policy, sys_dev);
+       if (ret)
+               goto err_out_unregister;
 
        unlock_policy_rwsem_write(cpu);
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        module_put(cpufreq_driver->owner);
-       dprintk("initialization complete\n");
-       cpufreq_debug_enable_ratelimit();
+       pr_debug("initialization complete\n");
 
        return 0;
 
@@ -978,16 +975,12 @@ err_out_unregister:
                per_cpu(cpufreq_cpu_data, j) = NULL;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-err_out_kobj_put:
        kobject_put(&policy->kobj);
        wait_for_completion(&policy->kobj_unregister);
 
-out_driver_exit:
-       if (cpufreq_driver->exit)
-               cpufreq_driver->exit(policy);
-
 err_unlock_policy:
        unlock_policy_rwsem_write(cpu);
+       free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
        free_cpumask_var(policy->cpus);
 err_free_policy:
@@ -995,7 +988,6 @@ err_free_policy:
 nomem_out:
        module_put(cpufreq_driver->owner);
 module_out:
-       cpufreq_debug_enable_ratelimit();
        return ret;
 }
 
@@ -1012,20 +1004,20 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        unsigned int cpu = sys_dev->id;
        unsigned long flags;
        struct cpufreq_policy *data;
+       struct kobject *kobj;
+       struct completion *cmp;
 #ifdef CONFIG_SMP
        struct sys_device *cpu_sys_dev;
        unsigned int j;
 #endif
 
-       cpufreq_debug_disable_ratelimit();
-       dprintk("unregistering CPU %u\n", cpu);
+       pr_debug("unregistering CPU %u\n", cpu);
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        data = per_cpu(cpufreq_cpu_data, cpu);
 
        if (!data) {
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-               cpufreq_debug_enable_ratelimit();
                unlock_policy_rwsem_write(cpu);
                return -EINVAL;
        }
@@ -1037,13 +1029,13 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
         * only need to unlink, put and exit
         */
        if (unlikely(cpu != data->cpu)) {
-               dprintk("removing link\n");
+               pr_debug("removing link\n");
                cpumask_clear_cpu(cpu, data->cpus);
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-               sysfs_remove_link(&sys_dev->kobj, "cpufreq");
+               kobj = &sys_dev->kobj;
                cpufreq_cpu_put(data);
-               cpufreq_debug_enable_ratelimit();
                unlock_policy_rwsem_write(cpu);
+               sysfs_remove_link(kobj, "cpufreq");
                return 0;
        }
 #endif
@@ -1051,7 +1043,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
 #ifdef CONFIG_SMP
 
 #ifdef CONFIG_HOTPLUG_CPU
-       per_cpu(cpufreq_cpu_governor, cpu) = data->governor;
+       strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
+                       CPUFREQ_NAME_LEN);
 #endif
 
        /* if we have other CPUs still registered, we need to unlink them,
@@ -1073,12 +1066,16 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
                for_each_cpu(j, data->cpus) {
                        if (j == cpu)
                                continue;
-                       dprintk("removing link for cpu %u\n", j);
+                       pr_debug("removing link for cpu %u\n", j);
 #ifdef CONFIG_HOTPLUG_CPU
-                       per_cpu(cpufreq_cpu_governor, j) = data->governor;
+                       strncpy(per_cpu(cpufreq_cpu_governor, j),
+                               data->governor->name, CPUFREQ_NAME_LEN);
 #endif
                        cpu_sys_dev = get_cpu_sysdev(j);
-                       sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
+                       kobj = &cpu_sys_dev->kobj;
+                       unlock_policy_rwsem_write(cpu);
+                       sysfs_remove_link(kobj, "cpufreq");
+                       lock_policy_rwsem_write(cpu);
                        cpufreq_cpu_put(data);
                }
        }
@@ -1089,27 +1086,44 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        if (cpufreq_driver->target)
                __cpufreq_governor(data, CPUFREQ_GOV_STOP);
 
-       kobject_put(&data->kobj);
+       kobj = &data->kobj;
+       cmp = &data->kobj_unregister;
+       unlock_policy_rwsem_write(cpu);
+       kobject_put(kobj);
 
        /* we need to make sure that the underlying kobj is actually
         * not referenced anymore by anybody before we proceed with
         * unloading.
         */
-       dprintk("waiting for dropping of refcount\n");
-       wait_for_completion(&data->kobj_unregister);
-       dprintk("wait complete\n");
+       pr_debug("waiting for dropping of refcount\n");
+       wait_for_completion(cmp);
+       pr_debug("wait complete\n");
 
+       lock_policy_rwsem_write(cpu);
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(data);
-
        unlock_policy_rwsem_write(cpu);
 
+#ifdef CONFIG_HOTPLUG_CPU
+       /* when the CPU which is the parent of the kobj is hotplugged
+        * offline, check for siblings, and create cpufreq sysfs interface
+        * and symlinks
+        */
+       if (unlikely(cpumask_weight(data->cpus) > 1)) {
+               /* first sibling now owns the new sysfs dir */
+               cpumask_clear_cpu(cpu, data->cpus);
+               cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus)));
+
+               /* finally remove our own symlink */
+               lock_policy_rwsem_write(cpu);
+               __cpufreq_remove_dev(sys_dev);
+       }
+#endif
+
        free_cpumask_var(data->related_cpus);
        free_cpumask_var(data->cpus);
        kfree(data);
-       per_cpu(cpufreq_cpu_data, cpu) = NULL;
 
-       cpufreq_debug_enable_ratelimit();
        return 0;
 }
 
@@ -1135,7 +1149,7 @@ static void handle_update(struct work_struct *work)
        struct cpufreq_policy *policy =
                container_of(work, struct cpufreq_policy, update);
        unsigned int cpu = policy->cpu;
-       dprintk("handle_update for cpu %u called\n", cpu);
+       pr_debug("handle_update for cpu %u called\n", cpu);
        cpufreq_update_policy(cpu);
 }
 
@@ -1153,7 +1167,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
 {
        struct cpufreq_freqs freqs;
 
-       dprintk("Warning: CPU frequency out of sync: cpufreq and timing "
+       pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
               "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
 
        freqs.cpu = cpu;
@@ -1185,6 +1199,26 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_quick_get);
 
+/**
+ * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU
+ * @cpu: CPU number
+ *
+ * Just return the max possible frequency for a given CPU.
+ */
+unsigned int cpufreq_quick_get_max(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       unsigned int ret_freq = 0;
+
+       if (policy) {
+               ret_freq = policy->max;
+               cpufreq_cpu_put(policy);
+       }
+
+       return ret_freq;
+}
+EXPORT_SYMBOL(cpufreq_quick_get_max);
+
 
 static unsigned int __cpufreq_get(unsigned int cpu)
 {
@@ -1237,112 +1271,69 @@ out:
 }
 EXPORT_SYMBOL(cpufreq_get);
 
+static struct sysdev_driver cpufreq_sysdev_driver = {
+       .add            = cpufreq_add_dev,
+       .remove         = cpufreq_remove_dev,
+};
+
 
 /**
- *     cpufreq_suspend - let the low level driver prepare for suspend
+ * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
+ *
+ * This function is only executed for the boot processor.  The other CPUs
+ * have been put offline by means of CPU hotplug.
  */
-
-static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
+static int cpufreq_bp_suspend(void)
 {
-       int cpu = sysdev->id;
        int ret = 0;
-       unsigned int cur_freq = 0;
-       struct cpufreq_policy *cpu_policy;
-
-       dprintk("suspending cpu %u\n", cpu);
 
-       if (!cpu_online(cpu))
-               return 0;
+       int cpu = smp_processor_id();
+       struct cpufreq_policy *cpu_policy;
 
-       /* we may be lax here as interrupts are off. Nonetheless
-        * we need to grab the correct cpu policy, as to check
-        * whether we really run on this CPU.
-        */
+       pr_debug("suspending cpu %u\n", cpu);
 
+       /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
        if (!cpu_policy)
-               return -EINVAL;
-
-       /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu))
-               goto out;
+               return 0;
 
        if (cpufreq_driver->suspend) {
-               ret = cpufreq_driver->suspend(cpu_policy, pmsg);
-               if (ret) {
+               ret = cpufreq_driver->suspend(cpu_policy);
+               if (ret)
                        printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
                                        "step on CPU %u\n", cpu_policy->cpu);
-                       goto out;
-               }
        }
 
-       if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
-               goto out;
-
-       if (cpufreq_driver->get)
-               cur_freq = cpufreq_driver->get(cpu_policy->cpu);
-
-       if (!cur_freq || !cpu_policy->cur) {
-               printk(KERN_ERR "cpufreq: suspend failed to assert current "
-                      "frequency is what timing core thinks it is.\n");
-               goto out;
-       }
-
-       if (unlikely(cur_freq != cpu_policy->cur)) {
-               struct cpufreq_freqs freqs;
-
-               if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
-                       dprintk("Warning: CPU frequency is %u, "
-                              "cpufreq assumed %u kHz.\n",
-                              cur_freq, cpu_policy->cur);
-
-               freqs.cpu = cpu;
-               freqs.old = cpu_policy->cur;
-               freqs.new = cur_freq;
-
-               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
-                                   CPUFREQ_SUSPENDCHANGE, &freqs);
-               adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
-
-               cpu_policy->cur = cur_freq;
-       }
-
-out:
        cpufreq_cpu_put(cpu_policy);
        return ret;
 }
 
 /**
- *     cpufreq_resume -  restore proper CPU frequency handling after resume
+ * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
  *
  *     1.) resume CPUfreq hardware support (cpufreq_driver->resume())
- *     2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
- *     3.) schedule call cpufreq_update_policy() ASAP as interrupts are
- *         restored.
+ *     2.) schedule call cpufreq_update_policy() ASAP as interrupts are
+ *         restored. It will verify that the current freq is in sync with
+ *         what we believe it to be. This is a bit later than when it
+ *         should be, but nonethteless it's better than calling
+ *         cpufreq_driver->get() here which might re-enable interrupts...
+ *
+ * This function is only executed for the boot CPU.  The other CPUs have not
+ * been turned on yet.
  */
-static int cpufreq_resume(struct sys_device *sysdev)
+static void cpufreq_bp_resume(void)
 {
-       int cpu = sysdev->id;
        int ret = 0;
-       struct cpufreq_policy *cpu_policy;
 
-       dprintk("resuming cpu %u\n", cpu);
-
-       if (!cpu_online(cpu))
-               return 0;
+       int cpu = smp_processor_id();
+       struct cpufreq_policy *cpu_policy;
 
-       /* we may be lax here as interrupts are off. Nonetheless
-        * we need to grab the correct cpu policy, as to check
-        * whether we really run on this CPU.
-        */
+       pr_debug("resuming cpu %u\n", cpu);
 
+       /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
        if (!cpu_policy)
-               return -EINVAL;
-
-       /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu))
-               goto fail;
+               return;
 
        if (cpufreq_driver->resume) {
                ret = cpufreq_driver->resume(cpu_policy);
@@ -1353,52 +1344,15 @@ static int cpufreq_resume(struct sys_device *sysdev)
                }
        }
 
-       if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
-               unsigned int cur_freq = 0;
-
-               if (cpufreq_driver->get)
-                       cur_freq = cpufreq_driver->get(cpu_policy->cpu);
-
-               if (!cur_freq || !cpu_policy->cur) {
-                       printk(KERN_ERR "cpufreq: resume failed to assert "
-                                       "current frequency is what timing core "
-                                       "thinks it is.\n");
-                       goto out;
-               }
-
-               if (unlikely(cur_freq != cpu_policy->cur)) {
-                       struct cpufreq_freqs freqs;
-
-                       if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
-                               dprintk("Warning: CPU frequency "
-                                      "is %u, cpufreq assumed %u kHz.\n",
-                                      cur_freq, cpu_policy->cur);
-
-                       freqs.cpu = cpu;
-                       freqs.old = cpu_policy->cur;
-                       freqs.new = cur_freq;
-
-                       srcu_notifier_call_chain(
-                                       &cpufreq_transition_notifier_list,
-                                       CPUFREQ_RESUMECHANGE, &freqs);
-                       adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
-
-                       cpu_policy->cur = cur_freq;
-               }
-       }
-
-out:
        schedule_work(&cpu_policy->update);
+
 fail:
        cpufreq_cpu_put(cpu_policy);
-       return ret;
 }
 
-static struct sysdev_driver cpufreq_sysdev_driver = {
-       .add            = cpufreq_add_dev,
-       .remove         = cpufreq_remove_dev,
-       .suspend        = cpufreq_suspend,
-       .resume         = cpufreq_resume,
+static struct syscore_ops cpufreq_syscore_ops = {
+       .suspend        = cpufreq_bp_suspend,
+       .resume         = cpufreq_bp_resume,
 };
 
 
@@ -1486,7 +1440,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 {
        int retval = -EINVAL;
 
-       dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
+       pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
                target_freq, relation);
        if (cpu_online(policy->cpu) && cpufreq_driver->target)
                retval = cpufreq_driver->target(policy, target_freq, relation);
@@ -1572,7 +1526,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        if (!try_module_get(policy->governor->owner))
                return -EINVAL;
 
-       dprintk("__cpufreq_governor for CPU %u, event %u\n",
+       pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
        ret = policy->governor->governor(policy, event);
 
@@ -1610,9 +1564,22 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
 void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 {
+#ifdef CONFIG_HOTPLUG_CPU
+       int cpu;
+#endif
+
        if (!governor)
                return;
 
+#ifdef CONFIG_HOTPLUG_CPU
+       for_each_present_cpu(cpu) {
+               if (cpu_online(cpu))
+                       continue;
+               if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
+                       strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
+       }
+#endif
+
        mutex_lock(&cpufreq_governor_mutex);
        list_del(&governor->governor_list);
        mutex_unlock(&cpufreq_governor_mutex);
@@ -1660,8 +1627,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
 {
        int ret = 0;
 
-       cpufreq_debug_disable_ratelimit();
-       dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
+       pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
                policy->min, policy->max);
 
        memcpy(&policy->cpuinfo, &data->cpuinfo,
@@ -1698,19 +1664,19 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
        data->min = policy->min;
        data->max = policy->max;
 
-       dprintk("new min and max freqs are %u - %u kHz\n",
+       pr_debug("new min and max freqs are %u - %u kHz\n",
                                        data->min, data->max);
 
        if (cpufreq_driver->setpolicy) {
                data->policy = policy->policy;
-               dprintk("setting range\n");
+               pr_debug("setting range\n");
                ret = cpufreq_driver->setpolicy(policy);
        } else {
                if (policy->governor != data->governor) {
                        /* save old, working values */
                        struct cpufreq_governor *old_gov = data->governor;
 
-                       dprintk("governor switch\n");
+                       pr_debug("governor switch\n");
 
                        /* end old governor */
                        if (data->governor)
@@ -1720,7 +1686,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
                        data->governor = policy->governor;
                        if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
                                /* new governor failed, so re-start old one */
-                               dprintk("starting governor %s failed\n",
+                               pr_debug("starting governor %s failed\n",
                                                        data->governor->name);
                                if (old_gov) {
                                        data->governor = old_gov;
@@ -1732,12 +1698,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
                        }
                        /* might be a policy change, too, so fall through */
                }
-               dprintk("governor: change or update limits\n");
+               pr_debug("governor: change or update limits\n");
                __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
        }
 
 error_out:
-       cpufreq_debug_enable_ratelimit();
        return ret;
 }
 
@@ -1745,7 +1710,7 @@ error_out:
  *     cpufreq_update_policy - re-evaluate an existing cpufreq policy
  *     @cpu: CPU which shall be re-evaluated
  *
- *     Usefull for policy notifiers which have different necessities
+ *     Useful for policy notifiers which have different necessities
  *     at different times.
  */
 int cpufreq_update_policy(unsigned int cpu)
@@ -1764,7 +1729,7 @@ int cpufreq_update_policy(unsigned int cpu)
                goto fail;
        }
 
-       dprintk("updating policy for CPU %u\n", cpu);
+       pr_debug("updating policy for CPU %u\n", cpu);
        memcpy(&policy, data, sizeof(struct cpufreq_policy));
        policy.min = data->user_policy.min;
        policy.max = data->user_policy.max;
@@ -1776,7 +1741,7 @@ int cpufreq_update_policy(unsigned int cpu)
        if (cpufreq_driver->get) {
                policy.cur = cpufreq_driver->get(cpu);
                if (!data->cur) {
-                       dprintk("Driver did not initialize current freq");
+                       pr_debug("Driver did not initialize current freq");
                        data->cur = policy.cur;
                } else {
                        if (data->cur != policy.cur)
@@ -1825,8 +1790,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __refdata cpufreq_cpu_notifier =
-{
+static struct notifier_block __refdata cpufreq_cpu_notifier = {
     .notifier_call = cpufreq_cpu_callback,
 };
 
@@ -1834,6 +1798,20 @@ static struct notifier_block __refdata cpufreq_cpu_notifier =
  *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
  *********************************************************************/
 
+static char cpufreq_driver_name[CPUFREQ_NAME_LEN];
+
+static int __init cpufreq_driver_setup(char *str)
+{
+       strlcpy(cpufreq_driver_name, str, CPUFREQ_NAME_LEN);
+       return 1;
+}
+
+/*
+ * Set this name to only allow one specific cpu freq driver, e.g.,
+ * cpufreq_driver=powernow-k8
+ */
+__setup("cpufreq_driver=", cpufreq_driver_setup);
+
 /**
  * cpufreq_register_driver - register a CPU Frequency driver
  * @driver_data: A struct cpufreq_driver containing the values#
@@ -1853,7 +1831,13 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
            ((!driver_data->setpolicy) && (!driver_data->target)))
                return -EINVAL;
 
-       dprintk("trying to register driver %s\n", driver_data->name);
+       pr_debug("trying to register driver %s, cpufreq_driver=%s\n",
+               driver_data->name, cpufreq_driver_name);
+
+       if (cpufreq_driver_name[0])
+               if (!driver_data->name ||
+                       strcmp(cpufreq_driver_name, driver_data->name))
+                               return -EINVAL;
 
        if (driver_data->setpolicy)
                driver_data->flags |= CPUFREQ_CONST_LOOPS;
@@ -1868,8 +1852,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
        ret = sysdev_driver_register(&cpu_sysdev_class,
                                        &cpufreq_sysdev_driver);
+       if (ret)
+               goto err_null_driver;
 
-       if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
+       if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
                int i;
                ret = -ENODEV;
 
@@ -1882,23 +1868,23 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
                /* if all ->init() calls failed, unregister */
                if (ret) {
-                       dprintk("no CPU initialized for driver %s\n",
+                       pr_debug("no CPU initialized for driver %s\n",
                                                        driver_data->name);
-                       sysdev_driver_unregister(&cpu_sysdev_class,
-                                               &cpufreq_sysdev_driver);
-
-                       spin_lock_irqsave(&cpufreq_driver_lock, flags);
-                       cpufreq_driver = NULL;
-                       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+                       goto err_sysdev_unreg;
                }
        }
 
-       if (!ret) {
-               register_hotcpu_notifier(&cpufreq_cpu_notifier);
-               dprintk("driver %s up and running\n", driver_data->name);
-               cpufreq_debug_enable_ratelimit();
-       }
+       register_hotcpu_notifier(&cpufreq_cpu_notifier);
+       pr_debug("driver %s up and running\n", driver_data->name);
 
+       return 0;
+err_sysdev_unreg:
+       sysdev_driver_unregister(&cpu_sysdev_class,
+                       &cpufreq_sysdev_driver);
+err_null_driver:
+       spin_lock_irqsave(&cpufreq_driver_lock, flags);
+       cpufreq_driver = NULL;
+       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
@@ -1916,14 +1902,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 {
        unsigned long flags;
 
-       cpufreq_debug_disable_ratelimit();
-
-       if (!cpufreq_driver || (driver != cpufreq_driver)) {
-               cpufreq_debug_enable_ratelimit();
+       if (!cpufreq_driver || (driver != cpufreq_driver))
                return -EINVAL;
-       }
 
-       dprintk("unregistering driver %s\n", driver->name);
+       pr_debug("unregistering driver %s\n", driver->name);
 
        sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
        unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
@@ -1941,10 +1923,15 @@ static int __init cpufreq_core_init(void)
        int cpu;
 
        for_each_possible_cpu(cpu) {
-               per_cpu(policy_cpu, cpu) = -1;
+               per_cpu(cpufreq_policy_cpu, cpu) = -1;
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }
+
+       cpufreq_global_kobject = kobject_create_and_add("cpufreq",
+                                               &cpu_sysdev_class.kset.kobj);
+       BUG_ON(!cpufreq_global_kobject);
+       register_syscore_ops(&cpufreq_syscore_ops);
+
        return 0;
 }
-
 core_initcall(cpufreq_core_init);