cpufreq: Revert incorrect commit 5800043
Commit 5800043
(cpufreq: convert cpufreq_driver to using RCU) causes
the following call trace to be spit on boot:
BUG: sleeping function called from invalid context at /scratch/rafael/work/linux-pm/mm/slab.c:3179
in_atomic(): 0, irqs_disabled(): 0, pid: 292, name: systemd-udevd
2 locks held by systemd-udevd/292:
#0: (subsys mutex){+.+.+.}, at: [<ffffffff8146851a>] subsys_interface_register+0x4a/0xe0
#1: (rcu_read_lock){.+.+.+}, at: [<ffffffff81538210>] cpufreq_add_dev_interface+0x60/0x5e0
Pid: 292, comm: systemd-udevd Not tainted 3.9.0-rc8+ #323
Call Trace:
[<ffffffff81072c90>] __might_sleep+0x140/0x1f0
[<ffffffff811581c2>] kmem_cache_alloc+0x42/0x2b0
[<ffffffff811e7179>] sysfs_new_dirent+0x59/0x130
[<ffffffff811e63cb>] sysfs_add_file_mode+0x6b/0x110
[<ffffffff81538210>] ? cpufreq_add_dev_interface+0x60/0x5e0
[<ffffffff810a3254>] ? __lock_is_held+0x54/0x80
[<ffffffff811e647d>] sysfs_add_file+0xd/0x10
[<ffffffff811e6541>] sysfs_create_file+0x21/0x30
[<ffffffff81538280>] cpufreq_add_dev_interface+0xd0/0x5e0
[<ffffffff81538210>] ? cpufreq_add_dev_interface+0x60/0x5e0
[<ffffffffa000337f>] ? acpi_processor_get_platform_limit+0x32/0xbb [processor]
[<ffffffffa022f540>] ? do_drv_write+0x70/0x70 [acpi_cpufreq]
[<ffffffff810a3254>] ? __lock_is_held+0x54/0x80
[<ffffffff8106c97e>] ? up_read+0x1e/0x40
[<ffffffff8106e632>] ? __blocking_notifier_call_chain+0x72/0xc0
[<ffffffff81538dbd>] cpufreq_add_dev+0x62d/0xae0
[<ffffffff815389b8>] ? cpufreq_add_dev+0x228/0xae0
[<ffffffff81468569>] subsys_interface_register+0x99/0xe0
[<ffffffffa014d000>] ? 0xffffffffa014cfff
[<ffffffff81535d5d>] cpufreq_register_driver+0x9d/0x200
[<ffffffffa014d000>] ? 0xffffffffa014cfff
[<ffffffffa014d0e9>] acpi_cpufreq_init+0xe9/0x1000 [acpi_cpufreq]
[<ffffffff810002fa>] do_one_initcall+0x11a/0x170
[<ffffffff810b4b87>] load_module+0x1cf7/0x2920
[<ffffffff81322580>] ? ddebug_proc_open+0xb0/0xb0
[<ffffffff816baee0>] ? retint_restore_args+0xe/0xe
[<ffffffff810b5887>] sys_init_module+0xd7/0x120
[<ffffffff816bb6d2>] system_call_fastpath+0x16/0x1b
which is quite obvious, because that commit put (multiple instances
of) sysfs_create_file() under rcu_read_lock()/rcu_read_unlock(),
although sysfs_create_file() may cause memory to be allocated with
GFP_KERNEL and that may sleep, which is not permitted in RCU read
critical section.
Revert the buggy commit altogether along with some changes on top
of it.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
45c009a9a4
commit
1c3d85dd4e
1 changed files with 72 additions and 217 deletions
|
@ -39,7 +39,7 @@
|
|||
* level driver of CPUFreq support, and its spinlock. This lock
|
||||
* 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);
|
||||
#ifdef CONFIG_HOTPLUG_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;
|
||||
rcu_read_lock();
|
||||
have_governor_per_policy =
|
||||
rcu_dereference(cpufreq_driver)->have_governor_per_policy;
|
||||
rcu_read_unlock();
|
||||
return have_governor_per_policy;
|
||||
return cpufreq_driver->have_governor_per_policy;
|
||||
}
|
||||
|
||||
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
|
||||
{
|
||||
struct cpufreq_policy *data;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned long flags;
|
||||
|
||||
if (cpu >= nr_cpu_ids)
|
||||
goto err_out;
|
||||
|
||||
/* 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);
|
||||
|
||||
if (!cpufreq_driver)
|
||||
goto err_out_unlock;
|
||||
|
||||
if (!try_module_get(cpufreq_driver->owner))
|
||||
goto err_out_unlock;
|
||||
|
||||
|
||||
/* get the 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;
|
||||
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
rcu_read_unlock();
|
||||
return data;
|
||||
|
||||
err_out_put_module:
|
||||
module_put(driver->owner);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
module_put(cpufreq_driver->owner);
|
||||
err_out_unlock:
|
||||
rcu_read_unlock();
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -199,9 +189,7 @@ static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
|
|||
{
|
||||
if (!sysfs)
|
||||
kobject_put(&data->kobj);
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
module_put(cpufreq_driver->owner);
|
||||
}
|
||||
|
||||
void cpufreq_cpu_put(struct cpufreq_policy *data)
|
||||
|
@ -269,9 +257,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
|||
if (cpufreq_disabled())
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
freqs->flags = rcu_dereference(cpufreq_driver)->flags;
|
||||
rcu_read_unlock();
|
||||
freqs->flags = cpufreq_driver->flags;
|
||||
pr_debug("notification %u of frequency transition to %u kHz\n",
|
||||
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
|
||||
* "old frequency".
|
||||
*/
|
||||
if (!(freqs->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if ((policy) && (policy->cpu == freqs->cpu) &&
|
||||
(policy->cur) && (policy->cur != freqs->old)) {
|
||||
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)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct cpufreq_driver *driver;
|
||||
bool has_setpolicy;
|
||||
bool has_target;
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!driver) {
|
||||
rcu_read_unlock();
|
||||
if (!cpufreq_driver)
|
||||
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)) {
|
||||
*policy = CPUFREQ_POLICY_PERFORMANCE;
|
||||
err = 0;
|
||||
|
@ -371,7 +347,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
*policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
err = 0;
|
||||
}
|
||||
} else if (has_target) {
|
||||
} else if (cpufreq_driver->target) {
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
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)
|
||||
{
|
||||
ssize_t size;
|
||||
rcu_read_lock();
|
||||
size = scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n",
|
||||
rcu_dereference(cpufreq_driver)->name);
|
||||
rcu_read_unlock();
|
||||
return size;
|
||||
return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -539,13 +510,10 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
|
|||
ssize_t i = 0;
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
rcu_read_lock();
|
||||
if (!rcu_dereference(cpufreq_driver)->target) {
|
||||
rcu_read_unlock();
|
||||
if (!cpufreq_driver->target) {
|
||||
i += sprintf(buf, "performance powersave");
|
||||
goto out;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
|
||||
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)
|
||||
{
|
||||
unsigned int limit;
|
||||
int (*bios_limit)(int cpu, unsigned int *limit);
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
bios_limit = rcu_dereference(cpufreq_driver)->bios_limit;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (bios_limit) {
|
||||
ret = bios_limit(policy->cpu, &limit);
|
||||
if (cpufreq_driver->bios_limit) {
|
||||
ret = cpufreq_driver->bios_limit(policy->cpu, &limit);
|
||||
if (!ret)
|
||||
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 freq_attr **drv_attr;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
unsigned int j;
|
||||
|
@ -786,31 +747,28 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
|
|||
return ret;
|
||||
|
||||
/* set up files for this cpu device */
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
drv_attr = driver->attr;
|
||||
drv_attr = cpufreq_driver->attr;
|
||||
while ((drv_attr) && (*drv_attr)) {
|
||||
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
|
||||
if (ret)
|
||||
goto err_out_unlock;
|
||||
goto err_out_kobj_put;
|
||||
drv_attr++;
|
||||
}
|
||||
if (driver->get) {
|
||||
if (cpufreq_driver->get) {
|
||||
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
|
||||
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);
|
||||
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);
|
||||
if (ret)
|
||||
goto err_out_unlock;
|
||||
goto err_out_kobj_put;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
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;
|
||||
|
||||
if (ret) {
|
||||
int (*exit)(struct cpufreq_policy *policy);
|
||||
|
||||
pr_debug("setting policy failed\n");
|
||||
rcu_read_lock();
|
||||
exit = rcu_dereference(cpufreq_driver)->exit;
|
||||
rcu_read_unlock();
|
||||
if (exit)
|
||||
exit(policy);
|
||||
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
}
|
||||
return ret;
|
||||
|
||||
err_out_unlock:
|
||||
rcu_read_unlock();
|
||||
err_out_kobj_put:
|
||||
kobject_put(&policy->kobj);
|
||||
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 cpufreq_policy *policy;
|
||||
int ret = 0, has_target = 0;
|
||||
int ret = 0, has_target = !!cpufreq_driver->target;
|
||||
unsigned long flags;
|
||||
|
||||
policy = cpufreq_cpu_get(sibling);
|
||||
WARN_ON(!policy);
|
||||
|
||||
rcu_read_lock();
|
||||
has_target = !!rcu_dereference(cpufreq_driver)->target;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (has_target)
|
||||
__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;
|
||||
int ret = -ENOMEM;
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_driver *driver;
|
||||
int (*init)(struct cpufreq_policy *policy);
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpufreq_governor *gov;
|
||||
|
@ -947,15 +891,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!try_module_get(driver->owner)) {
|
||||
rcu_read_unlock();
|
||||
if (!try_module_get(cpufreq_driver->owner)) {
|
||||
ret = -EINVAL;
|
||||
goto module_out;
|
||||
}
|
||||
init = driver->init;
|
||||
rcu_read_unlock();
|
||||
|
||||
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
|
||||
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
|
||||
* to accept all calls to ->verify and ->setpolicy for this CPU
|
||||
*/
|
||||
ret = init(policy);
|
||||
ret = cpufreq_driver->init(policy);
|
||||
if (ret) {
|
||||
pr_debug("initialization failed\n");
|
||||
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;
|
||||
|
||||
kobject_uevent(&policy->kobj, KOBJ_ADD);
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
module_put(cpufreq_driver->owner);
|
||||
pr_debug("initialization complete\n");
|
||||
|
||||
return 0;
|
||||
|
@ -1039,9 +976,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
err_free_policy:
|
||||
kfree(policy);
|
||||
nomem_out:
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
module_put(cpufreq_driver->owner);
|
||||
module_out:
|
||||
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 long flags;
|
||||
struct cpufreq_policy *data;
|
||||
struct cpufreq_driver *driver;
|
||||
struct kobject *kobj;
|
||||
struct completion *cmp;
|
||||
struct device *cpu_dev;
|
||||
bool has_target;
|
||||
int (*exit)(struct cpufreq_policy *policy);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
has_target = driver->target ? true : false;
|
||||
exit = driver->exit;
|
||||
if (has_target)
|
||||
if (cpufreq_driver->target)
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!driver->setpolicy)
|
||||
if (!cpufreq_driver->setpolicy)
|
||||
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
|
||||
data->governor->name, CPUFREQ_NAME_LEN);
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
|
||||
WARN_ON(lock_policy_rwsem_write(cpu));
|
||||
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 (cpus == 1) {
|
||||
if (has_target)
|
||||
if (cpufreq_driver->target)
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
|
||||
|
||||
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);
|
||||
pr_debug("wait complete\n");
|
||||
|
||||
if (exit)
|
||||
exit(data);
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(data);
|
||||
|
||||
free_cpumask_var(data->related_cpus);
|
||||
free_cpumask_var(data->cpus);
|
||||
kfree(data);
|
||||
} else if (has_target) {
|
||||
} else if (cpufreq_driver->target) {
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_START);
|
||||
__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)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned int (*get)(unsigned int cpu);
|
||||
unsigned int ret_freq = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (driver && driver->setpolicy && driver->get) {
|
||||
get = driver->get;
|
||||
rcu_read_unlock();
|
||||
return get(cpu);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
|
||||
return cpufreq_driver->get(cpu);
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (policy) {
|
||||
|
@ -1297,26 +1216,15 @@ EXPORT_SYMBOL(cpufreq_quick_get_max);
|
|||
static unsigned int __cpufreq_get(unsigned int 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;
|
||||
u8 flags;
|
||||
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!driver->get) {
|
||||
rcu_read_unlock();
|
||||
if (!cpufreq_driver->get)
|
||||
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 &&
|
||||
!(flags & CPUFREQ_CONST_LOOPS)) {
|
||||
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
/* verify no discrepancy between actual and
|
||||
saved value exists */
|
||||
if (unlikely(ret_freq != policy->cur)) {
|
||||
|
@ -1372,7 +1280,6 @@ static struct subsys_interface cpufreq_interface = {
|
|||
*/
|
||||
static int cpufreq_bp_suspend(void)
|
||||
{
|
||||
int (*suspend)(struct cpufreq_policy *policy);
|
||||
int ret = 0;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
|
@ -1385,11 +1292,8 @@ static int cpufreq_bp_suspend(void)
|
|||
if (!cpu_policy)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
suspend = rcu_dereference(cpufreq_driver)->suspend;
|
||||
rcu_read_unlock();
|
||||
if (suspend) {
|
||||
ret = suspend(cpu_policy);
|
||||
if (cpufreq_driver->suspend) {
|
||||
ret = cpufreq_driver->suspend(cpu_policy);
|
||||
if (ret)
|
||||
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
|
||||
"step on CPU %u\n", cpu_policy->cpu);
|
||||
|
@ -1415,7 +1319,6 @@ static int cpufreq_bp_suspend(void)
|
|||
static void cpufreq_bp_resume(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int (*resume)(struct cpufreq_policy *policy);
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *cpu_policy;
|
||||
|
@ -1427,12 +1330,8 @@ static void cpufreq_bp_resume(void)
|
|||
if (!cpu_policy)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
resume = rcu_dereference(cpufreq_driver)->resume;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (resume) {
|
||||
ret = resume(cpu_policy);
|
||||
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);
|
||||
|
@ -1459,14 +1358,10 @@ static struct syscore_ops cpufreq_syscore_ops = {
|
|||
*/
|
||||
const char *cpufreq_get_current_driver(void)
|
||||
{
|
||||
struct cpufreq_driver *driver;
|
||||
const char *name = NULL;
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (driver)
|
||||
name = driver->name;
|
||||
rcu_read_unlock();
|
||||
return name;
|
||||
if (cpufreq_driver)
|
||||
return cpufreq_driver->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_get_current_driver);
|
||||
|
||||
|
@ -1560,9 +1455,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|||
{
|
||||
int retval = -EINVAL;
|
||||
unsigned int old_target_freq = target_freq;
|
||||
int (*target)(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation);
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return -ENODEV;
|
||||
|
@ -1579,11 +1471,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|||
if (target_freq == policy->cur)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
target = rcu_dereference(cpufreq_driver)->target;
|
||||
rcu_read_unlock();
|
||||
if (target)
|
||||
retval = target(policy, target_freq, relation);
|
||||
if (cpufreq_driver->target)
|
||||
retval = cpufreq_driver->target(policy, target_freq, relation);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -1616,24 +1505,18 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_target);
|
|||
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int (*getavg)(struct cpufreq_policy *policy,
|
||||
unsigned int cpu);
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return ret;
|
||||
|
||||
rcu_read_lock();
|
||||
getavg = rcu_dereference(cpufreq_driver)->getavg;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!getavg)
|
||||
if (!cpufreq_driver->getavg)
|
||||
return 0;
|
||||
|
||||
policy = cpufreq_cpu_get(policy->cpu);
|
||||
if (!policy)
|
||||
return -EINVAL;
|
||||
|
||||
ret = getavg(policy, cpu);
|
||||
ret = cpufreq_driver->getavg(policy, cpu);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
return ret;
|
||||
|
@ -1791,9 +1674,6 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
|||
struct cpufreq_policy *policy)
|
||||
{
|
||||
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,
|
||||
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 */
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
verify = driver->verify;
|
||||
setpolicy = driver->setpolicy;
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = verify(policy);
|
||||
ret = cpufreq_driver->verify(policy);
|
||||
if (ret)
|
||||
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,
|
||||
which might be different to the first one */
|
||||
ret = verify(policy);
|
||||
ret = cpufreq_driver->verify(policy);
|
||||
if (ret)
|
||||
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",
|
||||
data->min, data->max);
|
||||
|
||||
if (setpolicy) {
|
||||
if (cpufreq_driver->setpolicy) {
|
||||
data->policy = policy->policy;
|
||||
pr_debug("setting range\n");
|
||||
ret = setpolicy(policy);
|
||||
ret = cpufreq_driver->setpolicy(policy);
|
||||
} else {
|
||||
if (policy->governor != data->governor) {
|
||||
/* 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 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;
|
||||
|
||||
if (!data) {
|
||||
|
@ -1930,18 +1799,13 @@ int cpufreq_update_policy(unsigned int cpu)
|
|||
|
||||
/* BIOS might change freq behind our back
|
||||
-> ask driver for current freq and notify governors about a change */
|
||||
rcu_read_lock();
|
||||
driver = rcu_access_pointer(cpufreq_driver);
|
||||
get = driver->get;
|
||||
target = driver->target;
|
||||
rcu_read_unlock();
|
||||
if (get) {
|
||||
policy.cur = get(cpu);
|
||||
if (cpufreq_driver->get) {
|
||||
policy.cur = cpufreq_driver->get(cpu);
|
||||
if (!data->cur) {
|
||||
pr_debug("Driver did not initialize current freq");
|
||||
data->cur = policy.cur;
|
||||
} else {
|
||||
if (data->cur != policy.cur && target)
|
||||
if (data->cur != policy.cur && cpufreq_driver->target)
|
||||
cpufreq_out_of_sync(cpu, data->cur,
|
||||
policy.cur);
|
||||
}
|
||||
|
@ -2020,19 +1884,18 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
driver_data->flags |= CPUFREQ_CONST_LOOPS;
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
if (rcu_access_pointer(cpufreq_driver)) {
|
||||
if (cpufreq_driver) {
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
rcu_assign_pointer(cpufreq_driver, driver_data);
|
||||
cpufreq_driver = driver_data;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
|
||||
ret = subsys_interface_register(&cpufreq_interface);
|
||||
if (ret)
|
||||
goto err_null_driver;
|
||||
|
||||
if (!(driver_data->flags & CPUFREQ_STICKY)) {
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
|
||||
int i;
|
||||
ret = -ENODEV;
|
||||
|
||||
|
@ -2059,9 +1922,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
subsys_interface_unregister(&cpufreq_interface);
|
||||
err_null_driver:
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
rcu_assign_pointer(cpufreq_driver, NULL);
|
||||
cpufreq_driver = NULL;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
||||
|
@ -2078,15 +1940,9 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
|||
int cpufreq_unregister_driver(struct cpufreq_driver *driver)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct cpufreq_driver *old_driver;
|
||||
|
||||
rcu_read_lock();
|
||||
old_driver = rcu_access_pointer(cpufreq_driver);
|
||||
if (!old_driver || (driver != old_driver)) {
|
||||
rcu_read_unlock();
|
||||
if (!cpufreq_driver || (driver != cpufreq_driver))
|
||||
return -EINVAL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
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);
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
rcu_assign_pointer(cpufreq_driver, NULL);
|
||||
cpufreq_driver = NULL;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue