* Arun R Bharadwaj <a...@linux.vnet.ibm.com> [2009-09-01 17:07:04]: Implement a LIFO based approach for registering arch dependent idle routines.
This is a prototype for pseries, needs to be extended for other platforms. Signed-off-by: Arun R Bharadwaj <a...@linux.vnet.ibm.com> --- arch/powerpc/kernel/idle.c | 5 +++++ drivers/cpuidle/cpuidle.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 10 ++++++++++ 3 files changed, 52 insertions(+) Index: linux.trees.git/arch/powerpc/kernel/idle.c =================================================================== --- linux.trees.git.orig/arch/powerpc/kernel/idle.c +++ linux.trees.git/arch/powerpc/kernel/idle.c @@ -46,6 +46,11 @@ static int __init powersave_off(char *ar } __setup("powersave=off", powersave_off); +void set_arch_idle(void (*idle)(void)) +{ + ppc_md.power_save = idle; +} + /* * The body of the idle task. */ Index: linux.trees.git/include/linux/pm.h =================================================================== --- linux.trees.git.orig/include/linux/pm.h +++ linux.trees.git/include/linux/pm.h @@ -30,6 +30,16 @@ extern void (*pm_idle)(void); extern void (*pm_power_off)(void); extern void (*pm_power_off_prepare)(void); +struct idle_function_desc { + char *name; + void (*idle_func)(void); + struct list_head idle_list; +}; + +extern void set_arch_idle(void (*idle)(void)); +extern void register_idle_function(struct idle_function_desc *desc); +extern void unregister_idle_function(struct idle_function_desc *desc); + /* * Device power management */ Index: linux.trees.git/drivers/cpuidle/cpuidle.c =================================================================== --- linux.trees.git.orig/drivers/cpuidle/cpuidle.c +++ linux.trees.git/drivers/cpuidle/cpuidle.c @@ -44,6 +44,43 @@ static void cpuidle_kick_cpus(void) static void cpuidle_kick_cpus(void) {} #endif +LIST_HEAD(idle_function_list); +static DEFINE_MUTEX(idle_list_mutex); + +void register_idle_function(struct idle_function_desc *desc) +{ + mutex_lock(&idle_list_mutex); + + list_add(&desc->idle_list, &idle_function_list); + set_arch_idle(desc->idle_func); + cpuidle_kick_cpus(); + + mutex_unlock(&idle_list_mutex); +} + +void unregister_idle_function(struct idle_function_desc *desc) +{ + struct list_head *pos; + struct idle_function_desc *temp_desc; + + mutex_lock(&idle_list_mutex); + WARN_ON_ONCE(list_empty(&desc->idle_list) || desc != NULL); + + list_for_each(pos, &idle_function_list) { + temp_desc = container_of(pos, struct idle_function_desc, + idle_list); + if (temp_desc == desc) { + list_del(&temp_desc->idle_list); + /* Re-using temp_desc here */ + temp_desc = list_first_entry(&idle_function_list, + struct idle_function_desc, idle_list); + set_arch_idle(temp_desc->idle_func); + cpuidle_kick_cpus(); + } + } + mutex_unlock(&idle_list_mutex); +} + static int __cpuidle_register_device(struct cpuidle_device *dev); /** _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev