mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 10:19:47 +00:00
![Daniel Lezcano](/assets/img/avatar_default.png)
The usual scheme to initialize a cpuidle driver on a SMP is: cpuidle_register_driver(drv); for_each_possible_cpu(cpu) { device = &per_cpu(cpuidle_dev, cpu); cpuidle_register_device(device); } This code is duplicated in each cpuidle driver. On UP systems, it is done this way: cpuidle_register_driver(drv); device = &per_cpu(cpuidle_dev, cpu); cpuidle_register_device(device); On UP, the macro 'for_each_cpu' does one iteration: #define for_each_cpu(cpu, mask) \ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) Hence, the initialization loop is the same for UP than SMP. Beside, we saw different bugs / mis-initialization / return code unchecked in the different drivers, the code is duplicated including bugs. After fixing all these ones, it appears the initialization pattern is the same for everyone. Please note, some drivers are doing dev->state_count = drv->state_count. This is not necessary because it is done by the cpuidle_enable_device function in the cpuidle framework. This is true, until you have the same states for all your devices. Otherwise, the 'low level' API should be used instead with the specific initialization for the driver. Let's add a wrapper function doing this initialization with a cpumask parameter for the coupled idle states and use it for all the drivers. That will save a lot of LOC, consolidate the code, and the modifications in the future could be done in a single place. Another benefit is the consolidation of the cpuidle_device variable which is now in the cpuidle framework and no longer spread accross the different arch specific drivers. Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
37 lines
1.4 KiB
Text
37 lines
1.4 KiB
Text
|
|
|
|
Supporting multiple CPU idle levels in kernel
|
|
|
|
cpuidle drivers
|
|
|
|
|
|
|
|
|
|
cpuidle driver hooks into the cpuidle infrastructure and handles the
|
|
architecture/platform dependent part of CPU idle states. Driver
|
|
provides the platform idle state detection capability and also
|
|
has mechanisms in place to support actual entry-exit into CPU idle states.
|
|
|
|
cpuidle driver initializes the cpuidle_device structure for each CPU device
|
|
and registers with cpuidle using cpuidle_register_device.
|
|
|
|
If all the idle states are the same, the wrapper function cpuidle_register
|
|
could be used instead.
|
|
|
|
It can also support the dynamic changes (like battery <-> AC), by using
|
|
cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device,
|
|
cpuidle_resume_and_unlock.
|
|
|
|
Interfaces:
|
|
extern int cpuidle_register(struct cpuidle_driver *drv,
|
|
const struct cpumask *const coupled_cpus);
|
|
extern int cpuidle_unregister(struct cpuidle_driver *drv);
|
|
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
|
|
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
|
|
extern int cpuidle_register_device(struct cpuidle_device *dev);
|
|
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
|
|
|
|
extern void cpuidle_pause_and_lock(void);
|
|
extern void cpuidle_resume_and_unlock(void);
|
|
extern int cpuidle_enable_device(struct cpuidle_device *dev);
|
|
extern void cpuidle_disable_device(struct cpuidle_device *dev);
|