]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/cpufreq/cpufreq.c
[S390] cio: Use helpers instead of container_of().
[linux-2.6-omap-h63xx.git] / drivers / cpufreq / cpufreq.c
index 0db9e1bda3227f36cb383a641ae0ca670724eb0a..5efd5550f4ca7a4afcf1a606d29e293eea5b4c9e 100644 (file)
  */
 static struct cpufreq_driver *cpufreq_driver;
 static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
+#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];
+#endif
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
 /*
@@ -759,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        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
         */
@@ -770,9 +776,17 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        }
        policy->user_policy.min = policy->cpuinfo.min_freq;
        policy->user_policy.max = policy->cpuinfo.max_freq;
-       policy->user_policy.governor = policy->governor;
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_HOTPLUG_CPU
+       if (cpufreq_cpu_governor[cpu]){
+               policy->governor = cpufreq_cpu_governor[cpu];
+               dprintk("Restoring governor %s for cpu %d\n",
+                      policy->governor->name, cpu);
+       }
+#endif
+
        for_each_cpu_mask(j, policy->cpus) {
                if (cpu == j)
                        continue;
@@ -814,11 +828,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
 
        /* prepare interface data */
-       policy->kobj.parent = &sys_dev->kobj;
-       policy->kobj.ktype = &ktype_cpufreq;
-       strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
-
-       ret = kobject_register(&policy->kobj);
+       ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
+                                  "cpufreq");
        if (ret) {
                unlock_policy_rwsem_write(cpu);
                goto err_out_driver_exit;
@@ -827,19 +838,25 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
                ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
-               if (ret)
+               if (ret) {
+                       unlock_policy_rwsem_write(cpu);
                        goto err_out_driver_exit;
+               }
                drv_attr++;
        }
        if (cpufreq_driver->get){
                ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
-               if (ret)
+               if (ret) {
+                       unlock_policy_rwsem_write(cpu);
                        goto err_out_driver_exit;
+               }
        }
        if (cpufreq_driver->target){
                ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
-               if (ret)
+               if (ret) {
+                       unlock_policy_rwsem_write(cpu);
                        goto err_out_driver_exit;
+               }
        }
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -873,6 +890,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        /* set default policy */
        ret = __cpufreq_set_policy(policy, &new_policy);
        policy->user_policy.policy = policy->policy;
+       policy->user_policy.governor = policy->governor;
 
        unlock_policy_rwsem_write(cpu);
 
@@ -881,6 +899,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
                goto err_out_unregister;
        }
 
+       kobject_uevent(&policy->kobj, KOBJ_ADD);
        module_put(cpufreq_driver->owner);
        dprintk("initialization complete\n");
        cpufreq_debug_enable_ratelimit();
@@ -894,7 +913,7 @@ err_out_unregister:
                cpufreq_cpu_data[j] = NULL;
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       kobject_unregister(&policy->kobj);
+       kobject_put(&policy->kobj);
        wait_for_completion(&policy->kobj_unregister);
 
 err_out_driver_exit:
@@ -969,6 +988,11 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
        }
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_HOTPLUG_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
@@ -989,6 +1013,9 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
                        if (j == cpu)
                                continue;
                        dprintk("removing link for cpu %u\n", j);
+#ifdef CONFIG_HOTPLUG_CPU
+                       cpufreq_cpu_governor[j] = data->governor;
+#endif
                        cpu_sys_dev = get_cpu_sysdev(j);
                        sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
                        cpufreq_cpu_put(data);
@@ -1003,8 +1030,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
 
        unlock_policy_rwsem_write(cpu);
 
-       kobject_unregister(&data->kobj);
-
        kobject_put(&data->kobj);
 
        /* we need to make sure that the underlying kobj is actually
@@ -1088,12 +1113,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
        unsigned int ret_freq = 0;
 
        if (policy) {
-               if (unlikely(lock_policy_rwsem_read(cpu)))
-                       return ret_freq;
-
                ret_freq = policy->cur;
-
-               unlock_policy_rwsem_read(cpu);
                cpufreq_cpu_put(policy);
        }
 
@@ -1462,6 +1482,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 {
        int ret;
 
+       /* Only must be defined when default governor is known to have latency
+          restrictions, like e.g. conservative or ondemand.
+          That this is the case is already ensured in Kconfig
+       */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+       struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+       struct cpufreq_governor *gov = NULL;
+#endif
+
+       if (policy->governor->max_transition_latency &&
+           policy->cpuinfo.transition_latency >
+           policy->governor->max_transition_latency) {
+               if (!gov)
+                       return -EINVAL;
+               else {
+                       printk(KERN_WARNING "%s governor failed, too long"
+                              " transition latency of HW, fallback"
+                              " to %s governor\n",
+                              policy->governor->name,
+                              gov->name);
+                       policy->governor = gov;
+               }
+       }
+
        if (!try_module_get(policy->governor->owner))
                return -EINVAL;
 
@@ -1682,12 +1727,11 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
        struct sys_device *sys_dev;
-       struct cpufreq_policy *policy;
 
        sys_dev = get_cpu_sysdev(cpu);
        if (sys_dev) {
@@ -1701,11 +1745,6 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                        if (unlikely(lock_policy_rwsem_write(cpu)))
                                BUG();
 
-                       policy = cpufreq_cpu_data[cpu];
-                       if (policy) {
-                               __cpufreq_driver_target(policy, policy->min,
-                                               CPUFREQ_RELATION_H);
-                       }
                        __cpufreq_remove_dev(sys_dev);
                        break;
                case CPU_DOWN_FAILED: