--- a/drivers/cpuidle/governors/ladder.c +++ a/drivers/cpuidle/governors/ladder.c @@ -192,4 +192,14 @@ static int __init init_ladder(void) return cpuidle_register_governor(&ladder_governor); } -postcore_initcall(init_ladder); +/** + * exit_ladder - exits the governor + */ +static void __exit exit_ladder(void) +{ + cpuidle_unregister_governor(&ladder_governor); +} + +MODULE_LICENSE("GPL"); +module_init(init_ladder); +module_exit(exit_ladder); --- a/drivers/cpuidle/governors/menu.c +++ a/drivers/cpuidle/governors/menu.c @@ -540,4 +540,14 @@ static int __init init_menu(void) return cpuidle_register_governor(&menu_governor); } -postcore_initcall(init_menu); +/** + * exit_menu - exits the governor + */ +static void __exit exit_menu(void) +{ + cpuidle_unregister_governor(&menu_governor); +} + +MODULE_LICENSE("GPL"); +module_init(init_menu); +module_exit(exit_menu); --- a/Documentation/cpuidle/governor.txt +++ a/Documentation/cpuidle/governor.txt @@ -25,4 +25,5 @@ kernel configuration and platform will be selected by cpuidle. Interfaces: extern int cpuidle_register_governor(struct cpuidle_governor *gov); +extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); struct cpuidle_governor --- a/drivers/cpuidle/governor.c +++ a/drivers/cpuidle/governor.c @@ -96,3 +96,46 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) return ret; } + +/** + * cpuidle_replace_governor - find a replacement governor + * @exclude_rating: the rating that will be skipped while looking for + * new governor. + */ +static struct cpuidle_governor *cpuidle_replace_governor(int exclude_rating) +{ + struct cpuidle_governor *gov; + struct cpuidle_governor *ret_gov = NULL; + unsigned int max_rating = 0; + + list_for_each_entry(gov, &cpuidle_governors, governor_list) { + if (gov->rating == exclude_rating) + continue; + if (gov->rating > max_rating) { + max_rating = gov->rating; + ret_gov = gov; + } + } + + return ret_gov; +} + +/** + * cpuidle_unregister_governor - unregisters a governor + * @gov: the governor + */ +void cpuidle_unregister_governor(struct cpuidle_governor *gov) +{ + if (!gov) + return; + + mutex_lock(&cpuidle_lock); + if (gov == cpuidle_curr_governor) { + struct cpuidle_governor *new_gov; + new_gov = cpuidle_replace_governor(gov->rating); + cpuidle_switch_governor(new_gov); + } + list_del(&gov->governor_list); + mutex_unlock(&cpuidle_lock); +} + --- a/include/linux/cpuidle.h +++ a/include/linux/cpuidle.h @@ -195,10 +195,16 @@ struct cpuidle_governor { }; #ifdef CONFIG_CPU_IDLE + extern int cpuidle_register_governor(struct cpuidle_governor *gov); +extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); + #else + static inline int cpuidle_register_governor(struct cpuidle_governor *gov) {return 0;} +static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { } + #endif #ifdef CONFIG_ARCH_HAS_CPU_RELAX