]> err.no Git - linux-2.6/blobdiff - drivers/cpufreq/cpufreq.c
Merge branch 'linux-2.6' into for-linus
[linux-2.6] / drivers / cpufreq / cpufreq.c
index bc1088d9b379a97843c58b050f046b8b0df023f5..dd0c2623e27be0312eba1220c8d1eb38fe09bef3 100644 (file)
@@ -32,7 +32,7 @@
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
 
 /**
- * The "cpufreq driver" - the arch- or hardware-dependend low
+ * The "cpufreq driver" - the arch- or hardware-dependent low
  * level driver of CPUFreq support, and its spinlock. This lock
  * also protects the cpufreq_cpu_data array.
  */
@@ -52,8 +52,14 @@ static void handle_update(void *data);
  * The mutex locks both lists.
  */
 static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
-static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
+static struct srcu_notifier_head cpufreq_transition_notifier_list;
 
+static int __init init_cpufreq_transition_notifier_list(void)
+{
+       srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+       return 0;
+}
+pure_initcall(init_cpufreq_transition_notifier_list);
 
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX (cpufreq_governor_mutex);
@@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
                                freqs->old = policy->cur;
                        }
                }
-               blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
                                CPUFREQ_PRECHANGE, freqs);
                adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
                break;
 
        case CPUFREQ_POSTCHANGE:
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-               blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
                                CPUFREQ_POSTCHANGE, freqs);
                if (likely(policy) && likely(policy->cpu == freqs->cpu))
                        policy->cur = freqs->new;
@@ -284,39 +290,69 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
 
+static struct cpufreq_governor *__find_governor(const char *str_governor)
+{
+       struct cpufreq_governor *t;
+
+       list_for_each_entry(t, &cpufreq_governor_list, governor_list)
+               if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN))
+                       return t;
+
+       return NULL;
+}
+
 /**
  * cpufreq_parse_governor - parse a governor string
  */
 static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
                                struct cpufreq_governor **governor)
 {
+       int err = -EINVAL;
+
        if (!cpufreq_driver)
-               return -EINVAL;
+               goto out;
+
        if (cpufreq_driver->setpolicy) {
                if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
                        *policy = CPUFREQ_POLICY_PERFORMANCE;
-                       return 0;
+                       err = 0;
                } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
                        *policy = CPUFREQ_POLICY_POWERSAVE;
-                       return 0;
+                       err = 0;
                }
-               return -EINVAL;
-       } else {
+       } else if (cpufreq_driver->target) {
                struct cpufreq_governor *t;
+
                mutex_lock(&cpufreq_governor_mutex);
-               if (!cpufreq_driver || !cpufreq_driver->target)
-                       goto out;
-               list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
-                       if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
-                               *governor = t;
+
+               t = __find_governor(str_governor);
+
+               if (t == NULL) {
+                       char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor);
+
+                       if (name) {
+                               int ret;
+
                                mutex_unlock(&cpufreq_governor_mutex);
-                               return 0;
+                               ret = request_module(name);
+                               mutex_lock(&cpufreq_governor_mutex);
+
+                               if (ret == 0)
+                                       t = __find_governor(str_governor);
                        }
+
+                       kfree(name);
                }
-out:
+
+               if (t != NULL) {
+                       *governor = t;
+                       err = 0;
+               }
+
                mutex_unlock(&cpufreq_governor_mutex);
        }
-       return -EINVAL;
+  out:
+       return err;
 }
 
 
@@ -964,7 +1000,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
        unsigned int cur_freq = 0;
        struct cpufreq_policy *cpu_policy;
 
-       dprintk("resuming cpu %u\n", cpu);
+       dprintk("suspending cpu %u\n", cpu);
 
        if (!cpu_online(cpu))
                return 0;
@@ -1019,7 +1055,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
                freqs.old = cpu_policy->cur;
                freqs.new = cur_freq;
 
-               blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
                                    CPUFREQ_SUSPENDCHANGE, &freqs);
                adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
 
@@ -1100,7 +1136,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
                        freqs.old = cpu_policy->cur;
                        freqs.new = cur_freq;
 
-                       blocking_notifier_call_chain(
+                       srcu_notifier_call_chain(
                                        &cpufreq_transition_notifier_list,
                                        CPUFREQ_RESUMECHANGE, &freqs);
                        adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@@ -1146,7 +1182,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
 
        switch (list) {
        case CPUFREQ_TRANSITION_NOTIFIER:
-               ret = blocking_notifier_chain_register(
+               ret = srcu_notifier_chain_register(
                                &cpufreq_transition_notifier_list, nb);
                break;
        case CPUFREQ_POLICY_NOTIFIER:
@@ -1178,7 +1214,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
 
        switch (list) {
        case CPUFREQ_TRANSITION_NOTIFIER:
-               ret = blocking_notifier_chain_unregister(
+               ret = srcu_notifier_chain_unregister(
                                &cpufreq_transition_notifier_list, nb);
                break;
        case CPUFREQ_POLICY_NOTIFIER:
@@ -1265,23 +1301,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
 
 int cpufreq_register_governor(struct cpufreq_governor *governor)
 {
-       struct cpufreq_governor *t;
+       int err;
 
        if (!governor)
                return -EINVAL;
 
        mutex_lock(&cpufreq_governor_mutex);
 
-       list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
-               if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
-                       mutex_unlock(&cpufreq_governor_mutex);
-                       return -EBUSY;
-               }
+       err = -EBUSY;
+       if (__find_governor(governor->name) == NULL) {
+               err = 0;
+               list_add(&governor->governor_list, &cpufreq_governor_list);
        }
-       list_add(&governor->governor_list, &cpufreq_governor_list);
 
        mutex_unlock(&cpufreq_governor_mutex);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
@@ -1343,6 +1377,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
 
        memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
 
+       if (policy->min > data->min && policy->min > policy->max) {
+               ret = -EINVAL;
+               goto error_out;
+       }
+
        /* verify the cpu speed can be set within this limit */
        ret = cpufreq_driver->verify(policy);
        if (ret)