[CPUFREQ] change cpu freq arrays to per_cpu variables
[safe/jmp/linux-2.6] / drivers / cpufreq / cpufreq.c
index be78c07..6b73d16 100644 (file)
  * also protects the cpufreq_cpu_data array.
  */
 static struct cpufreq_driver *cpufreq_driver;
-static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
+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 struct cpufreq_governor *cpufreq_cpu_governor[NR_CPUS];
+static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor);
 #endif
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
@@ -118,9 +118,11 @@ static void handle_update(struct work_struct *work);
 static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
 static struct srcu_notifier_head cpufreq_transition_notifier_list;
 
+static bool init_cpufreq_transition_notifier_list_called;
 static int __init init_cpufreq_transition_notifier_list(void)
 {
        srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+       init_cpufreq_transition_notifier_list_called = true;
        return 0;
 }
 pure_initcall(init_cpufreq_transition_notifier_list);
@@ -133,7 +135,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
        struct cpufreq_policy *data;
        unsigned long flags;
 
-       if (cpu >= NR_CPUS)
+       if (cpu >= nr_cpu_ids)
                goto err_out;
 
        /* get the cpufreq driver */
@@ -147,7 +149,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 
 
        /* get the CPU */
-       data = cpufreq_cpu_data[cpu];
+       data = per_cpu(cpufreq_cpu_data, cpu);
 
        if (!data)
                goto err_out_put_module;
@@ -325,7 +327,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
        dprintk("notification %u of frequency transition to %u kHz\n",
                state, freqs->new);
 
-       policy = cpufreq_cpu_data[freqs->cpu];
+       policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
        switch (state) {
 
        case CPUFREQ_PRECHANGE:
@@ -581,15 +583,13 @@ out:
        i += sprintf(&buf[i], "\n");
        return i;
 }
-/**
- * show_affected_cpus - show the CPUs affected by each transition
- */
-static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+
+static ssize_t show_cpus(cpumask_t mask, char *buf)
 {
        ssize_t i = 0;
        unsigned int cpu;
 
-       for_each_cpu_mask(cpu, policy->cpus) {
+       for_each_cpu_mask(cpu, mask) {
                if (i)
                        i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
                i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
@@ -600,6 +600,25 @@ static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
        return i;
 }
 
+/**
+ * show_related_cpus - show the CPUs affected by each transition even if
+ * hw coordination is in use
+ */
+static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
+{
+       if (cpus_empty(policy->related_cpus))
+               return show_cpus(policy->cpus, buf);
+       return show_cpus(policy->related_cpus, buf);
+}
+
+/**
+ * show_affected_cpus - show the CPUs affected by each transition
+ */
+static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+{
+       return show_cpus(policy->cpus, buf);
+}
+
 static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
                                        const char *buf, size_t count)
 {
@@ -644,6 +663,7 @@ define_one_ro(cpuinfo_max_freq);
 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);
@@ -656,6 +676,7 @@ static struct attribute *default_attrs[] = {
        &scaling_min_freq.attr,
        &scaling_max_freq.attr,
        &affected_cpus.attr,
+       &related_cpus.attr,
        &scaling_governor.attr,
        &scaling_driver.attr,
        &scaling_available_governors.attr,
@@ -807,8 +828,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 #ifdef CONFIG_SMP
 
 #ifdef CONFIG_HOTPLUG_CPU
-       if (cpufreq_cpu_governor[cpu]){
-               policy->governor = cpufreq_cpu_governor[cpu];
+       if (per_cpu(cpufreq_cpu_governor, cpu)) {
+               policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
                dprintk("Restoring governor %s for cpu %d\n",
                       policy->governor->name, cpu);
        }
@@ -833,7 +854,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
                        spin_lock_irqsave(&cpufreq_driver_lock, flags);
                        managed_policy->cpus = policy->cpus;
-                       cpufreq_cpu_data[cpu] = managed_policy;
+                       per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
                        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
                        dprintk("CPU already managed, adding link\n");
@@ -878,7 +899,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu_mask(j, policy->cpus) {
-               cpufreq_cpu_data[j] = policy;
+               per_cpu(cpufreq_cpu_data, j) = policy;
                per_cpu(policy_cpu, j) = policy->cpu;
        }
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -925,7 +946,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 err_out_unregister:
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu_mask(j, policy->cpus)
-               cpufreq_cpu_data[j] = NULL;
+               per_cpu(cpufreq_cpu_data, j) = NULL;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        kobject_put(&policy->kobj);
@@ -968,7 +989,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
        dprintk("unregistering CPU %u\n", cpu);
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
-       data = cpufreq_cpu_data[cpu];
+       data = per_cpu(cpufreq_cpu_data, cpu);
 
        if (!data) {
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -976,7 +997,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
                unlock_policy_rwsem_write(cpu);
                return -EINVAL;
        }
-       cpufreq_cpu_data[cpu] = NULL;
+       per_cpu(cpufreq_cpu_data, cpu) = NULL;
 
 
 #ifdef CONFIG_SMP
@@ -998,19 +1019,19 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
 #ifdef CONFIG_SMP
 
 #ifdef CONFIG_HOTPLUG_CPU
-       cpufreq_cpu_governor[cpu] = data->governor;
+       per_cpu(cpufreq_cpu_governor, cpu) = data->governor;
 #endif
 
        /* if we have other CPUs still registered, we need to unlink them,
         * or else wait_for_completion below will lock up. Clean the
-        * cpufreq_cpu_data[] while holding the lock, and remove the sysfs
-        * links afterwards.
+        * per_cpu(cpufreq_cpu_data) while holding the lock, and remove
+        * the sysfs links afterwards.
         */
        if (unlikely(cpus_weight(data->cpus) > 1)) {
                for_each_cpu_mask(j, data->cpus) {
                        if (j == cpu)
                                continue;
-                       cpufreq_cpu_data[j] = NULL;
+                       per_cpu(cpufreq_cpu_data, j) = NULL;
                }
        }
 
@@ -1022,7 +1043,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
                                continue;
                        dprintk("removing link for cpu %u\n", j);
 #ifdef CONFIG_HOTPLUG_CPU
-                       cpufreq_cpu_governor[j] = data->governor;
+                       per_cpu(cpufreq_cpu_governor, j) = data->governor;
 #endif
                        cpu_sys_dev = get_cpu_sysdev(j);
                        sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
@@ -1132,7 +1153,7 @@ EXPORT_SYMBOL(cpufreq_quick_get);
 
 static unsigned int __cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_policy *policy = cpufreq_cpu_data[cpu];
+       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
        unsigned int ret_freq = 0;
 
        if (!cpufreq_driver->get)
@@ -1367,6 +1388,8 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
 {
        int ret;
 
+       WARN_ON(!init_cpufreq_transition_notifier_list_called);
+
        switch (list) {
        case CPUFREQ_TRANSITION_NOTIFIER:
                ret = srcu_notifier_chain_register(
@@ -1799,16 +1822,19 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        cpufreq_driver = driver_data;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
+       ret = sysdev_driver_register(&cpu_sysdev_class,
+                                       &cpufreq_sysdev_driver);
 
        if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
                int i;
                ret = -ENODEV;
 
                /* check for at least one working CPU */
-               for (i=0; i<NR_CPUS; i++)
-                       if (cpufreq_cpu_data[i])
+               for (i = 0; i < nr_cpu_ids; i++)
+                       if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
                                ret = 0;
+                               break;
+                       }
 
                /* if all ->init() calls failed, unregister */
                if (ret) {