.. | .. |
---|
9 | 9 | |
---|
10 | 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
11 | 11 | |
---|
12 | | -#include <linux/module.h> |
---|
13 | 12 | #include <linux/device.h> |
---|
14 | 13 | #include <linux/err.h> |
---|
| 14 | +#include <linux/export.h> |
---|
15 | 15 | #include <linux/slab.h> |
---|
16 | 16 | #include <linux/kdev_t.h> |
---|
17 | 17 | #include <linux/idr.h> |
---|
.. | .. |
---|
19 | 19 | #include <linux/reboot.h> |
---|
20 | 20 | #include <linux/string.h> |
---|
21 | 21 | #include <linux/of.h> |
---|
22 | | -#include <net/netlink.h> |
---|
23 | | -#include <net/genetlink.h> |
---|
24 | 22 | #include <linux/suspend.h> |
---|
25 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
---|
26 | | -#include <soc/rockchip/rockchip_system_monitor.h> |
---|
27 | | -#endif |
---|
28 | 23 | |
---|
29 | 24 | #define CREATE_TRACE_POINTS |
---|
30 | 25 | #include <trace/events/thermal.h> |
---|
| 26 | +#undef CREATE_TRACE_POINTS |
---|
| 27 | +#include <trace/hooks/thermal.h> |
---|
31 | 28 | |
---|
32 | 29 | #include "thermal_core.h" |
---|
33 | 30 | #include "thermal_hwmon.h" |
---|
34 | | - |
---|
35 | | -MODULE_AUTHOR("Zhang Rui"); |
---|
36 | | -MODULE_DESCRIPTION("Generic thermal management sysfs support"); |
---|
37 | | -MODULE_LICENSE("GPL v2"); |
---|
38 | 31 | |
---|
39 | 32 | static DEFINE_IDA(thermal_tz_ida); |
---|
40 | 33 | static DEFINE_IDA(thermal_cdev_ida); |
---|
.. | .. |
---|
224 | 217 | mutex_unlock(&tz->lock); |
---|
225 | 218 | mutex_unlock(&thermal_governor_lock); |
---|
226 | 219 | |
---|
| 220 | + thermal_notify_tz_gov_change(tz->id, policy); |
---|
| 221 | + |
---|
227 | 222 | return ret; |
---|
228 | 223 | } |
---|
229 | 224 | |
---|
.. | .. |
---|
245 | 240 | return count; |
---|
246 | 241 | } |
---|
247 | 242 | |
---|
248 | | -static int __init thermal_register_governors(void) |
---|
| 243 | +static void __init thermal_unregister_governors(void) |
---|
249 | 244 | { |
---|
250 | | - int result; |
---|
| 245 | + struct thermal_governor **governor; |
---|
251 | 246 | |
---|
252 | | - result = thermal_gov_step_wise_register(); |
---|
253 | | - if (result) |
---|
254 | | - return result; |
---|
255 | | - |
---|
256 | | - result = thermal_gov_fair_share_register(); |
---|
257 | | - if (result) |
---|
258 | | - return result; |
---|
259 | | - |
---|
260 | | - result = thermal_gov_bang_bang_register(); |
---|
261 | | - if (result) |
---|
262 | | - return result; |
---|
263 | | - |
---|
264 | | - result = thermal_gov_user_space_register(); |
---|
265 | | - if (result) |
---|
266 | | - return result; |
---|
267 | | - |
---|
268 | | - return thermal_gov_power_allocator_register(); |
---|
| 247 | + for_each_governor_table(governor) |
---|
| 248 | + thermal_unregister_governor(*governor); |
---|
269 | 249 | } |
---|
270 | 250 | |
---|
271 | | -static void thermal_unregister_governors(void) |
---|
| 251 | +static int __init thermal_register_governors(void) |
---|
272 | 252 | { |
---|
273 | | - thermal_gov_step_wise_unregister(); |
---|
274 | | - thermal_gov_fair_share_unregister(); |
---|
275 | | - thermal_gov_bang_bang_unregister(); |
---|
276 | | - thermal_gov_user_space_unregister(); |
---|
277 | | - thermal_gov_power_allocator_unregister(); |
---|
| 253 | + int ret = 0; |
---|
| 254 | + struct thermal_governor **governor; |
---|
| 255 | + |
---|
| 256 | + for_each_governor_table(governor) { |
---|
| 257 | + ret = thermal_register_governor(*governor); |
---|
| 258 | + if (ret) { |
---|
| 259 | + pr_err("Failed to register governor: '%s'", |
---|
| 260 | + (*governor)->name); |
---|
| 261 | + break; |
---|
| 262 | + } |
---|
| 263 | + |
---|
| 264 | + pr_info("Registered thermal governor '%s'", |
---|
| 265 | + (*governor)->name); |
---|
| 266 | + } |
---|
| 267 | + |
---|
| 268 | + if (ret) { |
---|
| 269 | + struct thermal_governor **gov; |
---|
| 270 | + |
---|
| 271 | + for_each_governor_table(gov) { |
---|
| 272 | + if (gov == governor) |
---|
| 273 | + break; |
---|
| 274 | + thermal_unregister_governor(*gov); |
---|
| 275 | + } |
---|
| 276 | + } |
---|
| 277 | + |
---|
| 278 | + return ret; |
---|
278 | 279 | } |
---|
279 | 280 | |
---|
280 | 281 | /* |
---|
.. | .. |
---|
292 | 293 | int delay) |
---|
293 | 294 | { |
---|
294 | 295 | if (delay > 1000) |
---|
295 | | - mod_delayed_work(system_freezable_wq, &tz->poll_queue, |
---|
| 296 | + mod_delayed_work(system_freezable_power_efficient_wq, |
---|
| 297 | + &tz->poll_queue, |
---|
296 | 298 | round_jiffies(msecs_to_jiffies(delay))); |
---|
297 | 299 | else if (delay) |
---|
298 | | - mod_delayed_work(system_freezable_wq, &tz->poll_queue, |
---|
| 300 | + mod_delayed_work(system_freezable_power_efficient_wq, |
---|
| 301 | + &tz->poll_queue, |
---|
299 | 302 | msecs_to_jiffies(delay)); |
---|
300 | 303 | else |
---|
301 | 304 | cancel_delayed_work(&tz->poll_queue); |
---|
302 | 305 | } |
---|
303 | 306 | |
---|
| 307 | +static inline bool should_stop_polling(struct thermal_zone_device *tz) |
---|
| 308 | +{ |
---|
| 309 | + return !thermal_zone_device_is_enabled(tz); |
---|
| 310 | +} |
---|
| 311 | + |
---|
304 | 312 | static void monitor_thermal_zone(struct thermal_zone_device *tz) |
---|
305 | 313 | { |
---|
| 314 | + bool stop; |
---|
| 315 | + |
---|
| 316 | + stop = should_stop_polling(tz); |
---|
| 317 | + |
---|
306 | 318 | mutex_lock(&tz->lock); |
---|
307 | 319 | |
---|
308 | | - if (tz->passive) |
---|
| 320 | + if (!stop && tz->passive) |
---|
309 | 321 | thermal_zone_device_set_polling(tz, tz->passive_delay); |
---|
310 | | - else if (tz->polling_delay) |
---|
| 322 | + else if (!stop && tz->polling_delay) |
---|
311 | 323 | thermal_zone_device_set_polling(tz, tz->polling_delay); |
---|
312 | 324 | else |
---|
313 | 325 | thermal_zone_device_set_polling(tz, 0); |
---|
.. | .. |
---|
315 | 327 | mutex_unlock(&tz->lock); |
---|
316 | 328 | } |
---|
317 | 329 | |
---|
318 | | -static void handle_non_critical_trips(struct thermal_zone_device *tz, |
---|
319 | | - int trip, |
---|
320 | | - enum thermal_trip_type trip_type) |
---|
| 330 | +static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip) |
---|
321 | 331 | { |
---|
322 | 332 | tz->governor ? tz->governor->throttle(tz, trip) : |
---|
323 | 333 | def_governor->throttle(tz, trip); |
---|
.. | .. |
---|
408 | 418 | static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) |
---|
409 | 419 | { |
---|
410 | 420 | enum thermal_trip_type type; |
---|
| 421 | + int trip_temp, hyst = 0; |
---|
411 | 422 | |
---|
412 | 423 | /* Ignore disabled trip points */ |
---|
413 | 424 | if (test_bit(trip, &tz->trips_disabled)) |
---|
414 | 425 | return; |
---|
415 | 426 | |
---|
| 427 | + tz->ops->get_trip_temp(tz, trip, &trip_temp); |
---|
416 | 428 | tz->ops->get_trip_type(tz, trip, &type); |
---|
| 429 | + if (tz->ops->get_trip_hyst) |
---|
| 430 | + tz->ops->get_trip_hyst(tz, trip, &hyst); |
---|
| 431 | + |
---|
| 432 | + if (tz->last_temperature != THERMAL_TEMP_INVALID) { |
---|
| 433 | + if (tz->last_temperature < trip_temp && |
---|
| 434 | + tz->temperature >= trip_temp) |
---|
| 435 | + thermal_notify_tz_trip_up(tz->id, trip); |
---|
| 436 | + if (tz->last_temperature >= trip_temp && |
---|
| 437 | + tz->temperature < (trip_temp - hyst)) |
---|
| 438 | + thermal_notify_tz_trip_down(tz->id, trip); |
---|
| 439 | + } |
---|
417 | 440 | |
---|
418 | 441 | if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) |
---|
419 | 442 | handle_critical_trips(tz, trip, type); |
---|
420 | 443 | else |
---|
421 | | - handle_non_critical_trips(tz, trip, type); |
---|
| 444 | + handle_non_critical_trips(tz, trip); |
---|
422 | 445 | /* |
---|
423 | 446 | * Alright, we handled this trip successfully. |
---|
424 | 447 | * So, start monitoring again. |
---|
425 | 448 | */ |
---|
426 | 449 | monitor_thermal_zone(tz); |
---|
427 | | -} |
---|
428 | | - |
---|
429 | | -static void store_temperature(struct thermal_zone_device *tz, int temp) |
---|
430 | | -{ |
---|
431 | | - mutex_lock(&tz->lock); |
---|
432 | | - tz->last_temperature = tz->temperature; |
---|
433 | | - tz->temperature = temp; |
---|
434 | | - mutex_unlock(&tz->lock); |
---|
435 | | - |
---|
436 | | - trace_thermal_temperature(tz); |
---|
437 | | - if (tz->last_temperature == THERMAL_TEMP_INVALID || |
---|
438 | | - tz->last_temperature == THERMAL_TEMP_INVALID_LOW) |
---|
439 | | - dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", |
---|
440 | | - tz->temperature); |
---|
441 | | - else |
---|
442 | | - dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", |
---|
443 | | - tz->last_temperature, tz->temperature); |
---|
444 | 450 | } |
---|
445 | 451 | |
---|
446 | 452 | static void update_temperature(struct thermal_zone_device *tz) |
---|
.. | .. |
---|
455 | 461 | ret); |
---|
456 | 462 | return; |
---|
457 | 463 | } |
---|
458 | | - store_temperature(tz, temp); |
---|
| 464 | + |
---|
| 465 | + mutex_lock(&tz->lock); |
---|
| 466 | + tz->last_temperature = tz->temperature; |
---|
| 467 | + tz->temperature = temp; |
---|
| 468 | + mutex_unlock(&tz->lock); |
---|
| 469 | + |
---|
| 470 | + trace_thermal_temperature(tz); |
---|
| 471 | + |
---|
| 472 | + thermal_genl_sampling_temp(tz->id, temp); |
---|
459 | 473 | } |
---|
460 | 474 | |
---|
461 | 475 | static void thermal_zone_device_init(struct thermal_zone_device *tz) |
---|
.. | .. |
---|
474 | 488 | thermal_zone_device_init(tz); |
---|
475 | 489 | } |
---|
476 | 490 | |
---|
477 | | -void thermal_zone_device_update_temp(struct thermal_zone_device *tz, |
---|
478 | | - enum thermal_notify_event event, int temp) |
---|
| 491 | +static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, |
---|
| 492 | + enum thermal_device_mode mode) |
---|
479 | 493 | { |
---|
480 | | - int count; |
---|
| 494 | + int ret = 0; |
---|
481 | 495 | |
---|
482 | | - if (!tz || !tz->ops) |
---|
483 | | - return; |
---|
| 496 | + mutex_lock(&tz->lock); |
---|
484 | 497 | |
---|
485 | | - if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable || |
---|
486 | | - !(tz->ops->is_wakeable(tz)))) |
---|
487 | | - return; |
---|
| 498 | + /* do nothing if mode isn't changing */ |
---|
| 499 | + if (mode == tz->mode) { |
---|
| 500 | + mutex_unlock(&tz->lock); |
---|
488 | 501 | |
---|
489 | | - store_temperature(tz, temp); |
---|
| 502 | + return ret; |
---|
| 503 | + } |
---|
490 | 504 | |
---|
491 | | - thermal_zone_set_trips(tz); |
---|
| 505 | + if (tz->ops->change_mode) |
---|
| 506 | + ret = tz->ops->change_mode(tz, mode); |
---|
492 | 507 | |
---|
493 | | - tz->notify_event = event; |
---|
| 508 | + if (!ret) |
---|
| 509 | + tz->mode = mode; |
---|
494 | 510 | |
---|
495 | | - for (count = 0; count < tz->trips; count++) |
---|
496 | | - handle_thermal_trip(tz, count); |
---|
| 511 | + mutex_unlock(&tz->lock); |
---|
| 512 | + |
---|
| 513 | + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
---|
| 514 | + |
---|
| 515 | + if (mode == THERMAL_DEVICE_ENABLED) |
---|
| 516 | + thermal_notify_tz_enable(tz->id); |
---|
| 517 | + else |
---|
| 518 | + thermal_notify_tz_disable(tz->id); |
---|
| 519 | + |
---|
| 520 | + return ret; |
---|
497 | 521 | } |
---|
| 522 | + |
---|
| 523 | +int thermal_zone_device_enable(struct thermal_zone_device *tz) |
---|
| 524 | +{ |
---|
| 525 | + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED); |
---|
| 526 | +} |
---|
| 527 | +EXPORT_SYMBOL_GPL(thermal_zone_device_enable); |
---|
| 528 | + |
---|
| 529 | +int thermal_zone_device_disable(struct thermal_zone_device *tz) |
---|
| 530 | +{ |
---|
| 531 | + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED); |
---|
| 532 | +} |
---|
| 533 | +EXPORT_SYMBOL_GPL(thermal_zone_device_disable); |
---|
| 534 | + |
---|
| 535 | +int thermal_zone_device_is_enabled(struct thermal_zone_device *tz) |
---|
| 536 | +{ |
---|
| 537 | + enum thermal_device_mode mode; |
---|
| 538 | + |
---|
| 539 | + mutex_lock(&tz->lock); |
---|
| 540 | + |
---|
| 541 | + mode = tz->mode; |
---|
| 542 | + |
---|
| 543 | + mutex_unlock(&tz->lock); |
---|
| 544 | + |
---|
| 545 | + return mode == THERMAL_DEVICE_ENABLED; |
---|
| 546 | +} |
---|
| 547 | +EXPORT_SYMBOL_GPL(thermal_zone_device_is_enabled); |
---|
498 | 548 | |
---|
499 | 549 | void thermal_zone_device_update(struct thermal_zone_device *tz, |
---|
500 | 550 | enum thermal_notify_event event) |
---|
501 | 551 | { |
---|
502 | 552 | int count; |
---|
503 | 553 | |
---|
504 | | - if (!tz || !tz->ops) |
---|
| 554 | + if (should_stop_polling(tz)) |
---|
505 | 555 | return; |
---|
506 | 556 | |
---|
507 | | - if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable || |
---|
508 | | - !(tz->ops->is_wakeable(tz)))) |
---|
| 557 | + if (atomic_read(&in_suspend)) |
---|
509 | 558 | return; |
---|
510 | 559 | |
---|
511 | 560 | if (!tz->ops->get_temp) |
---|
.. | .. |
---|
558 | 607 | /** |
---|
559 | 608 | * power_actor_get_max_power() - get the maximum power that a cdev can consume |
---|
560 | 609 | * @cdev: pointer to &thermal_cooling_device |
---|
561 | | - * @tz: a valid thermal zone device pointer |
---|
562 | 610 | * @max_power: pointer in which to store the maximum power |
---|
563 | 611 | * |
---|
564 | 612 | * Calculate the maximum power consumption in milliwats that the |
---|
.. | .. |
---|
568 | 616 | * power_actor API or -E* on other error. |
---|
569 | 617 | */ |
---|
570 | 618 | int power_actor_get_max_power(struct thermal_cooling_device *cdev, |
---|
571 | | - struct thermal_zone_device *tz, u32 *max_power) |
---|
| 619 | + u32 *max_power) |
---|
572 | 620 | { |
---|
573 | 621 | if (!cdev_is_power_actor(cdev)) |
---|
574 | 622 | return -EINVAL; |
---|
575 | 623 | |
---|
576 | | - return cdev->ops->state2power(cdev, tz, 0, max_power); |
---|
| 624 | + return cdev->ops->state2power(cdev, 0, max_power); |
---|
577 | 625 | } |
---|
578 | 626 | |
---|
579 | 627 | /** |
---|
580 | 628 | * power_actor_get_min_power() - get the mainimum power that a cdev can consume |
---|
581 | 629 | * @cdev: pointer to &thermal_cooling_device |
---|
582 | | - * @tz: a valid thermal zone device pointer |
---|
583 | 630 | * @min_power: pointer in which to store the minimum power |
---|
584 | 631 | * |
---|
585 | 632 | * Calculate the minimum power consumption in milliwatts that the |
---|
.. | .. |
---|
589 | 636 | * power_actor API or -E* on other error. |
---|
590 | 637 | */ |
---|
591 | 638 | int power_actor_get_min_power(struct thermal_cooling_device *cdev, |
---|
592 | | - struct thermal_zone_device *tz, u32 *min_power) |
---|
| 639 | + u32 *min_power) |
---|
593 | 640 | { |
---|
594 | 641 | unsigned long max_state; |
---|
595 | 642 | int ret; |
---|
.. | .. |
---|
601 | 648 | if (ret) |
---|
602 | 649 | return ret; |
---|
603 | 650 | |
---|
604 | | - return cdev->ops->state2power(cdev, tz, max_state, min_power); |
---|
| 651 | + return cdev->ops->state2power(cdev, max_state, min_power); |
---|
605 | 652 | } |
---|
606 | 653 | |
---|
607 | 654 | /** |
---|
.. | .. |
---|
625 | 672 | if (!cdev_is_power_actor(cdev)) |
---|
626 | 673 | return -EINVAL; |
---|
627 | 674 | |
---|
628 | | - ret = cdev->ops->power2state(cdev, instance->tz, power, &state); |
---|
629 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
---|
630 | | - if (ret) |
---|
631 | | - state = THERMAL_CSTATE_INVALID; |
---|
632 | | - rockchip_system_monitor_adjust_cdev_state(cdev, |
---|
633 | | - instance->tz->temperature, |
---|
634 | | - &state); |
---|
635 | | - if (state == THERMAL_CSTATE_INVALID) |
---|
636 | | - ret = -EINVAL; |
---|
637 | | -#endif |
---|
| 675 | + ret = cdev->ops->power2state(cdev, power, &state); |
---|
638 | 676 | if (ret) |
---|
639 | 677 | return ret; |
---|
640 | 678 | |
---|
.. | .. |
---|
665 | 703 | THERMAL_WEIGHT_DEFAULT); |
---|
666 | 704 | } |
---|
667 | 705 | mutex_unlock(&thermal_list_lock); |
---|
| 706 | +} |
---|
| 707 | + |
---|
| 708 | +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), |
---|
| 709 | + void *data) |
---|
| 710 | +{ |
---|
| 711 | + struct thermal_governor *gov; |
---|
| 712 | + int ret = 0; |
---|
| 713 | + |
---|
| 714 | + mutex_lock(&thermal_governor_lock); |
---|
| 715 | + list_for_each_entry(gov, &thermal_governor_list, governor_list) { |
---|
| 716 | + ret = cb(gov, data); |
---|
| 717 | + if (ret) |
---|
| 718 | + break; |
---|
| 719 | + } |
---|
| 720 | + mutex_unlock(&thermal_governor_lock); |
---|
| 721 | + |
---|
| 722 | + return ret; |
---|
| 723 | +} |
---|
| 724 | + |
---|
| 725 | +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, |
---|
| 726 | + void *), void *data) |
---|
| 727 | +{ |
---|
| 728 | + struct thermal_cooling_device *cdev; |
---|
| 729 | + int ret = 0; |
---|
| 730 | + |
---|
| 731 | + mutex_lock(&thermal_list_lock); |
---|
| 732 | + list_for_each_entry(cdev, &thermal_cdev_list, node) { |
---|
| 733 | + ret = cb(cdev, data); |
---|
| 734 | + if (ret) |
---|
| 735 | + break; |
---|
| 736 | + } |
---|
| 737 | + mutex_unlock(&thermal_list_lock); |
---|
| 738 | + |
---|
| 739 | + return ret; |
---|
| 740 | +} |
---|
| 741 | + |
---|
| 742 | +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), |
---|
| 743 | + void *data) |
---|
| 744 | +{ |
---|
| 745 | + struct thermal_zone_device *tz; |
---|
| 746 | + int ret = 0; |
---|
| 747 | + |
---|
| 748 | + mutex_lock(&thermal_list_lock); |
---|
| 749 | + list_for_each_entry(tz, &thermal_tz_list, node) { |
---|
| 750 | + ret = cb(tz, data); |
---|
| 751 | + if (ret) |
---|
| 752 | + break; |
---|
| 753 | + } |
---|
| 754 | + mutex_unlock(&thermal_list_lock); |
---|
| 755 | + |
---|
| 756 | + return ret; |
---|
| 757 | +} |
---|
| 758 | + |
---|
| 759 | +struct thermal_zone_device *thermal_zone_get_by_id(int id) |
---|
| 760 | +{ |
---|
| 761 | + struct thermal_zone_device *tz, *match = NULL; |
---|
| 762 | + |
---|
| 763 | + mutex_lock(&thermal_list_lock); |
---|
| 764 | + list_for_each_entry(tz, &thermal_tz_list, node) { |
---|
| 765 | + if (tz->id == id) { |
---|
| 766 | + match = tz; |
---|
| 767 | + break; |
---|
| 768 | + } |
---|
| 769 | + } |
---|
| 770 | + mutex_unlock(&thermal_list_lock); |
---|
| 771 | + |
---|
| 772 | + return match; |
---|
668 | 773 | } |
---|
669 | 774 | |
---|
670 | 775 | void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, |
---|
.. | .. |
---|
780 | 885 | sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); |
---|
781 | 886 | sysfs_attr_init(&dev->attr.attr); |
---|
782 | 887 | dev->attr.attr.name = dev->attr_name; |
---|
783 | | - dev->attr.attr.mode = 0644; |
---|
| 888 | + dev->attr.attr.mode = 0444; |
---|
784 | 889 | dev->attr.show = trip_point_show; |
---|
785 | | - dev->attr.store = trip_point_store; |
---|
786 | 890 | result = device_create_file(&tz->device, &dev->attr); |
---|
787 | 891 | if (result) |
---|
788 | 892 | goto remove_symbol_link; |
---|
.. | .. |
---|
1024 | 1128 | result = device_register(&cdev->device); |
---|
1025 | 1129 | if (result) { |
---|
1026 | 1130 | ida_simple_remove(&thermal_cdev_ida, cdev->id); |
---|
1027 | | - kfree(cdev); |
---|
| 1131 | + put_device(&cdev->device); |
---|
1028 | 1132 | return ERR_PTR(result); |
---|
1029 | 1133 | } |
---|
1030 | 1134 | |
---|
.. | .. |
---|
1090 | 1194 | return __thermal_cooling_device_register(np, type, devdata, ops); |
---|
1091 | 1195 | } |
---|
1092 | 1196 | EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register); |
---|
| 1197 | + |
---|
| 1198 | +static void thermal_cooling_device_release(struct device *dev, void *res) |
---|
| 1199 | +{ |
---|
| 1200 | + thermal_cooling_device_unregister( |
---|
| 1201 | + *(struct thermal_cooling_device **)res); |
---|
| 1202 | +} |
---|
| 1203 | + |
---|
| 1204 | +/** |
---|
| 1205 | + * devm_thermal_of_cooling_device_register() - register an OF thermal cooling |
---|
| 1206 | + * device |
---|
| 1207 | + * @dev: a valid struct device pointer of a sensor device. |
---|
| 1208 | + * @np: a pointer to a device tree node. |
---|
| 1209 | + * @type: the thermal cooling device type. |
---|
| 1210 | + * @devdata: device private data. |
---|
| 1211 | + * @ops: standard thermal cooling devices callbacks. |
---|
| 1212 | + * |
---|
| 1213 | + * This function will register a cooling device with device tree node reference. |
---|
| 1214 | + * This interface function adds a new thermal cooling device (fan/processor/...) |
---|
| 1215 | + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself |
---|
| 1216 | + * to all the thermal zone devices registered at the same time. |
---|
| 1217 | + * |
---|
| 1218 | + * Return: a pointer to the created struct thermal_cooling_device or an |
---|
| 1219 | + * ERR_PTR. Caller must check return value with IS_ERR*() helpers. |
---|
| 1220 | + */ |
---|
| 1221 | +struct thermal_cooling_device * |
---|
| 1222 | +devm_thermal_of_cooling_device_register(struct device *dev, |
---|
| 1223 | + struct device_node *np, |
---|
| 1224 | + char *type, void *devdata, |
---|
| 1225 | + const struct thermal_cooling_device_ops *ops) |
---|
| 1226 | +{ |
---|
| 1227 | + struct thermal_cooling_device **ptr, *tcd; |
---|
| 1228 | + |
---|
| 1229 | + ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr), |
---|
| 1230 | + GFP_KERNEL); |
---|
| 1231 | + if (!ptr) |
---|
| 1232 | + return ERR_PTR(-ENOMEM); |
---|
| 1233 | + |
---|
| 1234 | + tcd = __thermal_cooling_device_register(np, type, devdata, ops); |
---|
| 1235 | + if (IS_ERR(tcd)) { |
---|
| 1236 | + devres_free(ptr); |
---|
| 1237 | + return tcd; |
---|
| 1238 | + } |
---|
| 1239 | + |
---|
| 1240 | + *ptr = tcd; |
---|
| 1241 | + devres_add(dev, ptr); |
---|
| 1242 | + |
---|
| 1243 | + return tcd; |
---|
| 1244 | +} |
---|
| 1245 | +EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register); |
---|
1093 | 1246 | |
---|
1094 | 1247 | static void __unbind(struct thermal_zone_device *tz, int mask, |
---|
1095 | 1248 | struct thermal_cooling_device *cdev) |
---|
.. | .. |
---|
1230 | 1383 | struct thermal_zone_device *tz; |
---|
1231 | 1384 | enum thermal_trip_type trip_type; |
---|
1232 | 1385 | int trip_temp; |
---|
| 1386 | + int id; |
---|
1233 | 1387 | int result; |
---|
1234 | 1388 | int count; |
---|
1235 | 1389 | struct thermal_governor *governor; |
---|
1236 | 1390 | |
---|
1237 | | - if (!type || strlen(type) == 0) |
---|
| 1391 | + if (!type || strlen(type) == 0) { |
---|
| 1392 | + pr_err("Error: No thermal zone type defined\n"); |
---|
1238 | 1393 | return ERR_PTR(-EINVAL); |
---|
| 1394 | + } |
---|
1239 | 1395 | |
---|
1240 | | - if (type && strlen(type) >= THERMAL_NAME_LENGTH) |
---|
| 1396 | + if (type && strlen(type) >= THERMAL_NAME_LENGTH) { |
---|
| 1397 | + pr_err("Error: Thermal zone name (%s) too long, should be under %d chars\n", |
---|
| 1398 | + type, THERMAL_NAME_LENGTH); |
---|
1241 | 1399 | return ERR_PTR(-EINVAL); |
---|
| 1400 | + } |
---|
1242 | 1401 | |
---|
1243 | | - if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) |
---|
| 1402 | + if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) { |
---|
| 1403 | + pr_err("Error: Incorrect number of thermal trips\n"); |
---|
1244 | 1404 | return ERR_PTR(-EINVAL); |
---|
| 1405 | + } |
---|
1245 | 1406 | |
---|
1246 | | - if (!ops) |
---|
| 1407 | + if (!ops) { |
---|
| 1408 | + pr_err("Error: Thermal zone device ops not defined\n"); |
---|
1247 | 1409 | return ERR_PTR(-EINVAL); |
---|
| 1410 | + } |
---|
1248 | 1411 | |
---|
1249 | 1412 | if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp)) |
---|
1250 | 1413 | return ERR_PTR(-EINVAL); |
---|
.. | .. |
---|
1256 | 1419 | INIT_LIST_HEAD(&tz->thermal_instances); |
---|
1257 | 1420 | ida_init(&tz->ida); |
---|
1258 | 1421 | mutex_init(&tz->lock); |
---|
1259 | | - result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL); |
---|
1260 | | - if (result < 0) |
---|
| 1422 | + id = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL); |
---|
| 1423 | + if (id < 0) { |
---|
| 1424 | + result = id; |
---|
1261 | 1425 | goto free_tz; |
---|
| 1426 | + } |
---|
1262 | 1427 | |
---|
1263 | | - tz->id = result; |
---|
| 1428 | + tz->id = id; |
---|
1264 | 1429 | strlcpy(tz->type, type, sizeof(tz->type)); |
---|
1265 | 1430 | tz->ops = ops; |
---|
1266 | 1431 | tz->tzp = tzp; |
---|
.. | .. |
---|
1282 | 1447 | dev_set_name(&tz->device, "thermal_zone%d", tz->id); |
---|
1283 | 1448 | result = device_register(&tz->device); |
---|
1284 | 1449 | if (result) |
---|
1285 | | - goto remove_device_groups; |
---|
| 1450 | + goto release_device; |
---|
1286 | 1451 | |
---|
1287 | 1452 | for (count = 0; count < trips; count++) { |
---|
1288 | 1453 | if (tz->ops->get_trip_type(tz, count, &trip_type)) |
---|
.. | .. |
---|
1330 | 1495 | if (atomic_cmpxchg(&tz->need_update, 1, 0)) |
---|
1331 | 1496 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
---|
1332 | 1497 | |
---|
| 1498 | + thermal_notify_tz_create(tz->id, tz->type); |
---|
| 1499 | + |
---|
1333 | 1500 | return tz; |
---|
1334 | 1501 | |
---|
1335 | 1502 | unregister: |
---|
1336 | | - ida_simple_remove(&thermal_tz_ida, tz->id); |
---|
1337 | | - device_unregister(&tz->device); |
---|
1338 | | - return ERR_PTR(result); |
---|
1339 | | - |
---|
1340 | | -remove_device_groups: |
---|
1341 | | - thermal_zone_destroy_device_groups(tz); |
---|
| 1503 | + device_del(&tz->device); |
---|
| 1504 | +release_device: |
---|
| 1505 | + put_device(&tz->device); |
---|
| 1506 | + tz = NULL; |
---|
1342 | 1507 | remove_id: |
---|
1343 | | - ida_simple_remove(&thermal_tz_ida, tz->id); |
---|
| 1508 | + ida_simple_remove(&thermal_tz_ida, id); |
---|
1344 | 1509 | free_tz: |
---|
1345 | 1510 | kfree(tz); |
---|
1346 | 1511 | return ERR_PTR(result); |
---|
.. | .. |
---|
1353 | 1518 | */ |
---|
1354 | 1519 | void thermal_zone_device_unregister(struct thermal_zone_device *tz) |
---|
1355 | 1520 | { |
---|
1356 | | - int i; |
---|
| 1521 | + int i, tz_id; |
---|
1357 | 1522 | const struct thermal_zone_params *tzp; |
---|
1358 | 1523 | struct thermal_cooling_device *cdev; |
---|
1359 | 1524 | struct thermal_zone_device *pos = NULL; |
---|
.. | .. |
---|
1362 | 1527 | return; |
---|
1363 | 1528 | |
---|
1364 | 1529 | tzp = tz->tzp; |
---|
| 1530 | + tz_id = tz->id; |
---|
1365 | 1531 | |
---|
1366 | 1532 | mutex_lock(&thermal_list_lock); |
---|
1367 | 1533 | list_for_each_entry(pos, &thermal_tz_list, node) |
---|
.. | .. |
---|
1403 | 1569 | ida_destroy(&tz->ida); |
---|
1404 | 1570 | mutex_destroy(&tz->lock); |
---|
1405 | 1571 | device_unregister(&tz->device); |
---|
| 1572 | + |
---|
| 1573 | + thermal_notify_tz_delete(tz_id); |
---|
1406 | 1574 | } |
---|
1407 | 1575 | EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); |
---|
1408 | 1576 | |
---|
.. | .. |
---|
1444 | 1612 | } |
---|
1445 | 1613 | EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); |
---|
1446 | 1614 | |
---|
1447 | | -/** |
---|
1448 | | - * thermal_zone_get_cdev_by_name() - search for a cooling device and returns |
---|
1449 | | - * its ref. |
---|
1450 | | - * @name: thermal cdev name to fetch the temperature |
---|
1451 | | - * |
---|
1452 | | - * When only one cdev is found with the passed name, returns a reference to it. |
---|
1453 | | - * |
---|
1454 | | - * Return: On success returns a reference to an unique thermal cooling device |
---|
1455 | | - * with matching name equals to @name, an ERR_PTR otherwise (-EINVAL for |
---|
1456 | | - * invalid paramenters, -ENODEV for not found and -EEXIST for multiple matches). |
---|
1457 | | - */ |
---|
1458 | | -struct thermal_cooling_device *thermal_zone_get_cdev_by_name(const char *name) |
---|
1459 | | -{ |
---|
1460 | | - struct thermal_cooling_device *pos = NULL, *ref = ERR_PTR(-EINVAL); |
---|
1461 | | - unsigned int found = 0; |
---|
1462 | | - |
---|
1463 | | - if (!name) |
---|
1464 | | - return ref; |
---|
1465 | | - |
---|
1466 | | - mutex_lock(&thermal_list_lock); |
---|
1467 | | - list_for_each_entry(pos, &thermal_cdev_list, node) |
---|
1468 | | - if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) { |
---|
1469 | | - found++; |
---|
1470 | | - ref = pos; |
---|
1471 | | - } |
---|
1472 | | - mutex_unlock(&thermal_list_lock); |
---|
1473 | | - |
---|
1474 | | - /* nothing has been found, thus an error code for it */ |
---|
1475 | | - if (found == 0) |
---|
1476 | | - return ERR_PTR(-ENODEV); |
---|
1477 | | - if (found > 1) |
---|
1478 | | - return ERR_PTR(-EEXIST); |
---|
1479 | | - return ref; |
---|
1480 | | - |
---|
1481 | | -} |
---|
1482 | | -EXPORT_SYMBOL_GPL(thermal_zone_get_cdev_by_name); |
---|
1483 | | - |
---|
1484 | | -#ifdef CONFIG_NET |
---|
1485 | | -static const struct genl_multicast_group thermal_event_mcgrps[] = { |
---|
1486 | | - { .name = THERMAL_GENL_MCAST_GROUP_NAME, }, |
---|
1487 | | -}; |
---|
1488 | | - |
---|
1489 | | -static struct genl_family thermal_event_genl_family __ro_after_init = { |
---|
1490 | | - .module = THIS_MODULE, |
---|
1491 | | - .name = THERMAL_GENL_FAMILY_NAME, |
---|
1492 | | - .version = THERMAL_GENL_VERSION, |
---|
1493 | | - .maxattr = THERMAL_GENL_ATTR_MAX, |
---|
1494 | | - .mcgrps = thermal_event_mcgrps, |
---|
1495 | | - .n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps), |
---|
1496 | | -}; |
---|
1497 | | - |
---|
1498 | | -int thermal_generate_netlink_event(struct thermal_zone_device *tz, |
---|
1499 | | - enum events event) |
---|
1500 | | -{ |
---|
1501 | | - struct sk_buff *skb; |
---|
1502 | | - struct nlattr *attr; |
---|
1503 | | - struct thermal_genl_event *thermal_event; |
---|
1504 | | - void *msg_header; |
---|
1505 | | - int size; |
---|
1506 | | - int result; |
---|
1507 | | - static unsigned int thermal_event_seqnum; |
---|
1508 | | - |
---|
1509 | | - if (!tz) |
---|
1510 | | - return -EINVAL; |
---|
1511 | | - |
---|
1512 | | - /* allocate memory */ |
---|
1513 | | - size = nla_total_size(sizeof(struct thermal_genl_event)) + |
---|
1514 | | - nla_total_size(0); |
---|
1515 | | - |
---|
1516 | | - skb = genlmsg_new(size, GFP_ATOMIC); |
---|
1517 | | - if (!skb) |
---|
1518 | | - return -ENOMEM; |
---|
1519 | | - |
---|
1520 | | - /* add the genetlink message header */ |
---|
1521 | | - msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++, |
---|
1522 | | - &thermal_event_genl_family, 0, |
---|
1523 | | - THERMAL_GENL_CMD_EVENT); |
---|
1524 | | - if (!msg_header) { |
---|
1525 | | - nlmsg_free(skb); |
---|
1526 | | - return -ENOMEM; |
---|
1527 | | - } |
---|
1528 | | - |
---|
1529 | | - /* fill the data */ |
---|
1530 | | - attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, |
---|
1531 | | - sizeof(struct thermal_genl_event)); |
---|
1532 | | - |
---|
1533 | | - if (!attr) { |
---|
1534 | | - nlmsg_free(skb); |
---|
1535 | | - return -EINVAL; |
---|
1536 | | - } |
---|
1537 | | - |
---|
1538 | | - thermal_event = nla_data(attr); |
---|
1539 | | - if (!thermal_event) { |
---|
1540 | | - nlmsg_free(skb); |
---|
1541 | | - return -EINVAL; |
---|
1542 | | - } |
---|
1543 | | - |
---|
1544 | | - memset(thermal_event, 0, sizeof(struct thermal_genl_event)); |
---|
1545 | | - |
---|
1546 | | - thermal_event->orig = tz->id; |
---|
1547 | | - thermal_event->event = event; |
---|
1548 | | - |
---|
1549 | | - /* send multicast genetlink message */ |
---|
1550 | | - genlmsg_end(skb, msg_header); |
---|
1551 | | - |
---|
1552 | | - result = genlmsg_multicast(&thermal_event_genl_family, skb, 0, |
---|
1553 | | - 0, GFP_ATOMIC); |
---|
1554 | | - if (result) |
---|
1555 | | - dev_err(&tz->device, "Failed to send netlink event:%d", result); |
---|
1556 | | - |
---|
1557 | | - return result; |
---|
1558 | | -} |
---|
1559 | | -EXPORT_SYMBOL_GPL(thermal_generate_netlink_event); |
---|
1560 | | - |
---|
1561 | | -static int __init genetlink_init(void) |
---|
1562 | | -{ |
---|
1563 | | - return genl_register_family(&thermal_event_genl_family); |
---|
1564 | | -} |
---|
1565 | | - |
---|
1566 | | -static void genetlink_exit(void) |
---|
1567 | | -{ |
---|
1568 | | - genl_unregister_family(&thermal_event_genl_family); |
---|
1569 | | -} |
---|
1570 | | -#else /* !CONFIG_NET */ |
---|
1571 | | -static inline int genetlink_init(void) { return 0; } |
---|
1572 | | -static inline void genetlink_exit(void) {} |
---|
1573 | | -#endif /* !CONFIG_NET */ |
---|
1574 | | - |
---|
1575 | 1615 | static int thermal_pm_notify(struct notifier_block *nb, |
---|
1576 | 1616 | unsigned long mode, void *_unused) |
---|
1577 | 1617 | { |
---|
1578 | 1618 | struct thermal_zone_device *tz; |
---|
| 1619 | + int irq_wakeable = 0; |
---|
1579 | 1620 | |
---|
1580 | 1621 | switch (mode) { |
---|
1581 | 1622 | case PM_HIBERNATION_PREPARE: |
---|
.. | .. |
---|
1588 | 1629 | case PM_POST_SUSPEND: |
---|
1589 | 1630 | atomic_set(&in_suspend, 0); |
---|
1590 | 1631 | list_for_each_entry(tz, &thermal_tz_list, node) { |
---|
1591 | | - if (tz->ops && tz->ops->is_wakeable && |
---|
1592 | | - tz->ops->is_wakeable(tz)) |
---|
| 1632 | + if (!thermal_zone_device_is_enabled(tz)) |
---|
1593 | 1633 | continue; |
---|
| 1634 | + |
---|
| 1635 | + trace_android_vh_thermal_pm_notify_suspend(tz, &irq_wakeable); |
---|
| 1636 | + if (irq_wakeable) |
---|
| 1637 | + continue; |
---|
| 1638 | + |
---|
1594 | 1639 | thermal_zone_device_init(tz); |
---|
1595 | 1640 | thermal_zone_device_update(tz, |
---|
1596 | 1641 | THERMAL_EVENT_UNSPECIFIED); |
---|
.. | .. |
---|
1610 | 1655 | { |
---|
1611 | 1656 | int result; |
---|
1612 | 1657 | |
---|
1613 | | - mutex_init(&poweroff_lock); |
---|
| 1658 | + result = thermal_netlink_init(); |
---|
| 1659 | + if (result) |
---|
| 1660 | + goto error; |
---|
| 1661 | + |
---|
1614 | 1662 | result = thermal_register_governors(); |
---|
1615 | 1663 | if (result) |
---|
1616 | 1664 | goto error; |
---|
.. | .. |
---|
1619 | 1667 | if (result) |
---|
1620 | 1668 | goto unregister_governors; |
---|
1621 | 1669 | |
---|
1622 | | - result = genetlink_init(); |
---|
1623 | | - if (result) |
---|
1624 | | - goto unregister_class; |
---|
1625 | | - |
---|
1626 | 1670 | result = of_parse_thermal_zones(); |
---|
1627 | 1671 | if (result) |
---|
1628 | | - goto exit_netlink; |
---|
| 1672 | + goto unregister_class; |
---|
1629 | 1673 | |
---|
1630 | 1674 | result = register_pm_notifier(&thermal_pm_nb); |
---|
1631 | 1675 | if (result) |
---|
.. | .. |
---|
1634 | 1678 | |
---|
1635 | 1679 | return 0; |
---|
1636 | 1680 | |
---|
1637 | | -exit_netlink: |
---|
1638 | | - genetlink_exit(); |
---|
1639 | 1681 | unregister_class: |
---|
1640 | 1682 | class_unregister(&thermal_class); |
---|
1641 | 1683 | unregister_governors: |
---|
.. | .. |
---|
1648 | 1690 | mutex_destroy(&poweroff_lock); |
---|
1649 | 1691 | return result; |
---|
1650 | 1692 | } |
---|
1651 | | - |
---|
1652 | | -static void __exit thermal_exit(void) |
---|
1653 | | -{ |
---|
1654 | | - unregister_pm_notifier(&thermal_pm_nb); |
---|
1655 | | - of_thermal_destroy_zones(); |
---|
1656 | | - genetlink_exit(); |
---|
1657 | | - class_unregister(&thermal_class); |
---|
1658 | | - thermal_unregister_governors(); |
---|
1659 | | - ida_destroy(&thermal_tz_ida); |
---|
1660 | | - ida_destroy(&thermal_cdev_ida); |
---|
1661 | | - mutex_destroy(&thermal_list_lock); |
---|
1662 | | - mutex_destroy(&thermal_governor_lock); |
---|
1663 | | -} |
---|
1664 | | - |
---|
1665 | | -fs_initcall(thermal_init); |
---|
1666 | | -module_exit(thermal_exit); |
---|
| 1693 | +postcore_initcall(thermal_init); |
---|