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/cpuidle.h> 13 14 #include "cpuidle.h" 15 16 LIST_HEAD(cpuidle_governors); 17 struct cpuidle_governor *cpuidle_curr_governor; 18 19 /** 20 * __cpuidle_find_governor - finds a governor of the specified name 21 * @str: the name 22 * 23 * Must be called with cpuidle_lock acquired. 24 */ 25 static struct cpuidle_governor * __cpuidle_find_governor(const char *str) 26 { 27 struct cpuidle_governor *gov; 28 29 list_for_each_entry(gov, &cpuidle_governors, governor_list) 30 if (!strncasecmp(str, gov->name, CPUIDLE_NAME_LEN)) 31 return gov; 32 33 return NULL; 34 } 35 36 /** 37 * cpuidle_switch_governor - changes the governor 38 * @gov: the new target governor 39 * 40 * NOTE: "gov" can be NULL to specify disabled 41 * Must be called with cpuidle_lock acquired. 42 */ 43 int cpuidle_switch_governor(struct cpuidle_governor *gov) 44 { 45 struct cpuidle_device *dev; 46 47 if (gov == cpuidle_curr_governor) 48 return 0; 49 50 cpuidle_uninstall_idle_handler(); 51 52 if (cpuidle_curr_governor) { 53 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 54 cpuidle_disable_device(dev); 55 } 56 57 cpuidle_curr_governor = gov; 58 59 if (gov) { 60 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 61 cpuidle_enable_device(dev); 62 cpuidle_install_idle_handler(); 63 printk(KERN_INFO "cpuidle: using governor %s\n", gov->name); 64 } 65 66 return 0; 67 } 68 69 /** 70 * cpuidle_register_governor - registers a governor 71 * @gov: the governor 72 */ 73 int cpuidle_register_governor(struct cpuidle_governor *gov) 74 { 75 int ret = -EEXIST; 76 77 if (!gov || !gov->select) 78 return -EINVAL; 79 80 if (cpuidle_disabled()) 81 return -ENODEV; 82 83 mutex_lock(&cpuidle_lock); 84 if (__cpuidle_find_governor(gov->name) == NULL) { 85 ret = 0; 86 list_add_tail(&gov->governor_list, &cpuidle_governors); 87 if (!cpuidle_curr_governor || 88 cpuidle_curr_governor->rating < gov->rating) 89 cpuidle_switch_governor(gov); 90 } 91 mutex_unlock(&cpuidle_lock); 92 93 return ret; 94 } 95