Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thermal: cpu_cooling: implement the power cooling device API

Add a basic power model to the cpu cooling device to implement the
power cooling device API. The power model uses the current frequency,
current load and OPPs for the power calculations. The cpus must have
registered their OPPs using the OPP library.

Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
Signed-off-by: Kapileshwar Singh <kapileshwar.singh@arm.com>
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Signed-off-by: Javi Merino <javi.merino@arm.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>

authored by

Javi Merino and committed by
Eduardo Valentin
c36cf071 35b11d2e

+761 -19
+155 -1
Documentation/thermal/cpu-cooling-api.txt
··· 36 36 np: pointer to the cooling device device tree node 37 37 clip_cpus: cpumask of cpus where the frequency constraints will happen. 38 38 39 - 1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 39 + 1.1.3 struct thermal_cooling_device *cpufreq_power_cooling_register( 40 + const struct cpumask *clip_cpus, u32 capacitance, 41 + get_static_t plat_static_func) 42 + 43 + Similar to cpufreq_cooling_register, this function registers a cpufreq 44 + cooling device. Using this function, the cooling device will 45 + implement the power extensions by using a simple cpu power model. The 46 + cpus must have registered their OPPs using the OPP library. 47 + 48 + The additional parameters are needed for the power model (See 2. Power 49 + models). "capacitance" is the dynamic power coefficient (See 2.1 50 + Dynamic power). "plat_static_func" is a function to calculate the 51 + static power consumed by these cpus (See 2.2 Static power). 52 + 53 + 1.1.4 struct thermal_cooling_device *of_cpufreq_power_cooling_register( 54 + struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance, 55 + get_static_t plat_static_func) 56 + 57 + Similar to cpufreq_power_cooling_register, this function register a 58 + cpufreq cooling device with power extensions using the device tree 59 + information supplied by the np parameter. 60 + 61 + 1.1.5 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 40 62 41 63 This interface function unregisters the "thermal-cpufreq-%x" cooling device. 42 64 43 65 cdev: Cooling device pointer which has to be unregistered. 66 + 67 + 2. Power models 68 + 69 + The power API registration functions provide a simple power model for 70 + CPUs. The current power is calculated as dynamic + (optionally) 71 + static power. This power model requires that the operating-points of 72 + the CPUs are registered using the kernel's opp library and the 73 + `cpufreq_frequency_table` is assigned to the `struct device` of the 74 + cpu. If you are using CONFIG_CPUFREQ_DT then the 75 + `cpufreq_frequency_table` should already be assigned to the cpu 76 + device. 77 + 78 + The `plat_static_func` parameter of `cpufreq_power_cooling_register()` 79 + and `of_cpufreq_power_cooling_register()` is optional. If you don't 80 + provide it, only dynamic power will be considered. 81 + 82 + 2.1 Dynamic power 83 + 84 + The dynamic power consumption of a processor depends on many factors. 85 + For a given processor implementation the primary factors are: 86 + 87 + - The time the processor spends running, consuming dynamic power, as 88 + compared to the time in idle states where dynamic consumption is 89 + negligible. Herein we refer to this as 'utilisation'. 90 + - The voltage and frequency levels as a result of DVFS. The DVFS 91 + level is a dominant factor governing power consumption. 92 + - In running time the 'execution' behaviour (instruction types, memory 93 + access patterns and so forth) causes, in most cases, a second order 94 + variation. In pathological cases this variation can be significant, 95 + but typically it is of a much lesser impact than the factors above. 96 + 97 + A high level dynamic power consumption model may then be represented as: 98 + 99 + Pdyn = f(run) * Voltage^2 * Frequency * Utilisation 100 + 101 + f(run) here represents the described execution behaviour and its 102 + result has a units of Watts/Hz/Volt^2 (this often expressed in 103 + mW/MHz/uVolt^2) 104 + 105 + The detailed behaviour for f(run) could be modelled on-line. However, 106 + in practice, such an on-line model has dependencies on a number of 107 + implementation specific processor support and characterisation 108 + factors. Therefore, in initial implementation that contribution is 109 + represented as a constant coefficient. This is a simplification 110 + consistent with the relative contribution to overall power variation. 111 + 112 + In this simplified representation our model becomes: 113 + 114 + Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation 115 + 116 + Where `capacitance` is a constant that represents an indicative 117 + running time dynamic power coefficient in fundamental units of 118 + mW/MHz/uVolt^2. Typical values for mobile CPUs might lie in range 119 + from 100 to 500. For reference, the approximate values for the SoC in 120 + ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and 121 + 140 for the Cortex-A53 cluster. 122 + 123 + 124 + 2.2 Static power 125 + 126 + Static leakage power consumption depends on a number of factors. For a 127 + given circuit implementation the primary factors are: 128 + 129 + - Time the circuit spends in each 'power state' 130 + - Temperature 131 + - Operating voltage 132 + - Process grade 133 + 134 + The time the circuit spends in each 'power state' for a given 135 + evaluation period at first order means OFF or ON. However, 136 + 'retention' states can also be supported that reduce power during 137 + inactive periods without loss of context. 138 + 139 + Note: The visibility of state entries to the OS can vary, according to 140 + platform specifics, and this can then impact the accuracy of a model 141 + based on OS state information alone. It might be possible in some 142 + cases to extract more accurate information from system resources. 143 + 144 + The temperature, operating voltage and process 'grade' (slow to fast) 145 + of the circuit are all significant factors in static leakage power 146 + consumption. All of these have complex relationships to static power. 147 + 148 + Circuit implementation specific factors include the chosen silicon 149 + process as well as the type, number and size of transistors in both 150 + the logic gates and any RAM elements included. 151 + 152 + The static power consumption modelling must take into account the 153 + power managed regions that are implemented. Taking the example of an 154 + ARM processor cluster, the modelling would take into account whether 155 + each CPU can be powered OFF separately or if only a single power 156 + region is implemented for the complete cluster. 157 + 158 + In one view, there are others, a static power consumption model can 159 + then start from a set of reference values for each power managed 160 + region (e.g. CPU, Cluster/L2) in each state (e.g. ON, OFF) at an 161 + arbitrary process grade, voltage and temperature point. These values 162 + are then scaled for all of the following: the time in each state, the 163 + process grade, the current temperature and the operating voltage. 164 + However, since both implementation specific and complex relationships 165 + dominate the estimate, the appropriate interface to the model from the 166 + cpu cooling device is to provide a function callback that calculates 167 + the static power in this platform. When registering the cpu cooling 168 + device pass a function pointer that follows the `get_static_t` 169 + prototype: 170 + 171 + int plat_get_static(cpumask_t *cpumask, int interval, 172 + unsigned long voltage, u32 &power); 173 + 174 + `cpumask` is the cpumask of the cpus involved in the calculation. 175 + `voltage` is the voltage at which they are operating. The function 176 + should calculate the average static power for the last `interval` 177 + milliseconds. It returns 0 on success, -E* on error. If it 178 + succeeds, it should store the static power in `power`. Reading the 179 + temperature of the cpus described by `cpumask` is left for 180 + plat_get_static() to do as the platform knows best which thermal 181 + sensor is closest to the cpu. 182 + 183 + If `plat_static_func` is NULL, static power is considered to be 184 + negligible for this platform and only dynamic power is considered. 185 + 186 + The platform specific callback can then use any combination of tables 187 + and/or equations to permute the estimated value. Process grade 188 + information is not passed to the model since access to such data, from 189 + on-chip measurement capability or manufacture time data, is platform 190 + specific. 191 + 192 + Note: the significance of static power for CPUs in comparison to 193 + dynamic power is highly dependent on implementation. Given the 194 + potential complexity in implementation, the importance and accuracy of 195 + its inclusion when using cpu cooling devices should be assessed on a 196 + case by case basis. 197 +
+567 -18
drivers/thermal/cpu_cooling.c
··· 26 26 #include <linux/thermal.h> 27 27 #include <linux/cpufreq.h> 28 28 #include <linux/err.h> 29 + #include <linux/pm_opp.h> 29 30 #include <linux/slab.h> 30 31 #include <linux/cpu.h> 31 32 #include <linux/cpu_cooling.h> ··· 46 45 */ 47 46 48 47 /** 48 + * struct power_table - frequency to power conversion 49 + * @frequency: frequency in KHz 50 + * @power: power in mW 51 + * 52 + * This structure is built when the cooling device registers and helps 53 + * in translating frequency to power and viceversa. 54 + */ 55 + struct power_table { 56 + u32 frequency; 57 + u32 power; 58 + }; 59 + 60 + /** 49 61 * struct cpufreq_cooling_device - data for cooling device with cpufreq 50 62 * @id: unique integer value corresponding to each cpufreq_cooling_device 51 63 * registered. ··· 72 58 * cpufreq frequencies. 73 59 * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. 74 60 * @node: list_head to link all cpufreq_cooling_device together. 61 + * @last_load: load measured by the latest call to cpufreq_get_actual_power() 62 + * @time_in_idle: previous reading of the absolute time that this cpu was idle 63 + * @time_in_idle_timestamp: wall time of the last invocation of 64 + * get_cpu_idle_time_us() 65 + * @dyn_power_table: array of struct power_table for frequency to power 66 + * conversion, sorted in ascending order. 67 + * @dyn_power_table_entries: number of entries in the @dyn_power_table array 68 + * @cpu_dev: the first cpu_device from @allowed_cpus that has OPPs registered 69 + * @plat_get_static_power: callback to calculate the static power 75 70 * 76 71 * This structure is required for keeping information of each registered 77 72 * cpufreq_cooling_device. ··· 94 71 unsigned int *freq_table; /* In descending order */ 95 72 struct cpumask allowed_cpus; 96 73 struct list_head node; 74 + u32 last_load; 75 + u64 *time_in_idle; 76 + u64 *time_in_idle_timestamp; 77 + struct power_table *dyn_power_table; 78 + int dyn_power_table_entries; 79 + struct device *cpu_dev; 80 + get_static_t plat_get_static_power; 97 81 }; 98 82 static DEFINE_IDR(cpufreq_idr); 99 83 static DEFINE_MUTEX(cooling_cpufreq_lock); ··· 197 167 } 198 168 EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); 199 169 170 + static void update_cpu_device(int cpu) 171 + { 172 + struct cpufreq_cooling_device *cpufreq_dev; 173 + 174 + mutex_lock(&cooling_cpufreq_lock); 175 + list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { 176 + if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { 177 + cpufreq_dev->cpu_dev = get_cpu_device(cpu); 178 + if (!cpufreq_dev->cpu_dev) { 179 + dev_warn(&cpufreq_dev->cool_dev->device, 180 + "No cpu device for new policy cpu %d\n", 181 + cpu); 182 + } 183 + break; 184 + } 185 + } 186 + mutex_unlock(&cooling_cpufreq_lock); 187 + } 188 + 189 + static void remove_cpu_device(int cpu) 190 + { 191 + struct cpufreq_cooling_device *cpufreq_dev; 192 + 193 + mutex_lock(&cooling_cpufreq_lock); 194 + list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { 195 + if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { 196 + cpufreq_dev->cpu_dev = NULL; 197 + break; 198 + } 199 + } 200 + mutex_unlock(&cooling_cpufreq_lock); 201 + } 202 + 200 203 /** 201 204 * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. 202 205 * @nb: struct notifier_block * with callback info. ··· 249 186 unsigned long max_freq = 0; 250 187 struct cpufreq_cooling_device *cpufreq_dev; 251 188 252 - if (event != CPUFREQ_ADJUST) 253 - return 0; 189 + switch (event) { 254 190 255 - mutex_lock(&cooling_cpufreq_lock); 256 - list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { 257 - if (!cpumask_test_cpu(policy->cpu, 258 - &cpufreq_dev->allowed_cpus)) 259 - continue; 191 + case CPUFREQ_ADJUST: 192 + mutex_lock(&cooling_cpufreq_lock); 193 + list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { 194 + if (!cpumask_test_cpu(policy->cpu, 195 + &cpufreq_dev->allowed_cpus)) 196 + continue; 260 197 261 - max_freq = cpufreq_dev->cpufreq_val; 198 + max_freq = cpufreq_dev->cpufreq_val; 262 199 263 - if (policy->max != max_freq) 264 - cpufreq_verify_within_limits(policy, 0, max_freq); 200 + if (policy->max != max_freq) 201 + cpufreq_verify_within_limits(policy, 0, 202 + max_freq); 203 + } 204 + mutex_unlock(&cooling_cpufreq_lock); 205 + break; 206 + 207 + case CPUFREQ_CREATE_POLICY: 208 + update_cpu_device(policy->cpu); 209 + break; 210 + case CPUFREQ_REMOVE_POLICY: 211 + remove_cpu_device(policy->cpu); 212 + break; 213 + default: 214 + return NOTIFY_DONE; 265 215 } 266 - mutex_unlock(&cooling_cpufreq_lock); 267 216 268 - return 0; 217 + return NOTIFY_OK; 218 + } 219 + 220 + /** 221 + * build_dyn_power_table() - create a dynamic power to frequency table 222 + * @cpufreq_device: the cpufreq cooling device in which to store the table 223 + * @capacitance: dynamic power coefficient for these cpus 224 + * 225 + * Build a dynamic power to frequency table for this cpu and store it 226 + * in @cpufreq_device. This table will be used in cpu_power_to_freq() and 227 + * cpu_freq_to_power() to convert between power and frequency 228 + * efficiently. Power is stored in mW, frequency in KHz. The 229 + * resulting table is in ascending order. 230 + * 231 + * Return: 0 on success, -E* on error. 232 + */ 233 + static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, 234 + u32 capacitance) 235 + { 236 + struct power_table *power_table; 237 + struct dev_pm_opp *opp; 238 + struct device *dev = NULL; 239 + int num_opps = 0, cpu, i, ret = 0; 240 + unsigned long freq; 241 + 242 + rcu_read_lock(); 243 + 244 + for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { 245 + dev = get_cpu_device(cpu); 246 + if (!dev) { 247 + dev_warn(&cpufreq_device->cool_dev->device, 248 + "No cpu device for cpu %d\n", cpu); 249 + continue; 250 + } 251 + 252 + num_opps = dev_pm_opp_get_opp_count(dev); 253 + if (num_opps > 0) { 254 + break; 255 + } else if (num_opps < 0) { 256 + ret = num_opps; 257 + goto unlock; 258 + } 259 + } 260 + 261 + if (num_opps == 0) { 262 + ret = -EINVAL; 263 + goto unlock; 264 + } 265 + 266 + power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL); 267 + 268 + for (freq = 0, i = 0; 269 + opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp); 270 + freq++, i++) { 271 + u32 freq_mhz, voltage_mv; 272 + u64 power; 273 + 274 + freq_mhz = freq / 1000000; 275 + voltage_mv = dev_pm_opp_get_voltage(opp) / 1000; 276 + 277 + /* 278 + * Do the multiplication with MHz and millivolt so as 279 + * to not overflow. 280 + */ 281 + power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv; 282 + do_div(power, 1000000000); 283 + 284 + /* frequency is stored in power_table in KHz */ 285 + power_table[i].frequency = freq / 1000; 286 + 287 + /* power is stored in mW */ 288 + power_table[i].power = power; 289 + } 290 + 291 + if (i == 0) { 292 + ret = PTR_ERR(opp); 293 + goto unlock; 294 + } 295 + 296 + cpufreq_device->cpu_dev = dev; 297 + cpufreq_device->dyn_power_table = power_table; 298 + cpufreq_device->dyn_power_table_entries = i; 299 + 300 + unlock: 301 + rcu_read_unlock(); 302 + return ret; 303 + } 304 + 305 + static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device, 306 + u32 freq) 307 + { 308 + int i; 309 + struct power_table *pt = cpufreq_device->dyn_power_table; 310 + 311 + for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) 312 + if (freq < pt[i].frequency) 313 + break; 314 + 315 + return pt[i - 1].power; 316 + } 317 + 318 + static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device, 319 + u32 power) 320 + { 321 + int i; 322 + struct power_table *pt = cpufreq_device->dyn_power_table; 323 + 324 + for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) 325 + if (power < pt[i].power) 326 + break; 327 + 328 + return pt[i - 1].frequency; 329 + } 330 + 331 + /** 332 + * get_load() - get load for a cpu since last updated 333 + * @cpufreq_device: &struct cpufreq_cooling_device for this cpu 334 + * @cpu: cpu number 335 + * 336 + * Return: The average load of cpu @cpu in percentage since this 337 + * function was last called. 338 + */ 339 + static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu) 340 + { 341 + u32 load; 342 + u64 now, now_idle, delta_time, delta_idle; 343 + 344 + now_idle = get_cpu_idle_time(cpu, &now, 0); 345 + delta_idle = now_idle - cpufreq_device->time_in_idle[cpu]; 346 + delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu]; 347 + 348 + if (delta_time <= delta_idle) 349 + load = 0; 350 + else 351 + load = div64_u64(100 * (delta_time - delta_idle), delta_time); 352 + 353 + cpufreq_device->time_in_idle[cpu] = now_idle; 354 + cpufreq_device->time_in_idle_timestamp[cpu] = now; 355 + 356 + return load; 357 + } 358 + 359 + /** 360 + * get_static_power() - calculate the static power consumed by the cpus 361 + * @cpufreq_device: struct &cpufreq_cooling_device for this cpu cdev 362 + * @tz: thermal zone device in which we're operating 363 + * @freq: frequency in KHz 364 + * @power: pointer in which to store the calculated static power 365 + * 366 + * Calculate the static power consumed by the cpus described by 367 + * @cpu_actor running at frequency @freq. This function relies on a 368 + * platform specific function that should have been provided when the 369 + * actor was registered. If it wasn't, the static power is assumed to 370 + * be negligible. The calculated static power is stored in @power. 371 + * 372 + * Return: 0 on success, -E* on failure. 373 + */ 374 + static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, 375 + struct thermal_zone_device *tz, unsigned long freq, 376 + u32 *power) 377 + { 378 + struct dev_pm_opp *opp; 379 + unsigned long voltage; 380 + struct cpumask *cpumask = &cpufreq_device->allowed_cpus; 381 + unsigned long freq_hz = freq * 1000; 382 + 383 + if (!cpufreq_device->plat_get_static_power || 384 + !cpufreq_device->cpu_dev) { 385 + *power = 0; 386 + return 0; 387 + } 388 + 389 + rcu_read_lock(); 390 + 391 + opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz, 392 + true); 393 + voltage = dev_pm_opp_get_voltage(opp); 394 + 395 + rcu_read_unlock(); 396 + 397 + if (voltage == 0) { 398 + dev_warn_ratelimited(cpufreq_device->cpu_dev, 399 + "Failed to get voltage for frequency %lu: %ld\n", 400 + freq_hz, IS_ERR(opp) ? PTR_ERR(opp) : 0); 401 + return -EINVAL; 402 + } 403 + 404 + return cpufreq_device->plat_get_static_power(cpumask, tz->passive_delay, 405 + voltage, power); 406 + } 407 + 408 + /** 409 + * get_dynamic_power() - calculate the dynamic power 410 + * @cpufreq_device: &cpufreq_cooling_device for this cdev 411 + * @freq: current frequency 412 + * 413 + * Return: the dynamic power consumed by the cpus described by 414 + * @cpufreq_device. 415 + */ 416 + static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device, 417 + unsigned long freq) 418 + { 419 + u32 raw_cpu_power; 420 + 421 + raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq); 422 + return (raw_cpu_power * cpufreq_device->last_load) / 100; 269 423 } 270 424 271 425 /* cpufreq cooling device callback functions are defined below */ ··· 560 280 return 0; 561 281 } 562 282 283 + /** 284 + * cpufreq_get_requested_power() - get the current power 285 + * @cdev: &thermal_cooling_device pointer 286 + * @tz: a valid thermal zone device pointer 287 + * @power: pointer in which to store the resulting power 288 + * 289 + * Calculate the current power consumption of the cpus in milliwatts 290 + * and store it in @power. This function should actually calculate 291 + * the requested power, but it's hard to get the frequency that 292 + * cpufreq would have assigned if there were no thermal limits. 293 + * Instead, we calculate the current power on the assumption that the 294 + * immediate future will look like the immediate past. 295 + * 296 + * We use the current frequency and the average load since this 297 + * function was last called. In reality, there could have been 298 + * multiple opps since this function was last called and that affects 299 + * the load calculation. While it's not perfectly accurate, this 300 + * simplification is good enough and works. REVISIT this, as more 301 + * complex code may be needed if experiments show that it's not 302 + * accurate enough. 303 + * 304 + * Return: 0 on success, -E* if getting the static power failed. 305 + */ 306 + static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, 307 + struct thermal_zone_device *tz, 308 + u32 *power) 309 + { 310 + unsigned long freq; 311 + int cpu, ret; 312 + u32 static_power, dynamic_power, total_load = 0; 313 + struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 314 + 315 + freq = cpufreq_quick_get(cpumask_any(&cpufreq_device->allowed_cpus)); 316 + 317 + for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { 318 + u32 load; 319 + 320 + if (cpu_online(cpu)) 321 + load = get_load(cpufreq_device, cpu); 322 + else 323 + load = 0; 324 + 325 + total_load += load; 326 + } 327 + 328 + cpufreq_device->last_load = total_load; 329 + 330 + dynamic_power = get_dynamic_power(cpufreq_device, freq); 331 + ret = get_static_power(cpufreq_device, tz, freq, &static_power); 332 + if (ret) 333 + return ret; 334 + 335 + *power = static_power + dynamic_power; 336 + return 0; 337 + } 338 + 339 + /** 340 + * cpufreq_state2power() - convert a cpu cdev state to power consumed 341 + * @cdev: &thermal_cooling_device pointer 342 + * @tz: a valid thermal zone device pointer 343 + * @state: cooling device state to be converted 344 + * @power: pointer in which to store the resulting power 345 + * 346 + * Convert cooling device state @state into power consumption in 347 + * milliwatts assuming 100% load. Store the calculated power in 348 + * @power. 349 + * 350 + * Return: 0 on success, -EINVAL if the cooling device state could not 351 + * be converted into a frequency or other -E* if there was an error 352 + * when calculating the static power. 353 + */ 354 + static int cpufreq_state2power(struct thermal_cooling_device *cdev, 355 + struct thermal_zone_device *tz, 356 + unsigned long state, u32 *power) 357 + { 358 + unsigned int freq, num_cpus; 359 + cpumask_t cpumask; 360 + u32 static_power, dynamic_power; 361 + int ret; 362 + struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 363 + 364 + cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask); 365 + num_cpus = cpumask_weight(&cpumask); 366 + 367 + /* None of our cpus are online, so no power */ 368 + if (num_cpus == 0) { 369 + *power = 0; 370 + return 0; 371 + } 372 + 373 + freq = cpufreq_device->freq_table[state]; 374 + if (!freq) 375 + return -EINVAL; 376 + 377 + dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus; 378 + ret = get_static_power(cpufreq_device, tz, freq, &static_power); 379 + if (ret) 380 + return ret; 381 + 382 + *power = static_power + dynamic_power; 383 + return 0; 384 + } 385 + 386 + /** 387 + * cpufreq_power2state() - convert power to a cooling device state 388 + * @cdev: &thermal_cooling_device pointer 389 + * @tz: a valid thermal zone device pointer 390 + * @power: power in milliwatts to be converted 391 + * @state: pointer in which to store the resulting state 392 + * 393 + * Calculate a cooling device state for the cpus described by @cdev 394 + * that would allow them to consume at most @power mW and store it in 395 + * @state. Note that this calculation depends on external factors 396 + * such as the cpu load or the current static power. Calling this 397 + * function with the same power as input can yield different cooling 398 + * device states depending on those external factors. 399 + * 400 + * Return: 0 on success, -ENODEV if no cpus are online or -EINVAL if 401 + * the calculated frequency could not be converted to a valid state. 402 + * The latter should not happen unless the frequencies available to 403 + * cpufreq have changed since the initialization of the cpu cooling 404 + * device. 405 + */ 406 + static int cpufreq_power2state(struct thermal_cooling_device *cdev, 407 + struct thermal_zone_device *tz, u32 power, 408 + unsigned long *state) 409 + { 410 + unsigned int cpu, cur_freq, target_freq; 411 + int ret; 412 + s32 dyn_power; 413 + u32 last_load, normalised_power, static_power; 414 + struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 415 + 416 + cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask); 417 + 418 + /* None of our cpus are online */ 419 + if (cpu >= nr_cpu_ids) 420 + return -ENODEV; 421 + 422 + cur_freq = cpufreq_quick_get(cpu); 423 + ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power); 424 + if (ret) 425 + return ret; 426 + 427 + dyn_power = power - static_power; 428 + dyn_power = dyn_power > 0 ? dyn_power : 0; 429 + last_load = cpufreq_device->last_load ?: 1; 430 + normalised_power = (dyn_power * 100) / last_load; 431 + target_freq = cpu_power_to_freq(cpufreq_device, normalised_power); 432 + 433 + *state = cpufreq_cooling_get_level(cpu, target_freq); 434 + if (*state == THERMAL_CSTATE_INVALID) { 435 + dev_warn_ratelimited(&cdev->device, 436 + "Failed to convert %dKHz for cpu %d into a cdev state\n", 437 + target_freq, cpu); 438 + return -EINVAL; 439 + } 440 + 441 + return 0; 442 + } 443 + 563 444 /* Bind cpufreq callbacks to thermal cooling device ops */ 564 - static struct thermal_cooling_device_ops const cpufreq_cooling_ops = { 445 + static struct thermal_cooling_device_ops cpufreq_cooling_ops = { 565 446 .get_max_state = cpufreq_get_max_state, 566 447 .get_cur_state = cpufreq_get_cur_state, 567 448 .set_cur_state = cpufreq_set_cur_state, ··· 752 311 * @np: a valid struct device_node to the cooling device device tree node 753 312 * @clip_cpus: cpumask of cpus where the frequency constraints will happen. 754 313 * Normally this should be same as cpufreq policy->related_cpus. 314 + * @capacitance: dynamic power coefficient for these cpus 315 + * @plat_static_func: function to calculate the static power consumed by these 316 + * cpus (optional) 755 317 * 756 318 * This interface function registers the cpufreq cooling device with the name 757 319 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq ··· 766 322 */ 767 323 static struct thermal_cooling_device * 768 324 __cpufreq_cooling_register(struct device_node *np, 769 - const struct cpumask *clip_cpus) 325 + const struct cpumask *clip_cpus, u32 capacitance, 326 + get_static_t plat_static_func) 770 327 { 771 328 struct thermal_cooling_device *cool_dev; 772 329 struct cpufreq_cooling_device *cpufreq_dev; 773 330 char dev_name[THERMAL_NAME_LENGTH]; 774 331 struct cpufreq_frequency_table *pos, *table; 775 - unsigned int freq, i; 332 + unsigned int freq, i, num_cpus; 776 333 int ret; 777 334 778 335 table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); ··· 786 341 if (!cpufreq_dev) 787 342 return ERR_PTR(-ENOMEM); 788 343 344 + num_cpus = cpumask_weight(clip_cpus); 345 + cpufreq_dev->time_in_idle = kcalloc(num_cpus, 346 + sizeof(*cpufreq_dev->time_in_idle), 347 + GFP_KERNEL); 348 + if (!cpufreq_dev->time_in_idle) { 349 + cool_dev = ERR_PTR(-ENOMEM); 350 + goto free_cdev; 351 + } 352 + 353 + cpufreq_dev->time_in_idle_timestamp = 354 + kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp), 355 + GFP_KERNEL); 356 + if (!cpufreq_dev->time_in_idle_timestamp) { 357 + cool_dev = ERR_PTR(-ENOMEM); 358 + goto free_time_in_idle; 359 + } 360 + 789 361 /* Find max levels */ 790 362 cpufreq_for_each_valid_entry(pos, table) 791 363 cpufreq_dev->max_level++; ··· 811 349 cpufreq_dev->max_level, GFP_KERNEL); 812 350 if (!cpufreq_dev->freq_table) { 813 351 cool_dev = ERR_PTR(-ENOMEM); 814 - goto free_cdev; 352 + goto free_time_in_idle_timestamp; 815 353 } 816 354 817 355 /* max_level is an index, not a counter */ 818 356 cpufreq_dev->max_level--; 819 357 820 358 cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); 359 + 360 + if (capacitance) { 361 + cpufreq_cooling_ops.get_requested_power = 362 + cpufreq_get_requested_power; 363 + cpufreq_cooling_ops.state2power = cpufreq_state2power; 364 + cpufreq_cooling_ops.power2state = cpufreq_power2state; 365 + cpufreq_dev->plat_get_static_power = plat_static_func; 366 + 367 + ret = build_dyn_power_table(cpufreq_dev, capacitance); 368 + if (ret) { 369 + cool_dev = ERR_PTR(ret); 370 + goto free_table; 371 + } 372 + } 821 373 822 374 ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); 823 375 if (ret) { ··· 878 402 release_idr(&cpufreq_idr, cpufreq_dev->id); 879 403 free_table: 880 404 kfree(cpufreq_dev->freq_table); 405 + free_time_in_idle_timestamp: 406 + kfree(cpufreq_dev->time_in_idle_timestamp); 407 + free_time_in_idle: 408 + kfree(cpufreq_dev->time_in_idle); 881 409 free_cdev: 882 410 kfree(cpufreq_dev); 883 411 ··· 902 422 struct thermal_cooling_device * 903 423 cpufreq_cooling_register(const struct cpumask *clip_cpus) 904 424 { 905 - return __cpufreq_cooling_register(NULL, clip_cpus); 425 + return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL); 906 426 } 907 427 EXPORT_SYMBOL_GPL(cpufreq_cooling_register); 908 428 ··· 926 446 if (!np) 927 447 return ERR_PTR(-EINVAL); 928 448 929 - return __cpufreq_cooling_register(np, clip_cpus); 449 + return __cpufreq_cooling_register(np, clip_cpus, 0, NULL); 930 450 } 931 451 EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); 452 + 453 + /** 454 + * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions 455 + * @clip_cpus: cpumask of cpus where the frequency constraints will happen 456 + * @capacitance: dynamic power coefficient for these cpus 457 + * @plat_static_func: function to calculate the static power consumed by these 458 + * cpus (optional) 459 + * 460 + * This interface function registers the cpufreq cooling device with 461 + * the name "thermal-cpufreq-%x". This api can support multiple 462 + * instances of cpufreq cooling devices. Using this function, the 463 + * cooling device will implement the power extensions by using a 464 + * simple cpu power model. The cpus must have registered their OPPs 465 + * using the OPP library. 466 + * 467 + * An optional @plat_static_func may be provided to calculate the 468 + * static power consumed by these cpus. If the platform's static 469 + * power consumption is unknown or negligible, make it NULL. 470 + * 471 + * Return: a valid struct thermal_cooling_device pointer on success, 472 + * on failure, it returns a corresponding ERR_PTR(). 473 + */ 474 + struct thermal_cooling_device * 475 + cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, 476 + get_static_t plat_static_func) 477 + { 478 + return __cpufreq_cooling_register(NULL, clip_cpus, capacitance, 479 + plat_static_func); 480 + } 481 + EXPORT_SYMBOL(cpufreq_power_cooling_register); 482 + 483 + /** 484 + * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions 485 + * @np: a valid struct device_node to the cooling device device tree node 486 + * @clip_cpus: cpumask of cpus where the frequency constraints will happen 487 + * @capacitance: dynamic power coefficient for these cpus 488 + * @plat_static_func: function to calculate the static power consumed by these 489 + * cpus (optional) 490 + * 491 + * This interface function registers the cpufreq cooling device with 492 + * the name "thermal-cpufreq-%x". This api can support multiple 493 + * instances of cpufreq cooling devices. Using this API, the cpufreq 494 + * cooling device will be linked to the device tree node provided. 495 + * Using this function, the cooling device will implement the power 496 + * extensions by using a simple cpu power model. The cpus must have 497 + * registered their OPPs using the OPP library. 498 + * 499 + * An optional @plat_static_func may be provided to calculate the 500 + * static power consumed by these cpus. If the platform's static 501 + * power consumption is unknown or negligible, make it NULL. 502 + * 503 + * Return: a valid struct thermal_cooling_device pointer on success, 504 + * on failure, it returns a corresponding ERR_PTR(). 505 + */ 506 + struct thermal_cooling_device * 507 + of_cpufreq_power_cooling_register(struct device_node *np, 508 + const struct cpumask *clip_cpus, 509 + u32 capacitance, 510 + get_static_t plat_static_func) 511 + { 512 + if (!np) 513 + return ERR_PTR(-EINVAL); 514 + 515 + return __cpufreq_cooling_register(np, clip_cpus, capacitance, 516 + plat_static_func); 517 + } 518 + EXPORT_SYMBOL(of_cpufreq_power_cooling_register); 932 519 933 520 /** 934 521 * cpufreq_cooling_unregister - function to remove cpufreq cooling device. ··· 1022 475 1023 476 thermal_cooling_device_unregister(cpufreq_dev->cool_dev); 1024 477 release_idr(&cpufreq_idr, cpufreq_dev->id); 478 + kfree(cpufreq_dev->time_in_idle_timestamp); 479 + kfree(cpufreq_dev->time_in_idle); 1025 480 kfree(cpufreq_dev->freq_table); 1026 481 kfree(cpufreq_dev); 1027 482 }
+39
include/linux/cpu_cooling.h
··· 28 28 #include <linux/thermal.h> 29 29 #include <linux/cpumask.h> 30 30 31 + typedef int (*get_static_t)(cpumask_t *cpumask, int interval, 32 + unsigned long voltage, u32 *power); 33 + 31 34 #ifdef CONFIG_CPU_THERMAL 32 35 /** 33 36 * cpufreq_cooling_register - function to create cpufreq cooling device. ··· 38 35 */ 39 36 struct thermal_cooling_device * 40 37 cpufreq_cooling_register(const struct cpumask *clip_cpus); 38 + 39 + struct thermal_cooling_device * 40 + cpufreq_power_cooling_register(const struct cpumask *clip_cpus, 41 + u32 capacitance, get_static_t plat_static_func); 41 42 42 43 /** 43 44 * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. ··· 52 45 struct thermal_cooling_device * 53 46 of_cpufreq_cooling_register(struct device_node *np, 54 47 const struct cpumask *clip_cpus); 48 + 49 + struct thermal_cooling_device * 50 + of_cpufreq_power_cooling_register(struct device_node *np, 51 + const struct cpumask *clip_cpus, 52 + u32 capacitance, 53 + get_static_t plat_static_func); 55 54 #else 56 55 static inline struct thermal_cooling_device * 57 56 of_cpufreq_cooling_register(struct device_node *np, 58 57 const struct cpumask *clip_cpus) 59 58 { 60 59 return ERR_PTR(-ENOSYS); 60 + } 61 + 62 + static inline struct thermal_cooling_device * 63 + of_cpufreq_power_cooling_register(struct device_node *np, 64 + const struct cpumask *clip_cpus, 65 + u32 capacitance, 66 + get_static_t plat_static_func) 67 + { 68 + return NULL; 61 69 } 62 70 #endif 63 71 ··· 90 68 return ERR_PTR(-ENOSYS); 91 69 } 92 70 static inline struct thermal_cooling_device * 71 + cpufreq_power_cooling_register(const struct cpumask *clip_cpus, 72 + u32 capacitance, get_static_t plat_static_func) 73 + { 74 + return NULL; 75 + } 76 + 77 + static inline struct thermal_cooling_device * 93 78 of_cpufreq_cooling_register(struct device_node *np, 94 79 const struct cpumask *clip_cpus) 95 80 { 96 81 return ERR_PTR(-ENOSYS); 97 82 } 83 + 84 + static inline struct thermal_cooling_device * 85 + of_cpufreq_power_cooling_register(struct device_node *np, 86 + const struct cpumask *clip_cpus, 87 + u32 capacitance, 88 + get_static_t plat_static_func) 89 + { 90 + return NULL; 91 + } 92 + 98 93 static inline 99 94 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 100 95 {