]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/cpufreq/cpufreq.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
[linux-2.6.git] / drivers / cpufreq / cpufreq.c
index 89a29cd9378379a00f80e6899eadbac949f03fde..7fce038fa57e6413892679f6c8ca7256aeedafa3 100644 (file)
@@ -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);
@@ -216,7 +218,7 @@ static void cpufreq_debug_disable_ratelimit(void)
 }
 
 void cpufreq_debug_printk(unsigned int type, const char *prefix,
-                                                       const char *fmt, ...)
+                       const char *fmt, ...)
 {
        char s[256];
        va_list args;
@@ -378,7 +380,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
 /**
  * cpufreq_parse_governor - parse a governor string
  */
-static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
+static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
                                struct cpufreq_governor **governor)
 {
        int err = -EINVAL;
@@ -446,7 +448,7 @@ extern struct sysdev_class cpu_sysdev_class;
 
 #define show_one(file_name, object)                    \
 static ssize_t show_##file_name                                \
-(struct cpufreq_policy * policy, char *buf)            \
+(struct cpufreq_policy *policy, char *buf)             \
 {                                                      \
        return sprintf (buf, "%u\n", policy->object);   \
 }
@@ -465,7 +467,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
  */
 #define store_one(file_name, object)                   \
 static ssize_t store_##file_name                                       \
-(struct cpufreq_policy * policy, const char *buf, size_t count)                \
+(struct cpufreq_policy *policy, const char *buf, size_t count)         \
 {                                                                      \
        unsigned int ret = -EINVAL;                                     \
        struct cpufreq_policy new_policy;                               \
@@ -490,8 +492,8 @@ store_one(scaling_max_freq,max);
 /**
  * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
  */
-static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
-                                                       char *buf)
+static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
+                                       char *buf)
 {
        unsigned int cur_freq = __cpufreq_get(policy->cpu);
        if (!cur_freq)
@@ -503,8 +505,7 @@ static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
 /**
  * show_scaling_governor - show the current policy for the specified CPU
  */
-static ssize_t show_scaling_governor (struct cpufreq_policy * policy,
-                                                       char *buf)
+static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
 {
        if(policy->policy == CPUFREQ_POLICY_POWERSAVE)
                return sprintf(buf, "powersave\n");
@@ -519,8 +520,8 @@ static ssize_t show_scaling_governor (struct cpufreq_policy * policy,
 /**
  * store_scaling_governor - store policy for the specified CPU
  */
-static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
-                                      const char *buf, size_t count)
+static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
+                                       const char *buf, size_t count)
 {
        unsigned int ret = -EINVAL;
        char    str_governor[16];
@@ -554,7 +555,7 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
 /**
  * show_scaling_driver - show the cpufreq driver currently loaded
  */
-static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
+static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
 {
        return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
 }
@@ -562,8 +563,8 @@ static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
 /**
  * show_scaling_available_governors - show the available CPUfreq governors
  */
-static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy,
-                               char *buf)
+static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
+                                               char *buf)
 {
        ssize_t i = 0;
        struct cpufreq_governor *t;
@@ -582,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);
@@ -601,8 +600,27 @@ 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)
+                                       const char *buf, size_t count)
 {
        unsigned int freq = 0;
        unsigned int ret;
@@ -645,18 +663,20 @@ 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);
 define_one_rw(scaling_governor);
 define_one_rw(scaling_setspeed);
 
-static struct attribute * default_attrs[] = {
+static struct attribute *default_attrs[] = {
        &cpuinfo_min_freq.attr,
        &cpuinfo_max_freq.attr,
        &scaling_min_freq.attr,
        &scaling_max_freq.attr,
        &affected_cpus.attr,
+       &related_cpus.attr,
        &scaling_governor.attr,
        &scaling_driver.attr,
        &scaling_available_governors.attr,
@@ -667,17 +687,17 @@ static struct attribute * default_attrs[] = {
 #define to_policy(k) container_of(k,struct cpufreq_policy,kobj)
 #define to_attr(a) container_of(a,struct freq_attr,attr)
 
-static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
+static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf)
 {
-       struct cpufreq_policy * policy = to_policy(kobj);
-       struct freq_attr * fattr = to_attr(attr);
-       ssize_t ret;
+       struct cpufreq_policy *policy = to_policy(kobj);
+       struct freq_attr *fattr = to_attr(attr);
+       ssize_t ret = -EINVAL;
        policy = cpufreq_cpu_get(policy->cpu);
        if (!policy)
-               return -EINVAL;
+               goto no_policy;
 
        if (lock_policy_rwsem_read(policy->cpu) < 0)
-               return -EINVAL;
+               goto fail;
 
        if (fattr->show)
                ret = fattr->show(policy, buf);
@@ -685,23 +705,24 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
                ret = -EIO;
 
        unlock_policy_rwsem_read(policy->cpu);
-
+fail:
        cpufreq_cpu_put(policy);
+no_policy:
        return ret;
 }
 
-static ssize_t store(struct kobject * kobj, struct attribute * attr,
-                    const char * buf, size_t count)
+static ssize_t store(struct kobject *kobj, struct attribute *attr,
+                    const char *buf, size_t count)
 {
-       struct cpufreq_policy * policy = to_policy(kobj);
-       struct freq_attr * fattr = to_attr(attr);
-       ssize_t ret;
+       struct cpufreq_policy *policy = to_policy(kobj);
+       struct freq_attr *fattr = to_attr(attr);
+       ssize_t ret = -EINVAL;
        policy = cpufreq_cpu_get(policy->cpu);
        if (!policy)
-               return -EINVAL;
+               goto no_policy;
 
        if (lock_policy_rwsem_write(policy->cpu) < 0)
-               return -EINVAL;
+               goto fail;
 
        if (fattr->store)
                ret = fattr->store(policy, buf, count);
@@ -709,14 +730,15 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr,
                ret = -EIO;
 
        unlock_policy_rwsem_write(policy->cpu);
-
+fail:
        cpufreq_cpu_put(policy);
+no_policy:
        return ret;
 }
 
-static void cpufreq_sysfs_release(struct kobject * kobj)
+static void cpufreq_sysfs_release(struct kobject *kobj)
 {
-       struct cpufreq_policy * policy = to_policy(kobj);
+       struct cpufreq_policy *policy = to_policy(kobj);
        dprintk("last reference is dropped\n");
        complete(&policy->kobj_unregister);
 }
@@ -738,7 +760,7 @@ static struct kobj_type ktype_cpufreq = {
  *
  * Adds the cpufreq interface for a CPU device.
  */
-static int cpufreq_add_dev (struct sys_device * sys_dev)
+static int cpufreq_add_dev(struct sys_device *sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        int ret = 0;
@@ -798,7 +820,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        ret = cpufreq_driver->init(policy);
        if (ret) {
                dprintk("initialization failed\n");
-               unlock_policy_rwsem_write(cpu);
                goto err_out;
        }
        policy->user_policy.min = policy->cpuinfo.min_freq;
@@ -821,7 +842,7 @@ 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.
                 */
-               managed_policy = cpufreq_cpu_get(j);
+               managed_policy = cpufreq_cpu_get(j);            // FIXME: Where is this released?  What about error paths?
                if (unlikely(managed_policy)) {
 
                        /* Set proper policy_cpu */
@@ -840,14 +861,11 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
                        ret = sysfs_create_link(&sys_dev->kobj,
                                                &managed_policy->kobj,
                                                "cpufreq");
-                       if (ret) {
-                               unlock_policy_rwsem_write(cpu);
+                       if (ret)
                                goto err_out_driver_exit;
-                       }
 
                        cpufreq_debug_enable_ratelimit();
                        ret = 0;
-                       unlock_policy_rwsem_write(cpu);
                        goto err_out_driver_exit; /* call driver->exit() */
                }
        }
@@ -857,33 +875,26 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        /* prepare interface data */
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
                                   "cpufreq");
-       if (ret) {
-               unlock_policy_rwsem_write(cpu);
+       if (ret)
                goto err_out_driver_exit;
-       }
+
        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
                ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
-               if (ret) {
-                       unlock_policy_rwsem_write(cpu);
+               if (ret)
                        goto err_out_driver_exit;
-               }
                drv_attr++;
        }
-       if (cpufreq_driver->get){
+       if (cpufreq_driver->get) {
                ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
-               if (ret) {
-                       unlock_policy_rwsem_write(cpu);
+               if (ret)
                        goto err_out_driver_exit;
-               }
        }
-       if (cpufreq_driver->target){
+       if (cpufreq_driver->target) {
                ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
-               if (ret) {
-                       unlock_policy_rwsem_write(cpu);
+               if (ret)
                        goto err_out_driver_exit;
-               }
        }
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -905,10 +916,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
                cpu_sys_dev = get_cpu_sysdev(j);
                ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
                                        "cpufreq");
-               if (ret) {
-                       unlock_policy_rwsem_write(cpu);
+               if (ret)
                        goto err_out_unregister;
-               }
        }
 
        policy->governor = NULL; /* to assure that the starting sequence is
@@ -948,6 +957,7 @@ err_out_driver_exit:
                cpufreq_driver->exit(policy);
 
 err_out:
+       unlock_policy_rwsem_write(cpu);
        kfree(policy);
 
 nomem_out:
@@ -965,7 +975,7 @@ module_out:
  * Caller should already have policy_rwsem in write mode for this CPU.
  * This routine frees the rwsem before returning.
  */
-static int __cpufreq_remove_dev (struct sys_device * sys_dev)
+static int __cpufreq_remove_dev(struct sys_device *sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        unsigned long flags;
@@ -1069,7 +1079,7 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
 }
 
 
-static int cpufreq_remove_dev (struct sys_device * sys_dev)
+static int cpufreq_remove_dev(struct sys_device *sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        int retval;
@@ -1136,7 +1146,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
                cpufreq_cpu_put(policy);
        }
 
-       return (ret_freq);
+       return ret_freq;
 }
 EXPORT_SYMBOL(cpufreq_quick_get);
 
@@ -1147,7 +1157,7 @@ static unsigned int __cpufreq_get(unsigned int cpu)
        unsigned int ret_freq = 0;
 
        if (!cpufreq_driver->get)
-               return (ret_freq);
+               return ret_freq;
 
        ret_freq = cpufreq_driver->get(cpu);
 
@@ -1161,7 +1171,7 @@ static unsigned int __cpufreq_get(unsigned int cpu)
                }
        }
 
-       return (ret_freq);
+       return ret_freq;
 }
 
 /**
@@ -1188,7 +1198,7 @@ unsigned int cpufreq_get(unsigned int cpu)
 out_policy:
        cpufreq_cpu_put(policy);
 out:
-       return (ret_freq);
+       return ret_freq;
 }
 EXPORT_SYMBOL(cpufreq_get);
 
@@ -1197,7 +1207,7 @@ EXPORT_SYMBOL(cpufreq_get);
  *     cpufreq_suspend - let the low level driver prepare for suspend
  */
 
-static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
+static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
 {
        int cpu = sysdev->id;
        int ret = 0;
@@ -1219,22 +1229,18 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
                return -EINVAL;
 
        /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu)) {
-               cpufreq_cpu_put(cpu_policy);
-               return 0;
-       }
+       if (unlikely(cpu_policy->cpu != cpu))
+               goto out;
 
        if (cpufreq_driver->suspend) {
                ret = cpufreq_driver->suspend(cpu_policy, pmsg);
                if (ret) {
                        printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
                                        "step on CPU %u\n", cpu_policy->cpu);
-                       cpufreq_cpu_put(cpu_policy);
-                       return ret;
+                       goto out;
                }
        }
 
-
        if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
                goto out;
 
@@ -1268,7 +1274,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
 
 out:
        cpufreq_cpu_put(cpu_policy);
-       return 0;
+       return ret;
 }
 
 /**
@@ -1279,7 +1285,7 @@ out:
  *     3.) schedule call cpufreq_update_policy() ASAP as interrupts are
  *         restored.
  */
-static int cpufreq_resume(struct sys_device * sysdev)
+static int cpufreq_resume(struct sys_device *sysdev)
 {
        int cpu = sysdev->id;
        int ret = 0;
@@ -1300,18 +1306,15 @@ static int cpufreq_resume(struct sys_device * sysdev)
                return -EINVAL;
 
        /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu)) {
-               cpufreq_cpu_put(cpu_policy);
-               return 0;
-       }
+       if (unlikely(cpu_policy->cpu != cpu))
+               goto fail;
 
        if (cpufreq_driver->resume) {
                ret = cpufreq_driver->resume(cpu_policy);
                if (ret) {
                        printk(KERN_ERR "cpufreq: resume failed in ->resume "
                                        "step on CPU %u\n", cpu_policy->cpu);
-                       cpufreq_cpu_put(cpu_policy);
-                       return ret;
+                       goto fail;
                }
        }
 
@@ -1351,6 +1354,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
 
 out:
        schedule_work(&cpu_policy->update);
+fail:
        cpufreq_cpu_put(cpu_policy);
        return ret;
 }
@@ -1384,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(
@@ -1775,7 +1781,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpufreq_cpu_notifier =
+static struct notifier_block __refdata cpufreq_cpu_notifier =
 {
     .notifier_call = cpufreq_cpu_callback,
 };
@@ -1846,7 +1852,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                cpufreq_debug_enable_ratelimit();
        }
 
-       return (ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);