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 * Must be called with cpuidle_lock acquired. 40 */ 41 int cpuidle_switch_governor(struct cpuidle_governor *gov) 42 { 43 struct cpuidle_device *dev; 44 45 if (!gov) 46 return -EINVAL; 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 } 57 58 cpuidle_curr_governor = gov; 59 60 if (gov) { 61 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 62 cpuidle_enable_device(dev); 63 cpuidle_install_idle_handler(); 64 printk(KERN_INFO "cpuidle: using governor %s\n", gov->name); 65 } 66 67 return 0; 68 } 69 70 /** 71 * cpuidle_register_governor - registers a governor 72 * @gov: the governor 73 */ 74 int cpuidle_register_governor(struct cpuidle_governor *gov) 75 { 76 int ret = -EEXIST; 77 78 if (!gov || !gov->select) 79 return -EINVAL; 80 81 if (cpuidle_disabled()) 82 return -ENODEV; 83 84 mutex_lock(&cpuidle_lock); 85 if (__cpuidle_find_governor(gov->name) == NULL) { 86 ret = 0; 87 list_add_tail(&gov->governor_list, &cpuidle_governors); 88 if (!cpuidle_curr_governor || 89 cpuidle_curr_governor->rating < gov->rating) 90 cpuidle_switch_governor(gov); 91 } 92 mutex_unlock(&cpuidle_lock); 93 94 return ret; 95 } 96