1/* 2 * governor.c - governor support 3 * 4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 5 * Shaohua Li <shaohua.li@intel.com> 6 * Adam Belay <abelay@novell.com> 7 * 8 * This code is licenced under the GPL. 9 */ 10 11#include <linux/mutex.h> 12#include <linux/module.h> 13#include <linux/cpuidle.h> 14 15#include "cpuidle.h" 16 17LIST_HEAD(cpuidle_governors); 18struct cpuidle_governor *cpuidle_curr_governor; 19 20/** 21 * __cpuidle_find_governor - finds a governor of the specified name 22 * @str: the name 23 * 24 * Must be called with cpuidle_lock acquired. 25 */ 26static struct cpuidle_governor * __cpuidle_find_governor(const char *str) 27{ 28 struct cpuidle_governor *gov; 29 30 list_for_each_entry(gov, &cpuidle_governors, governor_list) 31 if (!strncasecmp(str, gov->name, CPUIDLE_NAME_LEN)) 32 return gov; 33 34 return NULL; 35} 36 37/** 38 * cpuidle_switch_governor - changes the governor 39 * @gov: the new target governor 40 * 41 * NOTE: "gov" can be NULL to specify disabled 42 * Must be called with cpuidle_lock acquired. 43 */ 44int cpuidle_switch_governor(struct cpuidle_governor *gov) 45{ 46 struct cpuidle_device *dev; 47 48 if (gov == cpuidle_curr_governor) 49 return 0; 50 51 cpuidle_uninstall_idle_handler(); 52 53 if (cpuidle_curr_governor) { 54 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 55 cpuidle_disable_device(dev); 56 module_put(cpuidle_curr_governor->owner); 57 } 58 59 cpuidle_curr_governor = gov; 60 61 if (gov) { 62 if (!try_module_get(cpuidle_curr_governor->owner)) 63 return -EINVAL; 64 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 65 cpuidle_enable_device(dev); 66 cpuidle_install_idle_handler(); 67 printk(KERN_INFO "cpuidle: using governor %s\n", gov->name); 68 } 69 70 return 0; 71} 72 73/** 74 * cpuidle_register_governor - registers a governor 75 * @gov: the governor 76 */ 77int cpuidle_register_governor(struct cpuidle_governor *gov) 78{ 79 int ret = -EEXIST; 80 81 if (!gov || !gov->select) 82 return -EINVAL; 83 84 if (cpuidle_disabled()) 85 return -ENODEV; 86 87 mutex_lock(&cpuidle_lock); 88 if (__cpuidle_find_governor(gov->name) == NULL) { 89 ret = 0; 90 list_add_tail(&gov->governor_list, &cpuidle_governors); 91 if (!cpuidle_curr_governor || 92 cpuidle_curr_governor->rating < gov->rating) 93 cpuidle_switch_governor(gov); 94 } 95 mutex_unlock(&cpuidle_lock); 96 97 return ret; 98} 99