diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index 6e051cbd824f..3ce7ec3a4bbb 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R + * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -41,6 +42,12 @@ static unsigned long get_target_state(struct thermal_instance *instance, unsigned long cur_state; unsigned long next_target; + /* + * If the throttle condition is not reached and there is no + * previous mitigaiton request, then there is nothing to compute. + */ + if (!throttle && instance->target == THERMAL_NO_TARGET) + return THERMAL_NO_TARGET; /* * We keep this instance the way it is by default. * Otherwise, we use the current state of the @@ -77,7 +84,9 @@ static unsigned long get_target_state(struct thermal_instance *instance, next_target = instance->upper; break; case THERMAL_TREND_DROPPING: - if (cur_state <= instance->lower) { + case THERMAL_TREND_STABLE: + if (cur_state <= instance->lower || + instance->target <= instance->lower) { if (!throttle) next_target = THERMAL_NO_TARGET; } else { @@ -115,7 +124,7 @@ static void update_passive_instance(struct thermal_zone_device *tz, static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { - int trip_temp; + int trip_temp, hyst_temp; enum thermal_trip_type trip_type; enum thermal_trend trend; struct thermal_instance *instance; @@ -123,20 +132,21 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) int old_target; if (trip == THERMAL_TRIPS_NONE) { - trip_temp = tz->forced_passive; + hyst_temp = trip_temp = tz->forced_passive; trip_type = THERMAL_TRIPS_NONE; } else { tz->ops->get_trip_temp(tz, trip, &trip_temp); + if (tz->ops->get_trip_hyst) { + tz->ops->get_trip_hyst(tz, trip, &hyst_temp); + hyst_temp = trip_temp - hyst_temp; + } else { + hyst_temp = trip_temp; + } tz->ops->get_trip_type(tz, trip, &trip_type); } trend = get_tz_trend(tz, trip); - if (tz->temperature >= trip_temp) { - throttle = true; - trace_thermal_zone_trip(tz, trip, trip_type); - } - dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip, trip_type, trip_temp, trend, throttle); @@ -147,6 +157,20 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) continue; old_target = instance->target; + /* + * Step wise has to lower the mitigation only if the + * temperature goes below the hysteresis temperature. + * Atleast, it has to hold on to mitigation device lower + * limit if the temperature is above the hysteresis + * temperature. + */ + if (tz->temperature >= trip_temp || + (tz->temperature > hyst_temp && + old_target != THERMAL_NO_TARGET)) + throttle = true; + else + throttle = false; + instance->target = get_target_state(instance, trend, throttle); dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); @@ -154,14 +178,27 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) if (instance->initialized && old_target == instance->target) continue; - /* Activate a passive thermal instance */ - if (old_target == THERMAL_NO_TARGET && - instance->target != THERMAL_NO_TARGET) - update_passive_instance(tz, trip_type, 1); - /* Deactivate a passive thermal instance */ - else if (old_target != THERMAL_NO_TARGET && - instance->target == THERMAL_NO_TARGET) - update_passive_instance(tz, trip_type, -1); + if (!instance->initialized) { + if (instance->target != THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + true); + update_passive_instance(tz, trip_type, 1); + } + } else { + /* Activate a passive thermal instance */ + if (old_target == THERMAL_NO_TARGET && + instance->target != THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + true); + update_passive_instance(tz, trip_type, 1); + /* Deactivate a passive thermal instance */ + } else if (old_target != THERMAL_NO_TARGET && + instance->target == THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + false); + update_passive_instance(tz, trip_type, -1); + } + } instance->initialized = true; mutex_lock(&instance->cdev->lock); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index d4481cc8958f..c9a602c3886b 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -5,6 +5,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui * Copyright (C) 2008 Sujith Thomas + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -33,6 +34,8 @@ MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL v2"); +#define THERMAL_MAX_ACTIVE 16 + static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); @@ -49,6 +52,8 @@ static bool power_off_triggered; static struct thermal_governor *def_governor; +static struct workqueue_struct *thermal_passive_wq; + /* * Governor section: set of functions to handle thermal governors * @@ -292,19 +297,18 @@ static int __init thermal_register_governors(void) * - Hot trips will produce a notification to userspace; * - Critical trip point will cause a system shutdown. */ -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, +static void thermal_zone_device_set_polling(struct workqueue_struct *queue, + struct thermal_zone_device *tz, int delay) { if (delay > 1000) - mod_delayed_work(system_freezable_power_efficient_wq, - &tz->poll_queue, + mod_delayed_work(queue, &tz->poll_queue, round_jiffies(msecs_to_jiffies(delay))); else if (delay) - mod_delayed_work(system_freezable_power_efficient_wq, - &tz->poll_queue, + mod_delayed_work(queue, &tz->poll_queue, msecs_to_jiffies(delay)); else - cancel_delayed_work_sync(&tz->poll_queue); + cancel_delayed_work(&tz->poll_queue); } static void monitor_thermal_zone(struct thermal_zone_device *tz) @@ -312,11 +316,14 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz) mutex_lock(&tz->lock); if (tz->passive) - thermal_zone_device_set_polling(tz, tz->passive_delay); + thermal_zone_device_set_polling(thermal_passive_wq, + tz, tz->passive_delay); else if (tz->polling_delay) - thermal_zone_device_set_polling(tz, tz->polling_delay); + thermal_zone_device_set_polling( + system_freezable_power_efficient_wq, + tz, tz->polling_delay); else - thermal_zone_device_set_polling(tz, 0); + thermal_zone_device_set_polling(NULL, tz, 0); mutex_unlock(&tz->lock); } @@ -386,7 +393,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz, if (trip_temp <= 0 || tz->temperature < trip_temp) return; - trace_thermal_zone_trip(tz, trip, trip_type); + trace_thermal_zone_trip(tz, trip, trip_type, true); if (tz->ops->notify) tz->ops->notify(tz, trip, trip_type); @@ -428,6 +435,23 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) * So, start monitoring again. */ monitor_thermal_zone(tz); + trace_thermal_handle_trip(tz, trip); +} + +static void store_temperature(struct thermal_zone_device *tz, int temp) +{ + mutex_lock(&tz->lock); + tz->last_temperature = tz->temperature; + tz->temperature = temp; + mutex_unlock(&tz->lock); + + trace_thermal_temperature(tz); + if (tz->last_temperature == THERMAL_TEMP_INVALID) + dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", + tz->temperature); + else + dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", + tz->last_temperature, tz->temperature); } static void update_temperature(struct thermal_zone_device *tz) @@ -442,19 +466,7 @@ static void update_temperature(struct thermal_zone_device *tz) ret); return; } - - mutex_lock(&tz->lock); - tz->last_temperature = tz->temperature; - tz->temperature = temp; - mutex_unlock(&tz->lock); - - trace_thermal_temperature(tz); - if (tz->last_temperature == THERMAL_TEMP_INVALID) - dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", - tz->temperature); - else - dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", - tz->last_temperature, tz->temperature); + store_temperature(tz, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) @@ -471,17 +483,36 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) thermal_zone_device_init(tz); } +void thermal_zone_device_update_temp(struct thermal_zone_device *tz, + enum thermal_notify_event event, int temp) +{ + int count; + + if (atomic_read(&in_suspend) && tz->polling_delay) + return; + trace_thermal_device_update(tz, event); + store_temperature(tz, temp); + + thermal_zone_set_trips(tz); + + tz->notify_event = event; + + for (count = 0; count < tz->trips; count++) + handle_thermal_trip(tz, count); +} +EXPORT_SYMBOL(thermal_zone_device_update_temp); + void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { int count; - if (atomic_read(&in_suspend)) + if (atomic_read(&in_suspend) && tz->polling_delay) return; - if (!tz->ops->get_temp) return; + trace_thermal_device_update(tz, event); update_temperature(tz); thermal_zone_set_trips(tz); @@ -710,9 +741,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, if (ret) return ret; - /* lower default 0, upper default max_state */ - lower = lower == THERMAL_NO_LIMIT ? 0 : lower; - upper = upper == THERMAL_NO_LIMIT ? max_state : upper; + /* + * If upper or lower has a MACRO to define the mitigation state, + * based on the MACRO determine the default state to use or the + * offset from the max_state. + */ + if (upper >= (THERMAL_MAX_LIMIT - max_state)) { + /* upper default max_state */ + if (upper == THERMAL_NO_LIMIT) + upper = max_state; + else + upper = max_state - (THERMAL_MAX_LIMIT - upper); + } + + if (lower >= (THERMAL_MAX_LIMIT - max_state)) { + /* lower default 0 */ + if (lower == THERMAL_NO_LIMIT) + lower = 0; + else + lower = max_state - (THERMAL_MAX_LIMIT - lower); + } if (lower > upper || upper > max_state) return -EINVAL; @@ -839,6 +887,7 @@ static void thermal_release(struct device *dev) { struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; + struct thermal_instance *instance; if (!strncmp(dev_name(dev), "thermal_zone", sizeof("thermal_zone") - 1)) { @@ -848,6 +897,12 @@ static void thermal_release(struct device *dev) } else if (!strncmp(dev_name(dev), "cooling_device", sizeof("cooling_device") - 1)) { cdev = to_cooling_device(dev); + if (list_is_singular(&cdev->thermal_instances)) { + instance = list_first_entry(&cdev->thermal_instances, + typeof(*instance), cdev_node); + list_del(&instance->cdev_node); + kfree(instance); + } kfree(cdev); } } @@ -953,6 +1008,7 @@ __thermal_cooling_device_register(struct device_node *np, struct thermal_cooling_device *cdev; struct thermal_zone_device *pos = NULL; int result; + struct thermal_instance *instance; if (type && strlen(type) >= THERMAL_NAME_LENGTH) return ERR_PTR(-EINVAL); @@ -965,9 +1021,16 @@ __thermal_cooling_device_register(struct device_node *np, if (!cdev) return ERR_PTR(-ENOMEM); + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) { + kfree(cdev); + return ERR_PTR(-ENOMEM); + } + result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); if (result < 0) { kfree(cdev); + kfree(instance); return ERR_PTR(result); } @@ -975,6 +1038,8 @@ __thermal_cooling_device_register(struct device_node *np, strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); + instance->target = THERMAL_NO_TARGET; + list_add_tail(&instance->cdev_node, &cdev->thermal_instances); cdev->np = np; cdev->ops = ops; cdev->updated = false; @@ -1345,7 +1410,7 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* Bind cooling devices for this zone */ bind_tz(tz); - INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); + INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check); thermal_zone_device_reset(tz); /* Update the new thermal zone and mark it as already updated. */ @@ -1414,7 +1479,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) mutex_unlock(&thermal_list_lock); - thermal_zone_device_set_polling(tz, 0); + cancel_delayed_work_sync(&tz->poll_queue); thermal_set_governor(tz, NULL); @@ -1576,7 +1641,8 @@ static int thermal_pm_notify(struct notifier_block *nb, if (tz->ops->get_mode) tz->ops->get_mode(tz, &tz_mode); - if (tz_mode == THERMAL_DEVICE_DISABLED) + if (tz_mode == THERMAL_DEVICE_DISABLED || + tz->polling_delay == 0) continue; thermal_zone_device_init(tz); @@ -1599,21 +1665,26 @@ static int __init thermal_init(void) int result; mutex_init(&poweroff_lock); + thermal_passive_wq = alloc_workqueue("thermal_passive_wq", + WQ_HIGHPRI | WQ_UNBOUND + | WQ_FREEZABLE, + THERMAL_MAX_ACTIVE); + if (!thermal_passive_wq) { + result = -ENOMEM; + goto error; + } + result = thermal_register_governors(); if (result) - goto error; + goto destroy_wq; result = class_register(&thermal_class); if (result) goto unregister_governors; - result = genetlink_init(); - if (result) - goto unregister_class; - result = of_parse_thermal_zones(); if (result) - goto exit_netlink; + goto unregister_class; result = register_pm_notifier(&thermal_pm_nb); if (result) @@ -1622,12 +1693,12 @@ static int __init thermal_init(void) return 0; -exit_netlink: - genetlink_exit(); unregister_class: class_unregister(&thermal_class); unregister_governors: thermal_unregister_governors(); +destroy_wq: + destroy_workqueue(thermal_passive_wq); error: ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_cdev_ida); @@ -1636,4 +1707,33 @@ error: mutex_destroy(&poweroff_lock); return result; } -fs_initcall(thermal_init); + +static void thermal_exit(void) +{ + unregister_pm_notifier(&thermal_pm_nb); + of_thermal_destroy_zones(); + destroy_workqueue(thermal_passive_wq); + genetlink_exit(); + class_unregister(&thermal_class); + thermal_unregister_governors(); + ida_destroy(&thermal_tz_ida); + ida_destroy(&thermal_cdev_ida); + mutex_destroy(&thermal_list_lock); + mutex_destroy(&thermal_governor_lock); +} + +static int __init thermal_netlink_init(void) +{ + int ret = 0; + + ret = genetlink_init(); + if (!ret) + goto exit_netlink; + + thermal_exit(); +exit_netlink: + return ret; +} + +subsys_initcall(thermal_init); +fs_initcall(thermal_netlink_init); diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 207b0cda70da..24a7f90deedf 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Author: Durgadoss R + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __THERMAL_CORE_H__ @@ -97,6 +98,12 @@ int of_thermal_get_ntrips(struct thermal_zone_device *); bool of_thermal_is_trip_valid(struct thermal_zone_device *, int); const struct thermal_trip * of_thermal_get_trip_points(struct thermal_zone_device *); +int of_thermal_aggregate_trip(struct thermal_zone_device *tz, + enum thermal_trip_type type, + int *low, int *high); +void of_thermal_handle_trip(struct thermal_zone_device *tz); +void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, + int trip_temp); #else static inline int of_parse_thermal_zones(void) { return 0; } static inline void of_thermal_destroy_zones(void) { } @@ -114,6 +121,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz) { return NULL; } +static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz, + enum thermal_trip_type type, + int *low, int *high) +{ + return -ENODEV; +} +static inline +void of_thermal_handle_trip(struct thermal_zone_device *tz) +{ } +static inline +void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, + int trip_temp) +{ } #endif #endif /* __THERMAL_CORE_H__ */ diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index 2ba756af76b7..88581032b499 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui * Copyright (C) 2008 Sujith Thomas + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -106,7 +107,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) if (!ret && *temp < crit_temp) *temp = tz->emul_temperature; } - + trace_thermal_query_temp(tz, *temp); mutex_unlock(&tz->lock); exit: return ret; @@ -140,10 +141,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) high = trip_temp; } - /* No need to change trip points */ - if (tz->prev_low_trip == low && tz->prev_high_trip == high) - goto exit; - tz->prev_low_trip = low; tz->prev_high_trip = high; @@ -157,6 +154,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) ret = tz->ops->set_trips(tz, low, high); if (ret) dev_err(&tz->device, "Failed to set trips: %d\n", ret); + trace_thermal_set_trip(tz); exit: mutex_unlock(&tz->lock); @@ -177,8 +175,13 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) /* Make sure cdev enters the deepest cooling state */ list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { - dev_dbg(&cdev->device, "zone%d->target=%lu\n", - instance->tz->id, instance->target); + if (list_is_first(&instance->cdev_node, + &cdev->thermal_instances)) + dev_dbg(&cdev->device, "userspace->target=%lu\n", + instance->target); + else + dev_dbg(&cdev->device, "zone%d->target=%lu\n", + instance->tz->id, instance->target); if (instance->target == THERMAL_NO_TARGET) continue; if (instance->target > target) diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index aa99edb4dff7..c846008540ea 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui * Copyright (C) 2008 Sujith Thomas + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -63,6 +64,28 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf) : "disabled"); } +static int thermal_zone_device_clear(struct thermal_zone_device *tz) +{ + struct thermal_instance *pos; + int ret = 0; + + ret = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); + mutex_lock(&tz->lock); + tz->temperature = THERMAL_TEMP_INVALID; + tz->passive = 0; + list_for_each_entry(pos, &tz->thermal_instances, tz_node) { + pos->initialized = false; + pos->target = THERMAL_NO_TARGET; + mutex_lock(&pos->cdev->lock); + pos->cdev->updated = false; /* cdev needs update */ + mutex_unlock(&pos->cdev->lock); + thermal_cdev_update(pos->cdev); + } + mutex_unlock(&tz->lock); + + return ret; +} + static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -76,7 +99,7 @@ mode_store(struct device *dev, struct device_attribute *attr, if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) - result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); + result = thermal_zone_device_clear(tz); else result = -EINVAL; @@ -348,6 +371,24 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr, return count; } +static ssize_t +polling_delay_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", tz->polling_delay); +} + +static ssize_t +passive_delay_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", tz->passive_delay); +} + #define create_s32_tzp_attr(name) \ static ssize_t \ name##_show(struct device *dev, struct device_attribute *devattr, \ @@ -399,6 +440,8 @@ static DEVICE_ATTR_RO(temp); static DEVICE_ATTR_RW(policy); static DEVICE_ATTR_RO(available_policies); static DEVICE_ATTR_RW(sustainable_power); +static DEVICE_ATTR_RO(passive_delay); +static DEVICE_ATTR_RO(polling_delay); /* These thermal zone device attributes are created based on conditions */ static DEVICE_ATTR_RW(mode); @@ -414,6 +457,8 @@ static struct attribute *thermal_zone_dev_attrs[] = { &dev_attr_policy.attr, &dev_attr_available_policies.attr, &dev_attr_sustainable_power.attr, + &dev_attr_passive_delay.attr, + &dev_attr_polling_delay.attr, &dev_attr_k_po.attr, &dev_attr_k_pu.attr, &dev_attr_k_i.attr, @@ -704,7 +749,7 @@ cur_state_store(struct device *dev, struct device_attribute *attr, { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; - int result; + struct thermal_instance *instance = NULL; if (sscanf(buf, "%ld\n", &state) != 1) return -EINVAL; @@ -713,13 +758,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&cdev->lock); + instance = list_first_entry(&cdev->thermal_instances, + typeof(*instance), cdev_node); + instance->target = state; - result = cdev->ops->set_cur_state(cdev, state); - if (!result) - thermal_cooling_device_stats_update(cdev, state); - + cdev->updated = false; mutex_unlock(&cdev->lock); - return result ? result : count; + thermal_cdev_update(cdev); + + return count; } static struct device_attribute @@ -770,6 +817,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, { struct cooling_dev_stats *stats = cdev->stats; + if (!stats) + return; + spin_lock(&stats->lock); if (stats->state == new_state) @@ -791,6 +841,9 @@ static ssize_t total_trans_show(struct device *dev, struct cooling_dev_stats *stats = cdev->stats; int ret; + if (!stats) + return -ENODEV; + spin_lock(&stats->lock); ret = sprintf(buf, "%u\n", stats->total_trans); spin_unlock(&stats->lock); @@ -807,6 +860,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ssize_t len = 0; int i; + if (!stats) + return -ENODEV; + spin_lock(&stats->lock); update_time_in_state(stats); @@ -825,8 +881,12 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; - int i, states = stats->max_states; + int i, states; + if (!stats) + return -ENODEV; + + states = stats->max_states; spin_lock(&stats->lock); stats->total_trans = 0; @@ -850,6 +910,9 @@ static ssize_t trans_table_show(struct device *dev, ssize_t len = 0; int i, j; + if (!stats) + return -ENODEV; + len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->max_states; i++) { diff --git a/include/linux/thermal.h b/include/linux/thermal.h index e45659c75920..e813ee1f2389 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -5,6 +5,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui * Copyright (C) 2008 Sujith Thomas + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __THERMAL_H__ @@ -26,6 +27,9 @@ /* No upper/lower limit requirement */ #define THERMAL_NO_LIMIT ((u32)~0) +/* upper limit requirement */ +#define THERMAL_MAX_LIMIT (THERMAL_NO_LIMIT - 1) + /* Default weight of a bound cooling device */ #define THERMAL_WEIGHT_DEFAULT 0 @@ -440,6 +444,8 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, struct thermal_cooling_device *); void thermal_zone_device_update(struct thermal_zone_device *, enum thermal_notify_event); +void thermal_zone_device_update_temp(struct thermal_zone_device *tz, + enum thermal_notify_event event, int temp); void thermal_zone_set_trips(struct thermal_zone_device *); struct thermal_cooling_device *thermal_cooling_device_register(const char *, @@ -498,6 +504,10 @@ static inline int thermal_zone_unbind_cooling_device( static inline void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { } +static inline void thermal_zone_device_update_temp( + struct thermal_zone_device *tz, enum thermal_notify_event event, + int temp) +{ } static inline void thermal_zone_set_trips(struct thermal_zone_device *tz) { } static inline struct thermal_cooling_device * diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h index 135e5421f003..c60a0bddde59 100644 --- a/include/trace/events/thermal.h +++ b/include/trace/events/thermal.h @@ -21,6 +21,29 @@ TRACE_DEFINE_ENUM(THERMAL_TRIP_ACTIVE); { THERMAL_TRIP_PASSIVE, "PASSIVE"}, \ { THERMAL_TRIP_ACTIVE, "ACTIVE"}) +TRACE_EVENT(thermal_query_temp, + + TP_PROTO(struct thermal_zone_device *tz, int temp), + + TP_ARGS(tz, temp), + + TP_STRUCT__entry( + __string(thermal_zone, tz->type) + __field(int, id) + __field(int, temp) + ), + + TP_fast_assign( + __assign_str(thermal_zone, tz->type); + __entry->id = tz->id; + __entry->temp = temp; + ), + + TP_printk("thermal_zone=%s id=%d temp=%d", + __get_str(thermal_zone), __entry->id, + __entry->temp) +); + TRACE_EVENT(thermal_temperature, TP_PROTO(struct thermal_zone_device *tz), @@ -68,15 +91,16 @@ TRACE_EVENT(cdev_update, TRACE_EVENT(thermal_zone_trip, TP_PROTO(struct thermal_zone_device *tz, int trip, - enum thermal_trip_type trip_type), + enum thermal_trip_type trip_type, bool is_trip), - TP_ARGS(tz, trip, trip_type), + TP_ARGS(tz, trip, trip_type, is_trip), TP_STRUCT__entry( __string(thermal_zone, tz->type) __field(int, id) __field(int, trip) __field(enum thermal_trip_type, trip_type) + __field(bool, is_trip) ), TP_fast_assign( @@ -84,13 +108,85 @@ TRACE_EVENT(thermal_zone_trip, __entry->id = tz->id; __entry->trip = trip; __entry->trip_type = trip_type; + __entry->is_trip = is_trip; ), - TP_printk("thermal_zone=%s id=%d trip=%d trip_type=%s", - __get_str(thermal_zone), __entry->id, __entry->trip, + TP_printk("thermal_zone=%s id=%d %s=%d trip_type=%s", + __get_str(thermal_zone), __entry->id, + (__entry->is_trip) ? "trip" : "hyst", + __entry->trip, show_tzt_type(__entry->trip_type)) ); +TRACE_EVENT(thermal_handle_trip, + + TP_PROTO(struct thermal_zone_device *tz, int trip), + + TP_ARGS(tz, trip), + + TP_STRUCT__entry( + __string(thermal_zone, tz->type) + __field(int, id) + __field(int, trip) + ), + + TP_fast_assign( + __assign_str(thermal_zone, tz->type); + __entry->id = tz->id; + __entry->trip = trip; + ), + + TP_printk("thermal_zone=%s id=%d handle trip=%d", + __get_str(thermal_zone), __entry->id, __entry->trip) +); + +TRACE_EVENT(thermal_device_update, + + TP_PROTO(struct thermal_zone_device *tz, int event), + + TP_ARGS(tz, event), + + TP_STRUCT__entry( + __string(thermal_zone, tz->type) + __field(int, id) + __field(int, event) + ), + + TP_fast_assign( + __assign_str(thermal_zone, tz->type); + __entry->id = tz->id; + __entry->event = event; + ), + + TP_printk("thermal_zone=%s id=%d received event:%d", + __get_str(thermal_zone), __entry->id, __entry->event) +); + +TRACE_EVENT(thermal_set_trip, + + TP_PROTO(struct thermal_zone_device *tz), + + TP_ARGS(tz), + + TP_STRUCT__entry( + __string(thermal_zone, tz->type) + __field(int, id) + __field(int, low) + __field(int, high) + ), + + TP_fast_assign( + __assign_str(thermal_zone, tz->type); + __entry->id = tz->id; + __entry->low = tz->prev_low_trip; + __entry->high = tz->prev_high_trip; + ), + + TP_printk("thermal_zone=%s id=%d low trip=%d high trip=%d", + __get_str(thermal_zone), __entry->id, __entry->low, + __entry->high) +); + #ifdef CONFIG_CPU_THERMAL TRACE_EVENT(thermal_power_cpu_get_power, TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,