Messages in this thread Patch in this message | | | Date | Tue, 1 Sep 2009 17:09:41 +0530 | From | Arun R Bharadwaj <> | Subject | [v4 PATCH 2/5]: cpuidle: Implement routines to register and unregister idle function. |
| |
* Arun R Bharadwaj <arun@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 <arun@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); /**
| |