drivers: thermal: Add a snapshot of thermal framework

This is a snapshot of the thermal framework from msm-4.19 to msm-5.4
as of 'commit <14237cefb3f65441677efd9163852ee148017d0c>
(thermal: Fix deadlock in thermal thermal_zone_device_check)'.

Change-Id: I5702ad4f314f2dddfc04244d21605444bd7760a3
Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
This commit is contained in:
Ram Chandrasekar
2019-10-21 17:15:50 -06:00
parent 915d2b2efe
commit 50dc9bdad7
7 changed files with 404 additions and 75 deletions

View File

@@ -4,6 +4,7 @@
* *
* Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Intel Corp
* Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
* 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 cur_state;
unsigned long next_target; 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. * We keep this instance the way it is by default.
* Otherwise, we use the current state of the * 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; next_target = instance->upper;
break; break;
case THERMAL_TREND_DROPPING: case THERMAL_TREND_DROPPING:
if (cur_state <= instance->lower) { case THERMAL_TREND_STABLE:
if (cur_state <= instance->lower ||
instance->target <= instance->lower) {
if (!throttle) if (!throttle)
next_target = THERMAL_NO_TARGET; next_target = THERMAL_NO_TARGET;
} else { } 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) 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_trip_type trip_type;
enum thermal_trend trend; enum thermal_trend trend;
struct thermal_instance *instance; struct thermal_instance *instance;
@@ -123,20 +132,21 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
int old_target; int old_target;
if (trip == THERMAL_TRIPS_NONE) { if (trip == THERMAL_TRIPS_NONE) {
trip_temp = tz->forced_passive; hyst_temp = trip_temp = tz->forced_passive;
trip_type = THERMAL_TRIPS_NONE; trip_type = THERMAL_TRIPS_NONE;
} else { } else {
tz->ops->get_trip_temp(tz, trip, &trip_temp); 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); tz->ops->get_trip_type(tz, trip, &trip_type);
} }
trend = get_tz_trend(tz, trip); 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", dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
trip, trip_type, trip_temp, trend, throttle); 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; continue;
old_target = instance->target; 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); instance->target = get_target_state(instance, trend, throttle);
dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
old_target, (int)instance->target); 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) if (instance->initialized && old_target == instance->target)
continue; continue;
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 */ /* Activate a passive thermal instance */
if (old_target == THERMAL_NO_TARGET && if (old_target == THERMAL_NO_TARGET &&
instance->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); update_passive_instance(tz, trip_type, 1);
/* Deactivate a passive thermal instance */ /* Deactivate a passive thermal instance */
else if (old_target != THERMAL_NO_TARGET && } else if (old_target != THERMAL_NO_TARGET &&
instance->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); update_passive_instance(tz, trip_type, -1);
}
}
instance->initialized = true; instance->initialized = true;
mutex_lock(&instance->cdev->lock); mutex_lock(&instance->cdev->lock);

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -33,6 +34,8 @@ MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
#define THERMAL_MAX_ACTIVE 16
static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_tz_ida);
static DEFINE_IDA(thermal_cdev_ida); static DEFINE_IDA(thermal_cdev_ida);
@@ -49,6 +52,8 @@ static bool power_off_triggered;
static struct thermal_governor *def_governor; static struct thermal_governor *def_governor;
static struct workqueue_struct *thermal_passive_wq;
/* /*
* Governor section: set of functions to handle thermal governors * 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; * - Hot trips will produce a notification to userspace;
* - Critical trip point will cause a system shutdown. * - 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) int delay)
{ {
if (delay > 1000) if (delay > 1000)
mod_delayed_work(system_freezable_power_efficient_wq, mod_delayed_work(queue, &tz->poll_queue,
&tz->poll_queue,
round_jiffies(msecs_to_jiffies(delay))); round_jiffies(msecs_to_jiffies(delay)));
else if (delay) else if (delay)
mod_delayed_work(system_freezable_power_efficient_wq, mod_delayed_work(queue, &tz->poll_queue,
&tz->poll_queue,
msecs_to_jiffies(delay)); msecs_to_jiffies(delay));
else else
cancel_delayed_work_sync(&tz->poll_queue); cancel_delayed_work(&tz->poll_queue);
} }
static void monitor_thermal_zone(struct thermal_zone_device *tz) 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); mutex_lock(&tz->lock);
if (tz->passive) 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) 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 else
thermal_zone_device_set_polling(tz, 0); thermal_zone_device_set_polling(NULL, tz, 0);
mutex_unlock(&tz->lock); 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) if (trip_temp <= 0 || tz->temperature < trip_temp)
return; return;
trace_thermal_zone_trip(tz, trip, trip_type); trace_thermal_zone_trip(tz, trip, trip_type, true);
if (tz->ops->notify) if (tz->ops->notify)
tz->ops->notify(tz, trip, trip_type); 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. * So, start monitoring again.
*/ */
monitor_thermal_zone(tz); 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) static void update_temperature(struct thermal_zone_device *tz)
@@ -442,19 +466,7 @@ static void update_temperature(struct thermal_zone_device *tz)
ret); ret);
return; return;
} }
store_temperature(tz, 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 thermal_zone_device_init(struct thermal_zone_device *tz) 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); 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, void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event) enum thermal_notify_event event)
{ {
int count; int count;
if (atomic_read(&in_suspend)) if (atomic_read(&in_suspend) && tz->polling_delay)
return; return;
if (!tz->ops->get_temp) if (!tz->ops->get_temp)
return; return;
trace_thermal_device_update(tz, event);
update_temperature(tz); update_temperature(tz);
thermal_zone_set_trips(tz); thermal_zone_set_trips(tz);
@@ -710,9 +741,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
if (ret) if (ret)
return ret; return ret;
/* lower default 0, upper default max_state */ /*
lower = lower == THERMAL_NO_LIMIT ? 0 : lower; * If upper or lower has a MACRO to define the mitigation state,
upper = upper == THERMAL_NO_LIMIT ? max_state : upper; * 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) if (lower > upper || upper > max_state)
return -EINVAL; return -EINVAL;
@@ -839,6 +887,7 @@ static void thermal_release(struct device *dev)
{ {
struct thermal_zone_device *tz; struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
struct thermal_instance *instance;
if (!strncmp(dev_name(dev), "thermal_zone", if (!strncmp(dev_name(dev), "thermal_zone",
sizeof("thermal_zone") - 1)) { sizeof("thermal_zone") - 1)) {
@@ -848,6 +897,12 @@ static void thermal_release(struct device *dev)
} else if (!strncmp(dev_name(dev), "cooling_device", } else if (!strncmp(dev_name(dev), "cooling_device",
sizeof("cooling_device") - 1)) { sizeof("cooling_device") - 1)) {
cdev = to_cooling_device(dev); 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); kfree(cdev);
} }
} }
@@ -953,6 +1008,7 @@ __thermal_cooling_device_register(struct device_node *np,
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos = NULL; struct thermal_zone_device *pos = NULL;
int result; int result;
struct thermal_instance *instance;
if (type && strlen(type) >= THERMAL_NAME_LENGTH) if (type && strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@@ -965,9 +1021,16 @@ __thermal_cooling_device_register(struct device_node *np,
if (!cdev) if (!cdev)
return ERR_PTR(-ENOMEM); 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); result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
if (result < 0) { if (result < 0) {
kfree(cdev); kfree(cdev);
kfree(instance);
return ERR_PTR(result); return ERR_PTR(result);
} }
@@ -975,6 +1038,8 @@ __thermal_cooling_device_register(struct device_node *np,
strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
mutex_init(&cdev->lock); mutex_init(&cdev->lock);
INIT_LIST_HEAD(&cdev->thermal_instances); INIT_LIST_HEAD(&cdev->thermal_instances);
instance->target = THERMAL_NO_TARGET;
list_add_tail(&instance->cdev_node, &cdev->thermal_instances);
cdev->np = np; cdev->np = np;
cdev->ops = ops; cdev->ops = ops;
cdev->updated = false; 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 cooling devices for this zone */
bind_tz(tz); 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); thermal_zone_device_reset(tz);
/* Update the new thermal zone and mark it as already updated. */ /* 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); mutex_unlock(&thermal_list_lock);
thermal_zone_device_set_polling(tz, 0); cancel_delayed_work_sync(&tz->poll_queue);
thermal_set_governor(tz, NULL); thermal_set_governor(tz, NULL);
@@ -1576,7 +1641,8 @@ static int thermal_pm_notify(struct notifier_block *nb,
if (tz->ops->get_mode) if (tz->ops->get_mode)
tz->ops->get_mode(tz, &tz_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; continue;
thermal_zone_device_init(tz); thermal_zone_device_init(tz);
@@ -1599,21 +1665,26 @@ static int __init thermal_init(void)
int result; int result;
mutex_init(&poweroff_lock); 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(); result = thermal_register_governors();
if (result) if (result)
goto error; goto destroy_wq;
result = class_register(&thermal_class); result = class_register(&thermal_class);
if (result) if (result)
goto unregister_governors; goto unregister_governors;
result = genetlink_init();
if (result)
goto unregister_class;
result = of_parse_thermal_zones(); result = of_parse_thermal_zones();
if (result) if (result)
goto exit_netlink; goto unregister_class;
result = register_pm_notifier(&thermal_pm_nb); result = register_pm_notifier(&thermal_pm_nb);
if (result) if (result)
@@ -1622,12 +1693,12 @@ static int __init thermal_init(void)
return 0; return 0;
exit_netlink:
genetlink_exit();
unregister_class: unregister_class:
class_unregister(&thermal_class); class_unregister(&thermal_class);
unregister_governors: unregister_governors:
thermal_unregister_governors(); thermal_unregister_governors();
destroy_wq:
destroy_workqueue(thermal_passive_wq);
error: error:
ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_tz_ida);
ida_destroy(&thermal_cdev_ida); ida_destroy(&thermal_cdev_ida);
@@ -1636,4 +1707,33 @@ error:
mutex_destroy(&poweroff_lock); mutex_destroy(&poweroff_lock);
return result; 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);

View File

@@ -4,6 +4,7 @@
* *
* Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Intel Corp
* Author: Durgadoss R <durgadoss.r@intel.com> * Author: Durgadoss R <durgadoss.r@intel.com>
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ */
#ifndef __THERMAL_CORE_H__ #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); bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
const struct thermal_trip * const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *); 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 #else
static inline int of_parse_thermal_zones(void) { return 0; } static inline int of_parse_thermal_zones(void) { return 0; }
static inline void of_thermal_destroy_zones(void) { } static inline void of_thermal_destroy_zones(void) { }
@@ -114,6 +121,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz)
{ {
return NULL; 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
#endif /* __THERMAL_CORE_H__ */ #endif /* __THERMAL_CORE_H__ */

View File

@@ -8,6 +8,7 @@
* Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #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) if (!ret && *temp < crit_temp)
*temp = tz->emul_temperature; *temp = tz->emul_temperature;
} }
trace_thermal_query_temp(tz, *temp);
mutex_unlock(&tz->lock); mutex_unlock(&tz->lock);
exit: exit:
return ret; return ret;
@@ -140,10 +141,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
high = trip_temp; 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_low_trip = low;
tz->prev_high_trip = high; 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); ret = tz->ops->set_trips(tz, low, high);
if (ret) if (ret)
dev_err(&tz->device, "Failed to set trips: %d\n", ret); dev_err(&tz->device, "Failed to set trips: %d\n", ret);
trace_thermal_set_trip(tz);
exit: exit:
mutex_unlock(&tz->lock); mutex_unlock(&tz->lock);
@@ -177,6 +175,11 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
/* Make sure cdev enters the deepest cooling state */ /* Make sure cdev enters the deepest cooling state */
list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
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", dev_dbg(&cdev->device, "zone%d->target=%lu\n",
instance->tz->id, instance->target); instance->tz->id, instance->target);
if (instance->target == THERMAL_NO_TARGET) if (instance->target == THERMAL_NO_TARGET)

View File

@@ -8,6 +8,7 @@
* Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -63,6 +64,28 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
: "disabled"); : "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 static ssize_t
mode_store(struct device *dev, struct device_attribute *attr, mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) 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)) if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); result = thermal_zone_device_clear(tz);
else else
result = -EINVAL; result = -EINVAL;
@@ -348,6 +371,24 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr,
return count; 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) \ #define create_s32_tzp_attr(name) \
static ssize_t \ static ssize_t \
name##_show(struct device *dev, struct device_attribute *devattr, \ 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_RW(policy);
static DEVICE_ATTR_RO(available_policies); static DEVICE_ATTR_RO(available_policies);
static DEVICE_ATTR_RW(sustainable_power); 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 */ /* These thermal zone device attributes are created based on conditions */
static DEVICE_ATTR_RW(mode); static DEVICE_ATTR_RW(mode);
@@ -414,6 +457,8 @@ static struct attribute *thermal_zone_dev_attrs[] = {
&dev_attr_policy.attr, &dev_attr_policy.attr,
&dev_attr_available_policies.attr, &dev_attr_available_policies.attr,
&dev_attr_sustainable_power.attr, &dev_attr_sustainable_power.attr,
&dev_attr_passive_delay.attr,
&dev_attr_polling_delay.attr,
&dev_attr_k_po.attr, &dev_attr_k_po.attr,
&dev_attr_k_pu.attr, &dev_attr_k_pu.attr,
&dev_attr_k_i.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); struct thermal_cooling_device *cdev = to_cooling_device(dev);
unsigned long state; unsigned long state;
int result; struct thermal_instance *instance = NULL;
if (sscanf(buf, "%ld\n", &state) != 1) if (sscanf(buf, "%ld\n", &state) != 1)
return -EINVAL; return -EINVAL;
@@ -713,13 +758,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
mutex_lock(&cdev->lock); 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); cdev->updated = false;
if (!result)
thermal_cooling_device_stats_update(cdev, state);
mutex_unlock(&cdev->lock); mutex_unlock(&cdev->lock);
return result ? result : count; thermal_cdev_update(cdev);
return count;
} }
static struct device_attribute 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; struct cooling_dev_stats *stats = cdev->stats;
if (!stats)
return;
spin_lock(&stats->lock); spin_lock(&stats->lock);
if (stats->state == new_state) 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; struct cooling_dev_stats *stats = cdev->stats;
int ret; int ret;
if (!stats)
return -ENODEV;
spin_lock(&stats->lock); spin_lock(&stats->lock);
ret = sprintf(buf, "%u\n", stats->total_trans); ret = sprintf(buf, "%u\n", stats->total_trans);
spin_unlock(&stats->lock); spin_unlock(&stats->lock);
@@ -807,6 +860,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
ssize_t len = 0; ssize_t len = 0;
int i; int i;
if (!stats)
return -ENODEV;
spin_lock(&stats->lock); spin_lock(&stats->lock);
update_time_in_state(stats); 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 thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats; 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); spin_lock(&stats->lock);
stats->total_trans = 0; stats->total_trans = 0;
@@ -850,6 +910,9 @@ static ssize_t trans_table_show(struct device *dev,
ssize_t len = 0; ssize_t len = 0;
int i, j; int i, j;
if (!stats)
return -ENODEV;
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : "); len += snprintf(buf + len, PAGE_SIZE - len, " : ");
for (i = 0; i < stats->max_states; i++) { for (i = 0; i < stats->max_states; i++) {

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/ */
#ifndef __THERMAL_H__ #ifndef __THERMAL_H__
@@ -26,6 +27,9 @@
/* No upper/lower limit requirement */ /* No upper/lower limit requirement */
#define THERMAL_NO_LIMIT ((u32)~0) #define THERMAL_NO_LIMIT ((u32)~0)
/* upper limit requirement */
#define THERMAL_MAX_LIMIT (THERMAL_NO_LIMIT - 1)
/* Default weight of a bound cooling device */ /* Default weight of a bound cooling device */
#define THERMAL_WEIGHT_DEFAULT 0 #define THERMAL_WEIGHT_DEFAULT 0
@@ -440,6 +444,8 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *); struct thermal_cooling_device *);
void thermal_zone_device_update(struct thermal_zone_device *, void thermal_zone_device_update(struct thermal_zone_device *,
enum thermal_notify_event); 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 *); void thermal_zone_set_trips(struct thermal_zone_device *);
struct thermal_cooling_device *thermal_cooling_device_register(const char *, 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, static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event) 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 void thermal_zone_set_trips(struct thermal_zone_device *tz)
{ } { }
static inline struct thermal_cooling_device * static inline struct thermal_cooling_device *

View File

@@ -21,6 +21,29 @@ TRACE_DEFINE_ENUM(THERMAL_TRIP_ACTIVE);
{ THERMAL_TRIP_PASSIVE, "PASSIVE"}, \ { THERMAL_TRIP_PASSIVE, "PASSIVE"}, \
{ THERMAL_TRIP_ACTIVE, "ACTIVE"}) { 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, TRACE_EVENT(thermal_temperature,
TP_PROTO(struct thermal_zone_device *tz), TP_PROTO(struct thermal_zone_device *tz),
@@ -68,15 +91,16 @@ TRACE_EVENT(cdev_update,
TRACE_EVENT(thermal_zone_trip, TRACE_EVENT(thermal_zone_trip,
TP_PROTO(struct thermal_zone_device *tz, int 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( TP_STRUCT__entry(
__string(thermal_zone, tz->type) __string(thermal_zone, tz->type)
__field(int, id) __field(int, id)
__field(int, trip) __field(int, trip)
__field(enum thermal_trip_type, trip_type) __field(enum thermal_trip_type, trip_type)
__field(bool, is_trip)
), ),
TP_fast_assign( TP_fast_assign(
@@ -84,13 +108,85 @@ TRACE_EVENT(thermal_zone_trip,
__entry->id = tz->id; __entry->id = tz->id;
__entry->trip = trip; __entry->trip = trip;
__entry->trip_type = trip_type; __entry->trip_type = trip_type;
__entry->is_trip = is_trip;
), ),
TP_printk("thermal_zone=%s id=%d trip=%d trip_type=%s", TP_printk("thermal_zone=%s id=%d %s=%d trip_type=%s",
__get_str(thermal_zone), __entry->id, __entry->trip, __get_str(thermal_zone), __entry->id,
(__entry->is_trip) ? "trip" : "hyst",
__entry->trip,
show_tzt_type(__entry->trip_type)) 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 #ifdef CONFIG_CPU_THERMAL
TRACE_EVENT(thermal_power_cpu_get_power, TRACE_EVENT(thermal_power_cpu_get_power,
TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load, TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,