diff options
Diffstat (limited to 'drivers/thermal/thermal_core.c')
-rw-r--r-- | drivers/thermal/thermal_core.c | 174 |
1 files changed, 165 insertions, 9 deletions
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index b71196eaf90e..72bf159bcecc 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -215,6 +215,8 @@ exit: mutex_unlock(&tz->lock); mutex_unlock(&thermal_governor_lock); + thermal_notify_tz_gov_change(tz->id, policy); + return ret; } @@ -301,13 +303,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, cancel_delayed_work(&tz->poll_queue); } +static inline bool should_stop_polling(struct thermal_zone_device *tz) +{ + return !thermal_zone_device_is_enabled(tz); +} + static void monitor_thermal_zone(struct thermal_zone_device *tz) { + bool stop; + + stop = should_stop_polling(tz); + mutex_lock(&tz->lock); - if (tz->passive) + if (!stop && tz->passive) thermal_zone_device_set_polling(tz, tz->passive_delay); - else if (tz->polling_delay) + else if (!stop && tz->polling_delay) thermal_zone_device_set_polling(tz, tz->polling_delay); else thermal_zone_device_set_polling(tz, 0); @@ -406,12 +417,25 @@ static void handle_critical_trips(struct thermal_zone_device *tz, static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) { enum thermal_trip_type type; + int trip_temp, hyst = 0; /* Ignore disabled trip points */ if (test_bit(trip, &tz->trips_disabled)) return; + tz->ops->get_trip_temp(tz, trip, &trip_temp); tz->ops->get_trip_type(tz, trip, &type); + if (tz->ops->get_trip_hyst) + tz->ops->get_trip_hyst(tz, trip, &hyst); + + if (tz->last_temperature != THERMAL_TEMP_INVALID) { + if (tz->last_temperature < trip_temp && + tz->temperature >= trip_temp) + thermal_notify_tz_trip_up(tz->id, trip); + if (tz->last_temperature >= trip_temp && + tz->temperature < (trip_temp - hyst)) + thermal_notify_tz_trip_down(tz->id, trip); + } if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) handle_critical_trips(tz, trip, type); @@ -443,6 +467,8 @@ static void update_temperature(struct thermal_zone_device *tz) mutex_unlock(&tz->lock); trace_thermal_temperature(tz); + + thermal_genl_sampling_temp(tz->id, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) @@ -459,11 +485,71 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) thermal_zone_device_init(tz); } +static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, + enum thermal_device_mode mode) +{ + int ret = 0; + + mutex_lock(&tz->lock); + + /* do nothing if mode isn't changing */ + if (mode == tz->mode) { + mutex_unlock(&tz->lock); + + return ret; + } + + if (tz->ops->change_mode) + ret = tz->ops->change_mode(tz, mode); + + if (!ret) + tz->mode = mode; + + mutex_unlock(&tz->lock); + + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + if (mode == THERMAL_DEVICE_ENABLED) + thermal_notify_tz_enable(tz->id); + else + thermal_notify_tz_disable(tz->id); + + return ret; +} + +int thermal_zone_device_enable(struct thermal_zone_device *tz) +{ + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED); +} +EXPORT_SYMBOL_GPL(thermal_zone_device_enable); + +int thermal_zone_device_disable(struct thermal_zone_device *tz) +{ + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED); +} +EXPORT_SYMBOL_GPL(thermal_zone_device_disable); + +int thermal_zone_device_is_enabled(struct thermal_zone_device *tz) +{ + enum thermal_device_mode mode; + + mutex_lock(&tz->lock); + + mode = tz->mode; + + mutex_unlock(&tz->lock); + + return mode == THERMAL_DEVICE_ENABLED; +} + void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { int count; + if (should_stop_polling(tz)) + return; + if (atomic_read(&in_suspend)) return; @@ -617,6 +703,73 @@ void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz, mutex_unlock(&thermal_list_lock); } +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), + void *data) +{ + struct thermal_governor *gov; + int ret = 0; + + mutex_lock(&thermal_governor_lock); + list_for_each_entry(gov, &thermal_governor_list, governor_list) { + ret = cb(gov, data); + if (ret) + break; + } + mutex_unlock(&thermal_governor_lock); + + return ret; +} + +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, + void *), void *data) +{ + struct thermal_cooling_device *cdev; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(cdev, &thermal_cdev_list, node) { + ret = cb(cdev, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), + void *data) +{ + struct thermal_zone_device *tz; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + ret = cb(tz, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + +struct thermal_zone_device *thermal_zone_get_by_id(int id) +{ + struct thermal_zone_device *tz, *match = NULL; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + if (tz->id == id) { + match = tz; + break; + } + } + mutex_unlock(&thermal_list_lock); + + return match; +} + void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, const char *cdev_type, size_t size) { @@ -1340,6 +1493,8 @@ thermal_zone_device_register(const char *type, int trips, int mask, if (atomic_cmpxchg(&tz->need_update, 1, 0)) thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_notify_tz_create(tz->id, tz->type); + return tz; unregister: @@ -1411,6 +1566,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) ida_destroy(&tz->ida); mutex_destroy(&tz->lock); device_unregister(&tz->device); + + thermal_notify_tz_delete(tz->id); } EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); @@ -1456,7 +1613,6 @@ static int thermal_pm_notify(struct notifier_block *nb, unsigned long mode, void *_unused) { struct thermal_zone_device *tz; - enum thermal_device_mode tz_mode; switch (mode) { case PM_HIBERNATION_PREPARE: @@ -1469,11 +1625,7 @@ static int thermal_pm_notify(struct notifier_block *nb, case PM_POST_SUSPEND: atomic_set(&in_suspend, 0); list_for_each_entry(tz, &thermal_tz_list, node) { - tz_mode = THERMAL_DEVICE_ENABLED; - if (tz->ops->get_mode) - tz->ops->get_mode(tz, &tz_mode); - - if (tz_mode == THERMAL_DEVICE_DISABLED) + if (!thermal_zone_device_is_enabled(tz)) continue; thermal_zone_device_init(tz); @@ -1495,6 +1647,10 @@ static int __init thermal_init(void) { int result; + result = thermal_netlink_init(); + if (result) + goto error; + mutex_init(&poweroff_lock); result = thermal_register_governors(); if (result) @@ -1527,4 +1683,4 @@ error: mutex_destroy(&poweroff_lock); return result; } -core_initcall(thermal_init); +postcore_initcall(thermal_init); |