diff options
-rw-r--r-- | Documentation/thermal/sysfs-api.txt | 21 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 17 | ||||
-rw-r--r-- | drivers/thermal/devfreq_cooling.c | 152 | ||||
-rw-r--r-- | drivers/thermal/intel_soc_dts_thermal.c | 9 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 64 | ||||
-rw-r--r-- | include/linux/devfreq_cooling.h | 19 | ||||
-rw-r--r-- | include/trace/events/thermal.h | 11 |
7 files changed, 244 insertions, 49 deletions
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index ef473dc7f55e..bb9a0a53e76b 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt | |||
@@ -582,3 +582,24 @@ platform data is provided, this uses the step_wise throttling policy. | |||
582 | This function serves as an arbitrator to set the state of a cooling | 582 | This function serves as an arbitrator to set the state of a cooling |
583 | device. It sets the cooling device to the deepest cooling state if | 583 | device. It sets the cooling device to the deepest cooling state if |
584 | possible. | 584 | possible. |
585 | |||
586 | 6. thermal_emergency_poweroff: | ||
587 | |||
588 | On an event of critical trip temperature crossing. Thermal framework | ||
589 | allows the system to shutdown gracefully by calling orderly_poweroff(). | ||
590 | In the event of a failure of orderly_poweroff() to shut down the system | ||
591 | we are in danger of keeping the system alive at undesirably high | ||
592 | temperatures. To mitigate this high risk scenario we program a work | ||
593 | queue to fire after a pre-determined number of seconds to start | ||
594 | an emergency shutdown of the device using the kernel_power_off() | ||
595 | function. In case kernel_power_off() fails then finally | ||
596 | emergency_restart() is called in the worst case. | ||
597 | |||
598 | The delay should be carefully profiled so as to give adequate time for | ||
599 | orderly_poweroff(). In case of failure of an orderly_poweroff() the | ||
600 | emergency poweroff kicks in after the delay has elapsed and shuts down | ||
601 | the system. | ||
602 | |||
603 | If set to 0 emergency poweroff will not be supported. So a carefully | ||
604 | profiled non-zero positive value is a must for emergerncy poweroff to be | ||
605 | triggered. | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index f786ae433032..4edc011fe4a5 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -15,6 +15,23 @@ menuconfig THERMAL | |||
15 | 15 | ||
16 | if THERMAL | 16 | if THERMAL |
17 | 17 | ||
18 | config THERMAL_EMERGENCY_POWEROFF_DELAY_MS | ||
19 | int "Emergency poweroff delay in milli-seconds" | ||
20 | depends on THERMAL | ||
21 | default 0 | ||
22 | help | ||
23 | Thermal subsystem will issue a graceful shutdown when | ||
24 | critical temperatures are reached using orderly_poweroff(). In | ||
25 | case of failure of an orderly_poweroff(), the thermal emergency | ||
26 | poweroff kicks in after a delay has elapsed and shuts down the system. | ||
27 | This config is number of milliseconds to delay before emergency | ||
28 | poweroff kicks in. Similarly to the critical trip point, | ||
29 | the delay should be carefully profiled so as to give adequate | ||
30 | time for orderly_poweroff() to finish on regular execution. | ||
31 | If set to 0 emergency poweroff will not be supported. | ||
32 | |||
33 | In doubt, leave as 0. | ||
34 | |||
18 | config THERMAL_HWMON | 35 | config THERMAL_HWMON |
19 | bool | 36 | bool |
20 | prompt "Expose thermal sensors as hwmon device" | 37 | prompt "Expose thermal sensors as hwmon device" |
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 4bf4ad58cffd..ef59256887ff 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include <trace/events/thermal.h> | 29 | #include <trace/events/thermal.h> |
30 | 30 | ||
31 | #define SCALE_ERROR_MITIGATION 100 | ||
32 | |||
31 | static DEFINE_IDA(devfreq_ida); | 33 | static DEFINE_IDA(devfreq_ida); |
32 | 34 | ||
33 | /** | 35 | /** |
@@ -45,6 +47,12 @@ static DEFINE_IDA(devfreq_ida); | |||
45 | * @freq_table_size: Size of the @freq_table and @power_table | 47 | * @freq_table_size: Size of the @freq_table and @power_table |
46 | * @power_ops: Pointer to devfreq_cooling_power, used to generate the | 48 | * @power_ops: Pointer to devfreq_cooling_power, used to generate the |
47 | * @power_table. | 49 | * @power_table. |
50 | * @res_util: Resource utilization scaling factor for the power. | ||
51 | * It is multiplied by 100 to minimize the error. It is used | ||
52 | * for estimation of the power budget instead of using | ||
53 | * 'utilization' (which is 'busy_time / 'total_time'). | ||
54 | * The 'res_util' range is from 100 to (power_table[state] * 100) | ||
55 | * for the corresponding 'state'. | ||
48 | */ | 56 | */ |
49 | struct devfreq_cooling_device { | 57 | struct devfreq_cooling_device { |
50 | int id; | 58 | int id; |
@@ -55,6 +63,8 @@ struct devfreq_cooling_device { | |||
55 | u32 *freq_table; | 63 | u32 *freq_table; |
56 | size_t freq_table_size; | 64 | size_t freq_table_size; |
57 | struct devfreq_cooling_power *power_ops; | 65 | struct devfreq_cooling_power *power_ops; |
66 | u32 res_util; | ||
67 | int capped_state; | ||
58 | }; | 68 | }; |
59 | 69 | ||
60 | /** | 70 | /** |
@@ -164,27 +174,12 @@ freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq) | |||
164 | return THERMAL_CSTATE_INVALID; | 174 | return THERMAL_CSTATE_INVALID; |
165 | } | 175 | } |
166 | 176 | ||
167 | /** | 177 | static unsigned long get_voltage(struct devfreq *df, unsigned long freq) |
168 | * get_static_power() - calculate the static power | ||
169 | * @dfc: Pointer to devfreq cooling device | ||
170 | * @freq: Frequency in Hz | ||
171 | * | ||
172 | * Calculate the static power in milliwatts using the supplied | ||
173 | * get_static_power(). The current voltage is calculated using the | ||
174 | * OPP library. If no get_static_power() was supplied, assume the | ||
175 | * static power is negligible. | ||
176 | */ | ||
177 | static unsigned long | ||
178 | get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
179 | { | 178 | { |
180 | struct devfreq *df = dfc->devfreq; | ||
181 | struct device *dev = df->dev.parent; | 179 | struct device *dev = df->dev.parent; |
182 | unsigned long voltage; | 180 | unsigned long voltage; |
183 | struct dev_pm_opp *opp; | 181 | struct dev_pm_opp *opp; |
184 | 182 | ||
185 | if (!dfc->power_ops->get_static_power) | ||
186 | return 0; | ||
187 | |||
188 | opp = dev_pm_opp_find_freq_exact(dev, freq, true); | 183 | opp = dev_pm_opp_find_freq_exact(dev, freq, true); |
189 | if (PTR_ERR(opp) == -ERANGE) | 184 | if (PTR_ERR(opp) == -ERANGE) |
190 | opp = dev_pm_opp_find_freq_exact(dev, freq, false); | 185 | opp = dev_pm_opp_find_freq_exact(dev, freq, false); |
@@ -202,9 +197,35 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | |||
202 | dev_err_ratelimited(dev, | 197 | dev_err_ratelimited(dev, |
203 | "Failed to get voltage for frequency %lu\n", | 198 | "Failed to get voltage for frequency %lu\n", |
204 | freq); | 199 | freq); |
205 | return 0; | ||
206 | } | 200 | } |
207 | 201 | ||
202 | return voltage; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * get_static_power() - calculate the static power | ||
207 | * @dfc: Pointer to devfreq cooling device | ||
208 | * @freq: Frequency in Hz | ||
209 | * | ||
210 | * Calculate the static power in milliwatts using the supplied | ||
211 | * get_static_power(). The current voltage is calculated using the | ||
212 | * OPP library. If no get_static_power() was supplied, assume the | ||
213 | * static power is negligible. | ||
214 | */ | ||
215 | static unsigned long | ||
216 | get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) | ||
217 | { | ||
218 | struct devfreq *df = dfc->devfreq; | ||
219 | unsigned long voltage; | ||
220 | |||
221 | if (!dfc->power_ops->get_static_power) | ||
222 | return 0; | ||
223 | |||
224 | voltage = get_voltage(df, freq); | ||
225 | |||
226 | if (voltage == 0) | ||
227 | return 0; | ||
228 | |||
208 | return dfc->power_ops->get_static_power(df, voltage); | 229 | return dfc->power_ops->get_static_power(df, voltage); |
209 | } | 230 | } |
210 | 231 | ||
@@ -239,6 +260,16 @@ get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, | |||
239 | return power; | 260 | return power; |
240 | } | 261 | } |
241 | 262 | ||
263 | |||
264 | static inline unsigned long get_total_power(struct devfreq_cooling_device *dfc, | ||
265 | unsigned long freq, | ||
266 | unsigned long voltage) | ||
267 | { | ||
268 | return get_static_power(dfc, freq) + get_dynamic_power(dfc, freq, | ||
269 | voltage); | ||
270 | } | ||
271 | |||
272 | |||
242 | static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, | 273 | static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, |
243 | struct thermal_zone_device *tz, | 274 | struct thermal_zone_device *tz, |
244 | u32 *power) | 275 | u32 *power) |
@@ -248,27 +279,55 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd | |||
248 | struct devfreq_dev_status *status = &df->last_status; | 279 | struct devfreq_dev_status *status = &df->last_status; |
249 | unsigned long state; | 280 | unsigned long state; |
250 | unsigned long freq = status->current_frequency; | 281 | unsigned long freq = status->current_frequency; |
251 | u32 dyn_power, static_power; | 282 | unsigned long voltage; |
283 | u32 dyn_power = 0; | ||
284 | u32 static_power = 0; | ||
285 | int res; | ||
252 | 286 | ||
253 | /* Get dynamic power for state */ | ||
254 | state = freq_get_state(dfc, freq); | 287 | state = freq_get_state(dfc, freq); |
255 | if (state == THERMAL_CSTATE_INVALID) | 288 | if (state == THERMAL_CSTATE_INVALID) { |
256 | return -EAGAIN; | 289 | res = -EAGAIN; |
290 | goto fail; | ||
291 | } | ||
257 | 292 | ||
258 | dyn_power = dfc->power_table[state]; | 293 | if (dfc->power_ops->get_real_power) { |
294 | voltage = get_voltage(df, freq); | ||
295 | if (voltage == 0) { | ||
296 | res = -EINVAL; | ||
297 | goto fail; | ||
298 | } | ||
259 | 299 | ||
260 | /* Scale dynamic power for utilization */ | 300 | res = dfc->power_ops->get_real_power(df, power, freq, voltage); |
261 | dyn_power = (dyn_power * status->busy_time) / status->total_time; | 301 | if (!res) { |
302 | state = dfc->capped_state; | ||
303 | dfc->res_util = dfc->power_table[state]; | ||
304 | dfc->res_util *= SCALE_ERROR_MITIGATION; | ||
262 | 305 | ||
263 | /* Get static power */ | 306 | if (*power > 1) |
264 | static_power = get_static_power(dfc, freq); | 307 | dfc->res_util /= *power; |
308 | } else { | ||
309 | goto fail; | ||
310 | } | ||
311 | } else { | ||
312 | dyn_power = dfc->power_table[state]; | ||
265 | 313 | ||
266 | trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, | 314 | /* Scale dynamic power for utilization */ |
267 | static_power); | 315 | dyn_power *= status->busy_time; |
316 | dyn_power /= status->total_time; | ||
317 | /* Get static power */ | ||
318 | static_power = get_static_power(dfc, freq); | ||
268 | 319 | ||
269 | *power = dyn_power + static_power; | 320 | *power = dyn_power + static_power; |
321 | } | ||
322 | |||
323 | trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, | ||
324 | static_power, *power); | ||
270 | 325 | ||
271 | return 0; | 326 | return 0; |
327 | fail: | ||
328 | /* It is safe to set max in this case */ | ||
329 | dfc->res_util = SCALE_ERROR_MITIGATION; | ||
330 | return res; | ||
272 | } | 331 | } |
273 | 332 | ||
274 | static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, | 333 | static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, |
@@ -301,26 +360,34 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, | |||
301 | unsigned long busy_time; | 360 | unsigned long busy_time; |
302 | s32 dyn_power; | 361 | s32 dyn_power; |
303 | u32 static_power; | 362 | u32 static_power; |
363 | s32 est_power; | ||
304 | int i; | 364 | int i; |
305 | 365 | ||
306 | static_power = get_static_power(dfc, freq); | 366 | if (dfc->power_ops->get_real_power) { |
367 | /* Scale for resource utilization */ | ||
368 | est_power = power * dfc->res_util; | ||
369 | est_power /= SCALE_ERROR_MITIGATION; | ||
370 | } else { | ||
371 | static_power = get_static_power(dfc, freq); | ||
307 | 372 | ||
308 | dyn_power = power - static_power; | 373 | dyn_power = power - static_power; |
309 | dyn_power = dyn_power > 0 ? dyn_power : 0; | 374 | dyn_power = dyn_power > 0 ? dyn_power : 0; |
310 | 375 | ||
311 | /* Scale dynamic power for utilization */ | 376 | /* Scale dynamic power for utilization */ |
312 | busy_time = status->busy_time ?: 1; | 377 | busy_time = status->busy_time ?: 1; |
313 | dyn_power = (dyn_power * status->total_time) / busy_time; | 378 | est_power = (dyn_power * status->total_time) / busy_time; |
379 | } | ||
314 | 380 | ||
315 | /* | 381 | /* |
316 | * Find the first cooling state that is within the power | 382 | * Find the first cooling state that is within the power |
317 | * budget for dynamic power. | 383 | * budget for dynamic power. |
318 | */ | 384 | */ |
319 | for (i = 0; i < dfc->freq_table_size - 1; i++) | 385 | for (i = 0; i < dfc->freq_table_size - 1; i++) |
320 | if (dyn_power >= dfc->power_table[i]) | 386 | if (est_power >= dfc->power_table[i]) |
321 | break; | 387 | break; |
322 | 388 | ||
323 | *state = i; | 389 | *state = i; |
390 | dfc->capped_state = i; | ||
324 | trace_thermal_power_devfreq_limit(cdev, freq, *state, power); | 391 | trace_thermal_power_devfreq_limit(cdev, freq, *state, power); |
325 | return 0; | 392 | return 0; |
326 | } | 393 | } |
@@ -376,7 +443,7 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) | |||
376 | } | 443 | } |
377 | 444 | ||
378 | for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { | 445 | for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { |
379 | unsigned long power_dyn, voltage; | 446 | unsigned long power, voltage; |
380 | struct dev_pm_opp *opp; | 447 | struct dev_pm_opp *opp; |
381 | 448 | ||
382 | opp = dev_pm_opp_find_freq_floor(dev, &freq); | 449 | opp = dev_pm_opp_find_freq_floor(dev, &freq); |
@@ -389,12 +456,15 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) | |||
389 | dev_pm_opp_put(opp); | 456 | dev_pm_opp_put(opp); |
390 | 457 | ||
391 | if (dfc->power_ops) { | 458 | if (dfc->power_ops) { |
392 | power_dyn = get_dynamic_power(dfc, freq, voltage); | 459 | if (dfc->power_ops->get_real_power) |
460 | power = get_total_power(dfc, freq, voltage); | ||
461 | else | ||
462 | power = get_dynamic_power(dfc, freq, voltage); | ||
393 | 463 | ||
394 | dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", | 464 | dev_dbg(dev, "Power table: %lu MHz @ %lu mV: %lu = %lu mW\n", |
395 | freq / 1000000, voltage, power_dyn, power_dyn); | 465 | freq / 1000000, voltage, power, power); |
396 | 466 | ||
397 | power_table[i] = power_dyn; | 467 | power_table[i] = power; |
398 | } | 468 | } |
399 | 469 | ||
400 | freq_table[i] = freq; | 470 | freq_table[i] = freq; |
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index b2bbaa1c60b0..c27868b2c6af 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c | |||
@@ -73,8 +73,12 @@ static int __init intel_soc_thermal_init(void) | |||
73 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | 73 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
74 | "soc_dts", soc_dts); | 74 | "soc_dts", soc_dts); |
75 | if (err) { | 75 | if (err) { |
76 | pr_err("request_threaded_irq ret %d\n", err); | 76 | /* |
77 | goto error_irq; | 77 | * Do not just error out because the user space thermal |
78 | * daemon such as DPTF may use polling instead of being | ||
79 | * interrupt driven. | ||
80 | */ | ||
81 | pr_warn("request_threaded_irq ret %d\n", err); | ||
78 | } | 82 | } |
79 | } | 83 | } |
80 | 84 | ||
@@ -88,7 +92,6 @@ static int __init intel_soc_thermal_init(void) | |||
88 | error_trips: | 92 | error_trips: |
89 | if (soc_dts_thres_irq) | 93 | if (soc_dts_thres_irq) |
90 | free_irq(soc_dts_thres_irq, soc_dts); | 94 | free_irq(soc_dts_thres_irq, soc_dts); |
91 | error_irq: | ||
92 | intel_soc_dts_iosf_exit(soc_dts); | 95 | intel_soc_dts_iosf_exit(soc_dts); |
93 | 96 | ||
94 | return err; | 97 | return err; |
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 11f0675cb7e5..b21b9cc2c8d6 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c | |||
@@ -45,8 +45,10 @@ static LIST_HEAD(thermal_governor_list); | |||
45 | 45 | ||
46 | static DEFINE_MUTEX(thermal_list_lock); | 46 | static DEFINE_MUTEX(thermal_list_lock); |
47 | static DEFINE_MUTEX(thermal_governor_lock); | 47 | static DEFINE_MUTEX(thermal_governor_lock); |
48 | static DEFINE_MUTEX(poweroff_lock); | ||
48 | 49 | ||
49 | static atomic_t in_suspend; | 50 | static atomic_t in_suspend; |
51 | static bool power_off_triggered; | ||
50 | 52 | ||
51 | static struct thermal_governor *def_governor; | 53 | static struct thermal_governor *def_governor; |
52 | 54 | ||
@@ -322,6 +324,54 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, | |||
322 | def_governor->throttle(tz, trip); | 324 | def_governor->throttle(tz, trip); |
323 | } | 325 | } |
324 | 326 | ||
327 | /** | ||
328 | * thermal_emergency_poweroff_func - emergency poweroff work after a known delay | ||
329 | * @work: work_struct associated with the emergency poweroff function | ||
330 | * | ||
331 | * This function is called in very critical situations to force | ||
332 | * a kernel poweroff after a configurable timeout value. | ||
333 | */ | ||
334 | static void thermal_emergency_poweroff_func(struct work_struct *work) | ||
335 | { | ||
336 | /* | ||
337 | * We have reached here after the emergency thermal shutdown | ||
338 | * Waiting period has expired. This means orderly_poweroff has | ||
339 | * not been able to shut off the system for some reason. | ||
340 | * Try to shut down the system immediately using kernel_power_off | ||
341 | * if populated | ||
342 | */ | ||
343 | WARN(1, "Attempting kernel_power_off: Temperature too high\n"); | ||
344 | kernel_power_off(); | ||
345 | |||
346 | /* | ||
347 | * Worst of the worst case trigger emergency restart | ||
348 | */ | ||
349 | WARN(1, "Attempting emergency_restart: Temperature too high\n"); | ||
350 | emergency_restart(); | ||
351 | } | ||
352 | |||
353 | static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work, | ||
354 | thermal_emergency_poweroff_func); | ||
355 | |||
356 | /** | ||
357 | * thermal_emergency_poweroff - Trigger an emergency system poweroff | ||
358 | * | ||
359 | * This may be called from any critical situation to trigger a system shutdown | ||
360 | * after a known period of time. By default this is not scheduled. | ||
361 | */ | ||
362 | void thermal_emergency_poweroff(void) | ||
363 | { | ||
364 | int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; | ||
365 | /* | ||
366 | * poweroff_delay_ms must be a carefully profiled positive value. | ||
367 | * Its a must for thermal_emergency_poweroff_work to be scheduled | ||
368 | */ | ||
369 | if (poweroff_delay_ms <= 0) | ||
370 | return; | ||
371 | schedule_delayed_work(&thermal_emergency_poweroff_work, | ||
372 | msecs_to_jiffies(poweroff_delay_ms)); | ||
373 | } | ||
374 | |||
325 | static void handle_critical_trips(struct thermal_zone_device *tz, | 375 | static void handle_critical_trips(struct thermal_zone_device *tz, |
326 | int trip, enum thermal_trip_type trip_type) | 376 | int trip, enum thermal_trip_type trip_type) |
327 | { | 377 | { |
@@ -342,7 +392,17 @@ static void handle_critical_trips(struct thermal_zone_device *tz, | |||
342 | dev_emerg(&tz->device, | 392 | dev_emerg(&tz->device, |
343 | "critical temperature reached(%d C),shutting down\n", | 393 | "critical temperature reached(%d C),shutting down\n", |
344 | tz->temperature / 1000); | 394 | tz->temperature / 1000); |
345 | orderly_poweroff(true); | 395 | mutex_lock(&poweroff_lock); |
396 | if (!power_off_triggered) { | ||
397 | /* | ||
398 | * Queue a backup emergency shutdown in the event of | ||
399 | * orderly_poweroff failure | ||
400 | */ | ||
401 | thermal_emergency_poweroff(); | ||
402 | orderly_poweroff(true); | ||
403 | power_off_triggered = true; | ||
404 | } | ||
405 | mutex_unlock(&poweroff_lock); | ||
346 | } | 406 | } |
347 | } | 407 | } |
348 | 408 | ||
@@ -1463,6 +1523,7 @@ static int __init thermal_init(void) | |||
1463 | { | 1523 | { |
1464 | int result; | 1524 | int result; |
1465 | 1525 | ||
1526 | mutex_init(&poweroff_lock); | ||
1466 | result = thermal_register_governors(); | 1527 | result = thermal_register_governors(); |
1467 | if (result) | 1528 | if (result) |
1468 | goto error; | 1529 | goto error; |
@@ -1497,6 +1558,7 @@ error: | |||
1497 | ida_destroy(&thermal_cdev_ida); | 1558 | ida_destroy(&thermal_cdev_ida); |
1498 | mutex_destroy(&thermal_list_lock); | 1559 | mutex_destroy(&thermal_list_lock); |
1499 | mutex_destroy(&thermal_governor_lock); | 1560 | mutex_destroy(&thermal_governor_lock); |
1561 | mutex_destroy(&poweroff_lock); | ||
1500 | return result; | 1562 | return result; |
1501 | } | 1563 | } |
1502 | 1564 | ||
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h index c35d0c0e0ada..4635f95000a4 100644 --- a/include/linux/devfreq_cooling.h +++ b/include/linux/devfreq_cooling.h | |||
@@ -34,6 +34,23 @@ | |||
34 | * If get_dynamic_power() is NULL, then the | 34 | * If get_dynamic_power() is NULL, then the |
35 | * dynamic power is calculated as | 35 | * dynamic power is calculated as |
36 | * @dyn_power_coeff * frequency * voltage^2 | 36 | * @dyn_power_coeff * frequency * voltage^2 |
37 | * @get_real_power: When this is set, the framework uses it to ask the | ||
38 | * device driver for the actual power. | ||
39 | * Some devices have more sophisticated methods | ||
40 | * (like power counters) to approximate the actual power | ||
41 | * that they use. | ||
42 | * This function provides more accurate data to the | ||
43 | * thermal governor. When the driver does not provide | ||
44 | * such function, framework just uses pre-calculated | ||
45 | * table and scale the power by 'utilization' | ||
46 | * (based on 'busy_time' and 'total_time' taken from | ||
47 | * devfreq 'last_status'). | ||
48 | * The value returned by this function must be lower | ||
49 | * or equal than the maximum power value | ||
50 | * for the current state | ||
51 | * (which can be found in power_table[state]). | ||
52 | * When this interface is used, the power_table holds | ||
53 | * max total (static + dynamic) power value for each OPP. | ||
37 | */ | 54 | */ |
38 | struct devfreq_cooling_power { | 55 | struct devfreq_cooling_power { |
39 | unsigned long (*get_static_power)(struct devfreq *devfreq, | 56 | unsigned long (*get_static_power)(struct devfreq *devfreq, |
@@ -41,6 +58,8 @@ struct devfreq_cooling_power { | |||
41 | unsigned long (*get_dynamic_power)(struct devfreq *devfreq, | 58 | unsigned long (*get_dynamic_power)(struct devfreq *devfreq, |
42 | unsigned long freq, | 59 | unsigned long freq, |
43 | unsigned long voltage); | 60 | unsigned long voltage); |
61 | int (*get_real_power)(struct devfreq *df, u32 *power, | ||
62 | unsigned long freq, unsigned long voltage); | ||
44 | unsigned long dyn_power_coeff; | 63 | unsigned long dyn_power_coeff; |
45 | }; | 64 | }; |
46 | 65 | ||
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h index 2b4a8ff72d0d..6cde5b3514c2 100644 --- a/include/trace/events/thermal.h +++ b/include/trace/events/thermal.h | |||
@@ -151,9 +151,9 @@ TRACE_EVENT(thermal_power_cpu_limit, | |||
151 | TRACE_EVENT(thermal_power_devfreq_get_power, | 151 | TRACE_EVENT(thermal_power_devfreq_get_power, |
152 | TP_PROTO(struct thermal_cooling_device *cdev, | 152 | TP_PROTO(struct thermal_cooling_device *cdev, |
153 | struct devfreq_dev_status *status, unsigned long freq, | 153 | struct devfreq_dev_status *status, unsigned long freq, |
154 | u32 dynamic_power, u32 static_power), | 154 | u32 dynamic_power, u32 static_power, u32 power), |
155 | 155 | ||
156 | TP_ARGS(cdev, status, freq, dynamic_power, static_power), | 156 | TP_ARGS(cdev, status, freq, dynamic_power, static_power, power), |
157 | 157 | ||
158 | TP_STRUCT__entry( | 158 | TP_STRUCT__entry( |
159 | __string(type, cdev->type ) | 159 | __string(type, cdev->type ) |
@@ -161,6 +161,7 @@ TRACE_EVENT(thermal_power_devfreq_get_power, | |||
161 | __field(u32, load ) | 161 | __field(u32, load ) |
162 | __field(u32, dynamic_power ) | 162 | __field(u32, dynamic_power ) |
163 | __field(u32, static_power ) | 163 | __field(u32, static_power ) |
164 | __field(u32, power) | ||
164 | ), | 165 | ), |
165 | 166 | ||
166 | TP_fast_assign( | 167 | TP_fast_assign( |
@@ -169,11 +170,13 @@ TRACE_EVENT(thermal_power_devfreq_get_power, | |||
169 | __entry->load = (100 * status->busy_time) / status->total_time; | 170 | __entry->load = (100 * status->busy_time) / status->total_time; |
170 | __entry->dynamic_power = dynamic_power; | 171 | __entry->dynamic_power = dynamic_power; |
171 | __entry->static_power = static_power; | 172 | __entry->static_power = static_power; |
173 | __entry->power = power; | ||
172 | ), | 174 | ), |
173 | 175 | ||
174 | TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u", | 176 | TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u power=%u", |
175 | __get_str(type), __entry->freq, | 177 | __get_str(type), __entry->freq, |
176 | __entry->load, __entry->dynamic_power, __entry->static_power) | 178 | __entry->load, __entry->dynamic_power, __entry->static_power, |
179 | __entry->power) | ||
177 | ); | 180 | ); |
178 | 181 | ||
179 | TRACE_EVENT(thermal_power_devfreq_limit, | 182 | TRACE_EVENT(thermal_power_devfreq_limit, |