Merge branch 'pm-cpufreq'

* pm-cpufreq:
  cpufreq: Revert incorrect commit 5800043
This commit is contained in:
Rafael J. Wysocki 2013-04-29 00:08:46 +02:00
commit 371deb9500
1 changed files with 72 additions and 217 deletions

View File

@ -39,7 +39,7 @@
* level driver of CPUFreq support, and its spinlock. This lock * level driver of CPUFreq support, and its spinlock. This lock
* also protects the cpufreq_cpu_data array. * also protects the cpufreq_cpu_data array.
*/ */
static struct cpufreq_driver __rcu *cpufreq_driver; static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */ /* This one keeps track of the previously set governor of a removed CPU */
@ -130,35 +130,27 @@ static DEFINE_MUTEX(cpufreq_governor_mutex);
bool have_governor_per_policy(void) bool have_governor_per_policy(void)
{ {
bool have_governor_per_policy; return cpufreq_driver->have_governor_per_policy;
rcu_read_lock();
have_governor_per_policy =
rcu_dereference(cpufreq_driver)->have_governor_per_policy;
rcu_read_unlock();
return have_governor_per_policy;
} }
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
{ {
struct cpufreq_policy *data; struct cpufreq_policy *data;
struct cpufreq_driver *driver;
unsigned long flags; unsigned long flags;
if (cpu >= nr_cpu_ids) if (cpu >= nr_cpu_ids)
goto err_out; goto err_out;
/* get the cpufreq driver */ /* get the cpufreq driver */
rcu_read_lock();
driver = rcu_dereference(cpufreq_driver);
if (!driver)
goto err_out_unlock;
if (!try_module_get(driver->owner))
goto err_out_unlock;
read_lock_irqsave(&cpufreq_driver_lock, flags); read_lock_irqsave(&cpufreq_driver_lock, flags);
if (!cpufreq_driver)
goto err_out_unlock;
if (!try_module_get(cpufreq_driver->owner))
goto err_out_unlock;
/* get the CPU */ /* get the CPU */
data = per_cpu(cpufreq_cpu_data, cpu); data = per_cpu(cpufreq_cpu_data, cpu);
@ -169,14 +161,12 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
goto err_out_put_module; goto err_out_put_module;
read_unlock_irqrestore(&cpufreq_driver_lock, flags); read_unlock_irqrestore(&cpufreq_driver_lock, flags);
rcu_read_unlock();
return data; return data;
err_out_put_module: err_out_put_module:
module_put(driver->owner); module_put(cpufreq_driver->owner);
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
err_out_unlock: err_out_unlock:
rcu_read_unlock(); read_unlock_irqrestore(&cpufreq_driver_lock, flags);
err_out: err_out:
return NULL; return NULL;
} }
@ -199,9 +189,7 @@ static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
{ {
if (!sysfs) if (!sysfs)
kobject_put(&data->kobj); kobject_put(&data->kobj);
rcu_read_lock(); module_put(cpufreq_driver->owner);
module_put(rcu_dereference(cpufreq_driver)->owner);
rcu_read_unlock();
} }
void cpufreq_cpu_put(struct cpufreq_policy *data) void cpufreq_cpu_put(struct cpufreq_policy *data)
@ -269,9 +257,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
if (cpufreq_disabled()) if (cpufreq_disabled())
return; return;
rcu_read_lock(); freqs->flags = cpufreq_driver->flags;
freqs->flags = rcu_dereference(cpufreq_driver)->flags;
rcu_read_unlock();
pr_debug("notification %u of frequency transition to %u kHz\n", pr_debug("notification %u of frequency transition to %u kHz\n",
state, freqs->new); state, freqs->new);
@ -282,7 +268,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
* which is not equal to what the cpufreq core thinks is * which is not equal to what the cpufreq core thinks is
* "old frequency". * "old frequency".
*/ */
if (!(freqs->flags & CPUFREQ_CONST_LOOPS)) { if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((policy) && (policy->cpu == freqs->cpu) && if ((policy) && (policy->cpu == freqs->cpu) &&
(policy->cur) && (policy->cur != freqs->old)) { (policy->cur) && (policy->cur != freqs->old)) {
pr_debug("Warning: CPU frequency is" pr_debug("Warning: CPU frequency is"
@ -348,21 +334,11 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor) struct cpufreq_governor **governor)
{ {
int err = -EINVAL; int err = -EINVAL;
struct cpufreq_driver *driver;
bool has_setpolicy;
bool has_target;
rcu_read_lock(); if (!cpufreq_driver)
driver = rcu_dereference(cpufreq_driver);
if (!driver) {
rcu_read_unlock();
goto out; goto out;
}
has_setpolicy = driver->setpolicy ? true : false;
has_target = driver->target ? true : false;
rcu_read_unlock();
if (has_setpolicy) { if (cpufreq_driver->setpolicy) {
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_PERFORMANCE; *policy = CPUFREQ_POLICY_PERFORMANCE;
err = 0; err = 0;
@ -371,7 +347,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
*policy = CPUFREQ_POLICY_POWERSAVE; *policy = CPUFREQ_POLICY_POWERSAVE;
err = 0; err = 0;
} }
} else if (has_target) { } else if (cpufreq_driver->target) {
struct cpufreq_governor *t; struct cpufreq_governor *t;
mutex_lock(&cpufreq_governor_mutex); mutex_lock(&cpufreq_governor_mutex);
@ -522,12 +498,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
*/ */
static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
{ {
ssize_t size; return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name);
rcu_read_lock();
size = scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n",
rcu_dereference(cpufreq_driver)->name);
rcu_read_unlock();
return size;
} }
/** /**
@ -539,13 +510,10 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
ssize_t i = 0; ssize_t i = 0;
struct cpufreq_governor *t; struct cpufreq_governor *t;
rcu_read_lock(); if (!cpufreq_driver->target) {
if (!rcu_dereference(cpufreq_driver)->target) {
rcu_read_unlock();
i += sprintf(buf, "performance powersave"); i += sprintf(buf, "performance powersave");
goto out; goto out;
} }
rcu_read_unlock();
list_for_each_entry(t, &cpufreq_governor_list, governor_list) { list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
@ -623,15 +591,9 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf)
{ {
unsigned int limit; unsigned int limit;
int (*bios_limit)(int cpu, unsigned int *limit);
int ret; int ret;
if (cpufreq_driver->bios_limit) {
rcu_read_lock(); ret = cpufreq_driver->bios_limit(policy->cpu, &limit);
bios_limit = rcu_dereference(cpufreq_driver)->bios_limit;
rcu_read_unlock();
if (bios_limit) {
ret = bios_limit(policy->cpu, &limit);
if (!ret) if (!ret)
return sprintf(buf, "%u\n", limit); return sprintf(buf, "%u\n", limit);
} }
@ -774,7 +736,6 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
{ {
struct cpufreq_policy new_policy; struct cpufreq_policy new_policy;
struct freq_attr **drv_attr; struct freq_attr **drv_attr;
struct cpufreq_driver *driver;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
unsigned int j; unsigned int j;
@ -786,31 +747,28 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
return ret; return ret;
/* set up files for this cpu device */ /* set up files for this cpu device */
rcu_read_lock(); drv_attr = cpufreq_driver->attr;
driver = rcu_dereference(cpufreq_driver);
drv_attr = driver->attr;
while ((drv_attr) && (*drv_attr)) { while ((drv_attr) && (*drv_attr)) {
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
if (ret) if (ret)
goto err_out_unlock; goto err_out_kobj_put;
drv_attr++; drv_attr++;
} }
if (driver->get) { if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (ret) if (ret)
goto err_out_unlock; goto err_out_kobj_put;
} }
if (driver->target) { if (cpufreq_driver->target) {
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
if (ret) if (ret)
goto err_out_unlock; goto err_out_kobj_put;
} }
if (driver->bios_limit) { if (cpufreq_driver->bios_limit) {
ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
if (ret) if (ret)
goto err_out_unlock; goto err_out_kobj_put;
} }
rcu_read_unlock();
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) { for_each_cpu(j, policy->cpus) {
@ -833,20 +791,12 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
policy->user_policy.governor = policy->governor; policy->user_policy.governor = policy->governor;
if (ret) { if (ret) {
int (*exit)(struct cpufreq_policy *policy);
pr_debug("setting policy failed\n"); pr_debug("setting policy failed\n");
rcu_read_lock(); if (cpufreq_driver->exit)
exit = rcu_dereference(cpufreq_driver)->exit; cpufreq_driver->exit(policy);
rcu_read_unlock();
if (exit)
exit(policy);
} }
return ret; return ret;
err_out_unlock:
rcu_read_unlock();
err_out_kobj_put: err_out_kobj_put:
kobject_put(&policy->kobj); kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister); wait_for_completion(&policy->kobj_unregister);
@ -858,16 +808,12 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
struct device *dev) struct device *dev)
{ {
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
int ret = 0, has_target = 0; int ret = 0, has_target = !!cpufreq_driver->target;
unsigned long flags; unsigned long flags;
policy = cpufreq_cpu_get(sibling); policy = cpufreq_cpu_get(sibling);
WARN_ON(!policy); WARN_ON(!policy);
rcu_read_lock();
has_target = !!rcu_dereference(cpufreq_driver)->target;
rcu_read_unlock();
if (has_target) if (has_target)
__cpufreq_governor(policy, CPUFREQ_GOV_STOP); __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
@ -911,8 +857,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
unsigned int j, cpu = dev->id; unsigned int j, cpu = dev->id;
int ret = -ENOMEM; int ret = -ENOMEM;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct cpufreq_driver *driver;
int (*init)(struct cpufreq_policy *policy);
unsigned long flags; unsigned long flags;
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
struct cpufreq_governor *gov; struct cpufreq_governor *gov;
@ -947,15 +891,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
#endif #endif
#endif #endif
rcu_read_lock(); if (!try_module_get(cpufreq_driver->owner)) {
driver = rcu_dereference(cpufreq_driver);
if (!try_module_get(driver->owner)) {
rcu_read_unlock();
ret = -EINVAL; ret = -EINVAL;
goto module_out; goto module_out;
} }
init = driver->init;
rcu_read_unlock();
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!policy) if (!policy)
@ -980,7 +919,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
/* call driver. From then on the cpufreq must be able /* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU * to accept all calls to ->verify and ->setpolicy for this CPU
*/ */
ret = init(policy); ret = cpufreq_driver->init(policy);
if (ret) { if (ret) {
pr_debug("initialization failed\n"); pr_debug("initialization failed\n");
goto err_set_policy_cpu; goto err_set_policy_cpu;
@ -1015,9 +954,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto err_out_unregister; goto err_out_unregister;
kobject_uevent(&policy->kobj, KOBJ_ADD); kobject_uevent(&policy->kobj, KOBJ_ADD);
rcu_read_lock(); module_put(cpufreq_driver->owner);
module_put(rcu_dereference(cpufreq_driver)->owner);
rcu_read_unlock();
pr_debug("initialization complete\n"); pr_debug("initialization complete\n");
return 0; return 0;
@ -1039,9 +976,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
err_free_policy: err_free_policy:
kfree(policy); kfree(policy);
nomem_out: nomem_out:
rcu_read_lock(); module_put(cpufreq_driver->owner);
module_put(rcu_dereference(cpufreq_driver)->owner);
rcu_read_unlock();
module_out: module_out:
return ret; return ret;
} }
@ -1075,12 +1010,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
unsigned int cpu = dev->id, ret, cpus; unsigned int cpu = dev->id, ret, cpus;
unsigned long flags; unsigned long flags;
struct cpufreq_policy *data; struct cpufreq_policy *data;
struct cpufreq_driver *driver;
struct kobject *kobj; struct kobject *kobj;
struct completion *cmp; struct completion *cmp;
struct device *cpu_dev; struct device *cpu_dev;
bool has_target;
int (*exit)(struct cpufreq_policy *policy);
pr_debug("%s: unregistering CPU %u\n", __func__, cpu); pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
@ -1096,19 +1028,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
return -EINVAL; return -EINVAL;
} }
rcu_read_lock(); if (cpufreq_driver->target)
driver = rcu_dereference(cpufreq_driver);
has_target = driver->target ? true : false;
exit = driver->exit;
if (has_target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP); __cpufreq_governor(data, CPUFREQ_GOV_STOP);
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
if (!driver->setpolicy) if (!cpufreq_driver->setpolicy)
strncpy(per_cpu(cpufreq_cpu_governor, cpu), strncpy(per_cpu(cpufreq_cpu_governor, cpu),
data->governor->name, CPUFREQ_NAME_LEN); data->governor->name, CPUFREQ_NAME_LEN);
#endif #endif
rcu_read_unlock();
WARN_ON(lock_policy_rwsem_write(cpu)); WARN_ON(lock_policy_rwsem_write(cpu));
cpus = cpumask_weight(data->cpus); cpus = cpumask_weight(data->cpus);
@ -1153,7 +1080,7 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
/* If cpu is last user of policy, free policy */ /* If cpu is last user of policy, free policy */
if (cpus == 1) { if (cpus == 1) {
if (has_target) if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
lock_policy_rwsem_read(cpu); lock_policy_rwsem_read(cpu);
@ -1170,13 +1097,13 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
wait_for_completion(cmp); wait_for_completion(cmp);
pr_debug("wait complete\n"); pr_debug("wait complete\n");
if (exit) if (cpufreq_driver->exit)
exit(data); cpufreq_driver->exit(data);
free_cpumask_var(data->related_cpus); free_cpumask_var(data->related_cpus);
free_cpumask_var(data->cpus); free_cpumask_var(data->cpus);
kfree(data); kfree(data);
} else if (has_target) { } else if (cpufreq_driver->target) {
__cpufreq_governor(data, CPUFREQ_GOV_START); __cpufreq_governor(data, CPUFREQ_GOV_START);
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS); __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
} }
@ -1250,18 +1177,10 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int cpufreq_quick_get(unsigned int cpu)
{ {
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct cpufreq_driver *driver;
unsigned int (*get)(unsigned int cpu);
unsigned int ret_freq = 0; unsigned int ret_freq = 0;
rcu_read_lock(); if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
driver = rcu_dereference(cpufreq_driver); return cpufreq_driver->get(cpu);
if (driver && driver->setpolicy && driver->get) {
get = driver->get;
rcu_read_unlock();
return get(cpu);
}
rcu_read_unlock();
policy = cpufreq_cpu_get(cpu); policy = cpufreq_cpu_get(cpu);
if (policy) { if (policy) {
@ -1297,26 +1216,15 @@ EXPORT_SYMBOL(cpufreq_quick_get_max);
static unsigned int __cpufreq_get(unsigned int cpu) static unsigned int __cpufreq_get(unsigned int cpu)
{ {
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
struct cpufreq_driver *driver;
unsigned int (*get)(unsigned int cpu);
unsigned int ret_freq = 0; unsigned int ret_freq = 0;
u8 flags;
if (!cpufreq_driver->get)
rcu_read_lock();
driver = rcu_dereference(cpufreq_driver);
if (!driver->get) {
rcu_read_unlock();
return ret_freq; return ret_freq;
}
flags = driver->flags;
get = driver->get;
rcu_read_unlock();
ret_freq = get(cpu); ret_freq = cpufreq_driver->get(cpu);
if (ret_freq && policy->cur && if (ret_freq && policy->cur &&
!(flags & CPUFREQ_CONST_LOOPS)) { !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
/* verify no discrepancy between actual and /* verify no discrepancy between actual and
saved value exists */ saved value exists */
if (unlikely(ret_freq != policy->cur)) { if (unlikely(ret_freq != policy->cur)) {
@ -1372,7 +1280,6 @@ static struct subsys_interface cpufreq_interface = {
*/ */
static int cpufreq_bp_suspend(void) static int cpufreq_bp_suspend(void)
{ {
int (*suspend)(struct cpufreq_policy *policy);
int ret = 0; int ret = 0;
int cpu = smp_processor_id(); int cpu = smp_processor_id();
@ -1385,11 +1292,8 @@ static int cpufreq_bp_suspend(void)
if (!cpu_policy) if (!cpu_policy)
return 0; return 0;
rcu_read_lock(); if (cpufreq_driver->suspend) {
suspend = rcu_dereference(cpufreq_driver)->suspend; ret = cpufreq_driver->suspend(cpu_policy);
rcu_read_unlock();
if (suspend) {
ret = suspend(cpu_policy);
if (ret) if (ret)
printk(KERN_ERR "cpufreq: suspend failed in ->suspend " printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
"step on CPU %u\n", cpu_policy->cpu); "step on CPU %u\n", cpu_policy->cpu);
@ -1415,7 +1319,6 @@ static int cpufreq_bp_suspend(void)
static void cpufreq_bp_resume(void) static void cpufreq_bp_resume(void)
{ {
int ret = 0; int ret = 0;
int (*resume)(struct cpufreq_policy *policy);
int cpu = smp_processor_id(); int cpu = smp_processor_id();
struct cpufreq_policy *cpu_policy; struct cpufreq_policy *cpu_policy;
@ -1427,12 +1330,8 @@ static void cpufreq_bp_resume(void)
if (!cpu_policy) if (!cpu_policy)
return; return;
rcu_read_lock(); if (cpufreq_driver->resume) {
resume = rcu_dereference(cpufreq_driver)->resume; ret = cpufreq_driver->resume(cpu_policy);
rcu_read_unlock();
if (resume) {
ret = resume(cpu_policy);
if (ret) { if (ret) {
printk(KERN_ERR "cpufreq: resume failed in ->resume " printk(KERN_ERR "cpufreq: resume failed in ->resume "
"step on CPU %u\n", cpu_policy->cpu); "step on CPU %u\n", cpu_policy->cpu);
@ -1459,14 +1358,10 @@ static struct syscore_ops cpufreq_syscore_ops = {
*/ */
const char *cpufreq_get_current_driver(void) const char *cpufreq_get_current_driver(void)
{ {
struct cpufreq_driver *driver; if (cpufreq_driver)
const char *name = NULL; return cpufreq_driver->name;
rcu_read_lock();
driver = rcu_dereference(cpufreq_driver); return NULL;
if (driver)
name = driver->name;
rcu_read_unlock();
return name;
} }
EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); EXPORT_SYMBOL_GPL(cpufreq_get_current_driver);
@ -1560,9 +1455,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
{ {
int retval = -EINVAL; int retval = -EINVAL;
unsigned int old_target_freq = target_freq; unsigned int old_target_freq = target_freq;
int (*target)(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
if (cpufreq_disabled()) if (cpufreq_disabled())
return -ENODEV; return -ENODEV;
@ -1579,11 +1471,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
if (target_freq == policy->cur) if (target_freq == policy->cur)
return 0; return 0;
rcu_read_lock(); if (cpufreq_driver->target)
target = rcu_dereference(cpufreq_driver)->target; retval = cpufreq_driver->target(policy, target_freq, relation);
rcu_read_unlock();
if (target)
retval = target(policy, target_freq, relation);
return retval; return retval;
} }
@ -1616,24 +1505,18 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_target);
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
{ {
int ret = 0; int ret = 0;
unsigned int (*getavg)(struct cpufreq_policy *policy,
unsigned int cpu);
if (cpufreq_disabled()) if (cpufreq_disabled())
return ret; return ret;
rcu_read_lock(); if (!cpufreq_driver->getavg)
getavg = rcu_dereference(cpufreq_driver)->getavg;
rcu_read_unlock();
if (!getavg)
return 0; return 0;
policy = cpufreq_cpu_get(policy->cpu); policy = cpufreq_cpu_get(policy->cpu);
if (!policy) if (!policy)
return -EINVAL; return -EINVAL;
ret = getavg(policy, cpu); ret = cpufreq_driver->getavg(policy, cpu);
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
return ret; return ret;
@ -1791,9 +1674,6 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
struct cpufreq_policy *policy) struct cpufreq_policy *policy)
{ {
int ret = 0, failed = 1; int ret = 0, failed = 1;
struct cpufreq_driver *driver;
int (*verify)(struct cpufreq_policy *policy);
int (*setpolicy)(struct cpufreq_policy *policy);
pr_debug("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); policy->min, policy->max);
@ -1807,13 +1687,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
} }
/* verify the cpu speed can be set within this limit */ /* verify the cpu speed can be set within this limit */
rcu_read_lock(); ret = cpufreq_driver->verify(policy);
driver = rcu_dereference(cpufreq_driver);
verify = driver->verify;
setpolicy = driver->setpolicy;
rcu_read_unlock();
ret = verify(policy);
if (ret) if (ret)
goto error_out; goto error_out;
@ -1827,7 +1701,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
/* verify the cpu speed can be set within this limit, /* verify the cpu speed can be set within this limit,
which might be different to the first one */ which might be different to the first one */
ret = verify(policy); ret = cpufreq_driver->verify(policy);
if (ret) if (ret)
goto error_out; goto error_out;
@ -1841,10 +1715,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
pr_debug("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); data->min, data->max);
if (setpolicy) { if (cpufreq_driver->setpolicy) {
data->policy = policy->policy; data->policy = policy->policy;
pr_debug("setting range\n"); pr_debug("setting range\n");
ret = setpolicy(policy); ret = cpufreq_driver->setpolicy(policy);
} else { } else {
if (policy->governor != data->governor) { if (policy->governor != data->governor) {
/* save old, working values */ /* save old, working values */
@ -1904,11 +1778,6 @@ int cpufreq_update_policy(unsigned int cpu)
{ {
struct cpufreq_policy *data = cpufreq_cpu_get(cpu); struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
struct cpufreq_policy policy; struct cpufreq_policy policy;
struct cpufreq_driver *driver;
unsigned int (*get)(unsigned int cpu);
int (*target)(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
int ret; int ret;
if (!data) { if (!data) {
@ -1930,18 +1799,13 @@ int cpufreq_update_policy(unsigned int cpu)
/* BIOS might change freq behind our back /* BIOS might change freq behind our back
-> ask driver for current freq and notify governors about a change */ -> ask driver for current freq and notify governors about a change */
rcu_read_lock(); if (cpufreq_driver->get) {
driver = rcu_access_pointer(cpufreq_driver); policy.cur = cpufreq_driver->get(cpu);
get = driver->get;
target = driver->target;
rcu_read_unlock();
if (get) {
policy.cur = get(cpu);
if (!data->cur) { if (!data->cur) {
pr_debug("Driver did not initialize current freq"); pr_debug("Driver did not initialize current freq");
data->cur = policy.cur; data->cur = policy.cur;
} else { } else {
if (data->cur != policy.cur && target) if (data->cur != policy.cur && cpufreq_driver->target)
cpufreq_out_of_sync(cpu, data->cur, cpufreq_out_of_sync(cpu, data->cur,
policy.cur); policy.cur);
} }
@ -2020,19 +1884,18 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
driver_data->flags |= CPUFREQ_CONST_LOOPS; driver_data->flags |= CPUFREQ_CONST_LOOPS;
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
if (rcu_access_pointer(cpufreq_driver)) { if (cpufreq_driver) {
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EBUSY; return -EBUSY;
} }
rcu_assign_pointer(cpufreq_driver, driver_data); cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
synchronize_rcu();
ret = subsys_interface_register(&cpufreq_interface); ret = subsys_interface_register(&cpufreq_interface);
if (ret) if (ret)
goto err_null_driver; goto err_null_driver;
if (!(driver_data->flags & CPUFREQ_STICKY)) { if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i; int i;
ret = -ENODEV; ret = -ENODEV;
@ -2059,9 +1922,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
subsys_interface_unregister(&cpufreq_interface); subsys_interface_unregister(&cpufreq_interface);
err_null_driver: err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
rcu_assign_pointer(cpufreq_driver, NULL); cpufreq_driver = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
synchronize_rcu();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(cpufreq_register_driver); EXPORT_SYMBOL_GPL(cpufreq_register_driver);
@ -2078,15 +1940,9 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver);
int cpufreq_unregister_driver(struct cpufreq_driver *driver) int cpufreq_unregister_driver(struct cpufreq_driver *driver)
{ {
unsigned long flags; unsigned long flags;
struct cpufreq_driver *old_driver;
rcu_read_lock(); if (!cpufreq_driver || (driver != cpufreq_driver))
old_driver = rcu_access_pointer(cpufreq_driver);
if (!old_driver || (driver != old_driver)) {
rcu_read_unlock();
return -EINVAL; return -EINVAL;
}
rcu_read_unlock();
pr_debug("unregistering driver %s\n", driver->name); pr_debug("unregistering driver %s\n", driver->name);
@ -2094,9 +1950,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
unregister_hotcpu_notifier(&cpufreq_cpu_notifier); unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
rcu_assign_pointer(cpufreq_driver, NULL); cpufreq_driver = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
synchronize_rcu();
return 0; return 0;
} }