| .. | .. |
|---|
| 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); |
|---|