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