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 17 LIST_HEAD(cpuidle_governors); 18 struct 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 aquired. 25 */ 26 static 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 (!strnicmp(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 aquired. 43 */ 44 int 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 */ 77 int cpuidle_register_governor(struct cpuidle_governor *gov) 78 { 79 int ret = -EEXIST; 80 81 if (!gov || !gov->select) 82 return -EINVAL; 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 97 /** 98 * cpuidle_replace_governor - find a replacement governor 99 * @exclude_rating: the rating that will be skipped while looking for 100 * new governor. 101 */ 102 static struct cpuidle_governor *cpuidle_replace_governor(int exclude_rating) 103 { 104 struct cpuidle_governor *gov; 105 struct cpuidle_governor *ret_gov = NULL; 106 unsigned int max_rating = 0; 107 108 list_for_each_entry(gov, &cpuidle_governors, governor_list) { 109 if (gov->rating == exclude_rating) 110 continue; 111 if (gov->rating > max_rating) { 112 max_rating = gov->rating; 113 ret_gov = gov; 114 } 115 } 116 117 return ret_gov; 118 } 119 120 /** 121 * cpuidle_unregister_governor - unregisters a governor 122 * @gov: the governor 123 */ 124 void cpuidle_unregister_governor(struct cpuidle_governor *gov) 125 { 126 if (!gov) 127 return; 128 129 mutex_lock(&cpuidle_lock); 130 if (gov == cpuidle_curr_governor) { 131 struct cpuidle_governor *new_gov; 132 new_gov = cpuidle_replace_governor(gov->rating); 133 cpuidle_switch_governor(new_gov); 134 } 135 list_del(&gov->governor_list); 136 mutex_unlock(&cpuidle_lock); 137 } 138 139