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/cpu.h> 12 #include <linux/cpuidle.h> 13 #include <linux/mutex.h> 14 #include <linux/pm_qos.h> 15 16 #include "cpuidle.h" 17 18 LIST_HEAD(cpuidle_governors); 19 struct cpuidle_governor *cpuidle_curr_governor; 20 21 /** 22 * __cpuidle_find_governor - finds a governor of the specified name 23 * @str: the name 24 * 25 * Must be called with cpuidle_lock acquired. 26 */ 27 static struct cpuidle_governor * __cpuidle_find_governor(const char *str) 28 { 29 struct cpuidle_governor *gov; 30 31 list_for_each_entry(gov, &cpuidle_governors, governor_list) 32 if (!strncasecmp(str, gov->name, CPUIDLE_NAME_LEN)) 33 return gov; 34 35 return NULL; 36 } 37 38 /** 39 * cpuidle_switch_governor - changes the governor 40 * @gov: the new target governor 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) 48 return -EINVAL; 49 50 if (gov == cpuidle_curr_governor) 51 return 0; 52 53 cpuidle_uninstall_idle_handler(); 54 55 if (cpuidle_curr_governor) { 56 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 57 cpuidle_disable_device(dev); 58 } 59 60 cpuidle_curr_governor = gov; 61 62 if (gov) { 63 list_for_each_entry(dev, &cpuidle_detected_devices, device_list) 64 cpuidle_enable_device(dev); 65 cpuidle_install_idle_handler(); 66 printk(KERN_INFO "cpuidle: using governor %s\n", gov->name); 67 } 68 69 return 0; 70 } 71 72 /** 73 * cpuidle_register_governor - registers a governor 74 * @gov: the governor 75 */ 76 int cpuidle_register_governor(struct cpuidle_governor *gov) 77 { 78 int ret = -EEXIST; 79 80 if (!gov || !gov->select) 81 return -EINVAL; 82 83 if (cpuidle_disabled()) 84 return -ENODEV; 85 86 mutex_lock(&cpuidle_lock); 87 if (__cpuidle_find_governor(gov->name) == NULL) { 88 ret = 0; 89 list_add_tail(&gov->governor_list, &cpuidle_governors); 90 if (!cpuidle_curr_governor || 91 cpuidle_curr_governor->rating < gov->rating) 92 cpuidle_switch_governor(gov); 93 } 94 mutex_unlock(&cpuidle_lock); 95 96 return ret; 97 } 98 99 /** 100 * cpuidle_governor_latency_req - Compute a latency constraint for CPU 101 * @cpu: Target CPU 102 */ 103 int cpuidle_governor_latency_req(unsigned int cpu) 104 { 105 int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); 106 struct device *device = get_cpu_device(cpu); 107 int device_req = dev_pm_qos_raw_read_value(device); 108 109 return device_req < global_req ? device_req : global_req; 110 } 111