Commit 618b27dc authored by Dave Jones's avatar Dave Jones

[CPUFREQ] Locking fixes [2/11]

As the per-CPU initialization can fail, we need to deal with this
situation in cpufreq_remove_dev as the sysdev core doesn't (yet) do
this for us. The solution: add a "struct cpufreq_policy
*cpufreq_cpu_data[NR_CPUS]" array, which has a NULL pointer for each
CPU not managed by cpufreq (yet) and a pointer to the per-CPU data
for each CPU managed by cpufreq. It is locked by cpufreq_driver_lock.
parent 807ea9d6
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
/** /**
* The "cpufreq driver" - the arch- or hardware-dependend low * The "cpufreq driver" - the arch- or hardware-dependend low
* level driver of CPUFreq support, and its spinlock. * level driver of CPUFreq support, and its spinlock. This lock
* cpu_max_freq is in kHz. * also protects the cpufreq_cpu_data array.
*/ */
static struct cpufreq_driver *cpufreq_driver; static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
/* will go away once the locking mess is cleaned up */ /* will go away once the locking mess is cleaned up */
...@@ -72,7 +73,10 @@ static int cpufreq_cpu_get(unsigned int cpu) ...@@ -72,7 +73,10 @@ static int cpufreq_cpu_get(unsigned int cpu)
/* get the CPU */ /* get the CPU */
data = &cpufreq_driver->policy[cpu]; data = cpufreq_cpu_data[cpu];
if (!data)
goto err_out_put_module;
if (!kobject_get(&data->kobj)) if (!kobject_get(&data->kobj))
goto err_out_put_module; goto err_out_put_module;
...@@ -349,15 +353,17 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -349,15 +353,17 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
struct cpufreq_policy new_policy; struct cpufreq_policy new_policy;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct freq_attr **drv_attr; struct freq_attr **drv_attr;
unsigned long flags;
if (!try_module_get(cpufreq_driver->owner)) if (!try_module_get(cpufreq_driver->owner))
return -EINVAL; return -EINVAL;
policy = &cpufreq_driver->policy[cpu];
policy->cpu = cpu;
/* 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
*/ */
policy = &cpufreq_driver->policy[cpu];
policy->cpu = cpu;
ret = cpufreq_driver->init(policy); ret = cpufreq_driver->init(policy);
if (ret) if (ret)
goto out; goto out;
...@@ -388,9 +394,16 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -388,9 +394,16 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
drv_attr++; drv_attr++;
} }
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
/* set default policy */ /* set default policy */
ret = cpufreq_set_policy(&new_policy); ret = cpufreq_set_policy(&new_policy);
if (ret) { if (ret) {
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_unregister(&policy->kobj); kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister); wait_for_completion(&policy->kobj_unregister);
} }
...@@ -409,6 +422,15 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -409,6 +422,15 @@ static int cpufreq_add_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; unsigned int cpu = sys_dev->id;
unsigned long flags;
spin_lock_irqsave(&cpufreq_driver_lock, flags);
if (!cpufreq_cpu_data[cpu]) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EINVAL;
}
cpufreq_cpu_data[cpu] = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) if (!kobject_get(&cpufreq_driver->policy[cpu].kobj))
return -EFAULT; return -EFAULT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment