Commit 7eb28b19 authored by Dave Jones's avatar Dave Jones Committed by Dave Jones

[CPUFREQ][3/4] cpufreq "cpu group" awareness: do symlinks for other CPUs...

[CPUFREQ][3/4] cpufreq "cpu group" awareness: do symlinks for other CPUs instead of registering kobjects

Only register each "affected_cpu_mask" once, and do symlinks for those
CPUs not directly registered to the driver model.

Zwane Mwaikambo tested it, and here is the result:

root@morocco cpu {0:0} pwd
/sys/devices/system/cpu
root@morocco cpu {0:0} tree
.
|-- cpu0
|   |-- cpufreq
|   |   |-- cpuinfo_cur_freq
|   |   |-- ...
|   |   -- scaling_setspeed
|   -- online
-- cpu1
    |-- cpufreq -> ../../../../devices/system/cpu/cpu0/cpufreq
    -- online
Signed-off-by: default avatarDominik Brodowski <linux@brodo.de>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
parent 0c2e5915
...@@ -162,6 +162,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) ...@@ -162,6 +162,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
*/ */
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((likely(cpufreq_cpu_data[freqs->cpu])) && if ((likely(cpufreq_cpu_data[freqs->cpu])) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu)) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) && (likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{ {
...@@ -176,7 +177,8 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) ...@@ -176,7 +177,8 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
case CPUFREQ_POSTCHANGE: case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
if (likely(cpufreq_cpu_data[freqs->cpu])) if ((likely(cpufreq_cpu_data[freqs->cpu])) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu)))
cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
break; break;
} }
...@@ -464,6 +466,18 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -464,6 +466,18 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct freq_attr **drv_attr; struct freq_attr **drv_attr;
unsigned long flags; unsigned long flags;
unsigned int j;
#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
* CPU because it is in the same boat. */
policy = cpufreq_cpu_get(cpu);
if (unlikely(policy)) {
cpu_sys_devices[cpu] = sys_dev;
sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq");
return 0;
}
#endif
if (!try_module_get(cpufreq_driver->owner)) if (!try_module_get(cpufreq_driver->owner))
return -EINVAL; return -EINVAL;
...@@ -512,7 +526,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -512,7 +526,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = policy; for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
policy->governor = NULL; /* to assure that the starting sequence is policy->governor = NULL; /* to assure that the starting sequence is
* run in cpufreq_set_policy */ * run in cpufreq_set_policy */
...@@ -531,7 +546,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -531,7 +546,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
err_out_unregister: err_out_unregister:
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = NULL; for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_unregister(&policy->kobj); kobject_unregister(&policy->kobj);
...@@ -556,21 +572,69 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) ...@@ -556,21 +572,69 @@ 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; unsigned long flags;
struct cpufreq_policy *data; struct cpufreq_policy *data;
#ifdef CONFIG_SMP
cpu_sys_devices[cpu] = NULL; unsigned int j;
#endif
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
data = cpufreq_cpu_data[cpu]; data = cpufreq_cpu_data[cpu];
if (!data) { if (!data) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
cpu_sys_devices[cpu] = NULL;
return -EINVAL; return -EINVAL;
} }
cpufreq_cpu_data[cpu] = NULL; cpufreq_cpu_data[cpu] = NULL;
#ifdef CONFIG_SMP
/* if this isn't the CPU which is the parent of the kobj, we
* only need to unlink, put and exit
*/
if (unlikely(cpu != data->cpu)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
sysfs_remove_link(&sys_dev->kobj, "cpufreq");
cpu_sys_devices[cpu] = NULL;
cpufreq_cpu_put(data);
return 0;
}
#endif
if (!kobject_get(&data->kobj)) cpu_sys_devices[cpu] = NULL;
if (!kobject_get(&data->kobj)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EFAULT; return -EFAULT;
}
#ifdef CONFIG_SMP
/* 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
* links afterwards.
*/
if (unlikely(cpus_weight(data->cpus) > 1)) {
for_each_cpu_mask(j, data->cpus) {
if (j == cpu)
continue;
cpufreq_cpu_data[j] = NULL;
}
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (unlikely(cpus_weight(data->cpus) > 1)) {
for_each_cpu_mask(j, data->cpus) {
if (j == cpu)
continue;
sysfs_remove_link(&cpu_sys_devices[j]->kobj, "cpufreq");
cpufreq_cpu_put(data);
}
}
#else
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
if (cpufreq_driver->target) if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP); __cpufreq_governor(data, CPUFREQ_GOV_STOP);
...@@ -689,6 +753,12 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -689,6 +753,12 @@ static int cpufreq_resume(struct sys_device * sysdev)
if (!cpu_policy) if (!cpu_policy)
return -EINVAL; return -EINVAL;
/* only handle each CPU group once */
if (unlikely(cpu_policy->cpu != cpu)) {
cpufreq_cpu_put(cpu_policy);
return 0;
}
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0; unsigned int cur_freq = 0;
......
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