Merge back thermal control material for v6.11.

This commit is contained in:
Rafael J. Wysocki 2024-06-27 21:22:15 +02:00
commit efde8bfdc1
7 changed files with 112 additions and 80 deletions

View File

@ -57,24 +57,16 @@ static void bang_bang_control(struct thermal_zone_device *tz,
if (instance->trip != trip) if (instance->trip != trip)
continue; continue;
if (instance->target == THERMAL_NO_TARGET) if (instance->target != 0 && instance->target != 1 &&
instance->target = 0; instance->target != THERMAL_NO_TARGET)
if (instance->target != 0 && instance->target != 1) {
pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n",
instance->target, instance->name); instance->target, instance->name);
instance->target = 1;
}
/* /*
* Enable the fan when the trip is crossed on the way up and * Enable the fan when the trip is crossed on the way up and
* disable it when the trip is crossed on the way down. * disable it when the trip is crossed on the way down.
*/ */
if (instance->target == 0 && crossed_up) instance->target = crossed_up;
instance->target = 1;
else if (instance->target == 1 && !crossed_up)
instance->target = 0;
dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);

View File

@ -463,6 +463,9 @@ static void thermal_governor_trip_crossed(struct thermal_governor *governor,
const struct thermal_trip *trip, const struct thermal_trip *trip,
bool crossed_up) bool crossed_up)
{ {
if (trip->type == THERMAL_TRIP_HOT || trip->type == THERMAL_TRIP_CRITICAL)
return;
if (governor->trip_crossed) if (governor->trip_crossed)
governor->trip_crossed(tz, trip, crossed_up); governor->trip_crossed(tz, trip, crossed_up);
} }
@ -513,13 +516,13 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz,
if (tz->temperature == THERMAL_TEMP_INVALID) if (tz->temperature == THERMAL_TEMP_INVALID)
return; return;
__thermal_zone_set_trips(tz);
tz->notify_event = event; tz->notify_event = event;
for_each_trip_desc(tz, td) for_each_trip_desc(tz, td)
handle_thermal_trip(tz, td, &way_up_list, &way_down_list); handle_thermal_trip(tz, td, &way_up_list, &way_down_list);
thermal_zone_set_trips(tz);
list_sort(&way_up_list, &way_up_list, thermal_trip_notify_cmp); list_sort(&way_up_list, &way_up_list, thermal_trip_notify_cmp);
list_for_each_entry(td, &way_up_list, notify_list_node) list_for_each_entry(td, &way_up_list, notify_list_node)
thermal_trip_crossed(tz, &td->trip, governor, true); thermal_trip_crossed(tz, &td->trip, governor, true);
@ -1649,6 +1652,7 @@ static void thermal_zone_device_resume(struct work_struct *work)
tz->suspended = false; tz->suspended = false;
thermal_debug_tz_resume(tz);
thermal_zone_device_init(tz); thermal_zone_device_init(tz);
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);

View File

@ -244,7 +244,9 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
#define trip_to_trip_desc(__trip) \ #define trip_to_trip_desc(__trip) \
container_of(__trip, struct thermal_trip_desc, trip) container_of(__trip, struct thermal_trip_desc, trip)
void __thermal_zone_set_trips(struct thermal_zone_device *tz); const char *thermal_trip_type_name(enum thermal_trip_type trip_type);
void thermal_zone_set_trips(struct thermal_zone_device *tz);
int thermal_zone_trip_id(const struct thermal_zone_device *tz, int thermal_zone_trip_id(const struct thermal_zone_device *tz,
const struct thermal_trip *trip); const struct thermal_trip *trip);
void thermal_zone_trip_updated(struct thermal_zone_device *tz, void thermal_zone_trip_updated(struct thermal_zone_device *tz,

View File

@ -94,7 +94,6 @@ struct cdev_record {
* @trip_temp: trip temperature at mitigation start * @trip_temp: trip temperature at mitigation start
* @trip_hyst: trip hysteresis at mitigation start * @trip_hyst: trip hysteresis at mitigation start
* @count: the number of times the zone temperature was above the trip point * @count: the number of times the zone temperature was above the trip point
* @max: maximum recorded temperature above the trip point
* @min: minimum recorded temperature above the trip point * @min: minimum recorded temperature above the trip point
* @avg: average temperature above the trip point * @avg: average temperature above the trip point
*/ */
@ -104,7 +103,6 @@ struct trip_stats {
int trip_temp; int trip_temp;
int trip_hyst; int trip_hyst;
int count; int count;
int max;
int min; int min;
int avg; int avg;
}; };
@ -122,12 +120,14 @@ struct trip_stats {
* @timestamp: first trip point crossed the way up * @timestamp: first trip point crossed the way up
* @duration: total duration of the mitigation episode * @duration: total duration of the mitigation episode
* @node: a list element to be added to the list of tz events * @node: a list element to be added to the list of tz events
* @max_temp: maximum zone temperature during this episode
* @trip_stats: per trip point statistics, flexible array * @trip_stats: per trip point statistics, flexible array
*/ */
struct tz_episode { struct tz_episode {
ktime_t timestamp; ktime_t timestamp;
ktime_t duration; ktime_t duration;
struct list_head node; struct list_head node;
int max_temp;
struct trip_stats trip_stats[]; struct trip_stats trip_stats[];
}; };
@ -561,10 +561,11 @@ static struct tz_episode *thermal_debugfs_tz_event_alloc(struct thermal_zone_dev
INIT_LIST_HEAD(&tze->node); INIT_LIST_HEAD(&tze->node);
tze->timestamp = now; tze->timestamp = now;
tze->duration = KTIME_MIN; tze->duration = KTIME_MIN;
tze->max_temp = INT_MIN;
for (i = 0; i < tz->num_trips; i++) { for (i = 0; i < tz->num_trips; i++) {
tze->trip_stats[i].trip_temp = THERMAL_TEMP_INVALID;
tze->trip_stats[i].min = INT_MAX; tze->trip_stats[i].min = INT_MAX;
tze->trip_stats[i].max = INT_MIN;
} }
return tze; return tze;
@ -573,20 +574,20 @@ static struct tz_episode *thermal_debugfs_tz_event_alloc(struct thermal_zone_dev
void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
const struct thermal_trip *trip) const struct thermal_trip *trip)
{ {
struct tz_episode *tze;
struct tz_debugfs *tz_dbg;
struct thermal_debugfs *thermal_dbg = tz->debugfs; struct thermal_debugfs *thermal_dbg = tz->debugfs;
int trip_id = thermal_zone_trip_id(tz, trip); int trip_id = thermal_zone_trip_id(tz, trip);
ktime_t now = ktime_get(); ktime_t now = ktime_get();
struct trip_stats *trip_stats; struct trip_stats *trip_stats;
struct tz_debugfs *tz_dbg;
struct tz_episode *tze;
if (!thermal_dbg) if (!thermal_dbg)
return; return;
mutex_lock(&thermal_dbg->lock);
tz_dbg = &thermal_dbg->tz_dbg; tz_dbg = &thermal_dbg->tz_dbg;
mutex_lock(&thermal_dbg->lock);
/* /*
* The mitigation is starting. A mitigation can contain * The mitigation is starting. A mitigation can contain
* several episodes where each of them is related to a * several episodes where each of them is related to a
@ -653,23 +654,33 @@ void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
mutex_unlock(&thermal_dbg->lock); mutex_unlock(&thermal_dbg->lock);
} }
static void tz_episode_close_trip(struct tz_episode *tze, int trip_id, ktime_t now)
{
struct trip_stats *trip_stats = &tze->trip_stats[trip_id];
ktime_t delta = ktime_sub(now, trip_stats->timestamp);
trip_stats->duration = ktime_add(delta, trip_stats->duration);
/* Mark the end of mitigation for this trip point. */
trip_stats->timestamp = KTIME_MAX;
}
void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
const struct thermal_trip *trip) const struct thermal_trip *trip)
{ {
struct thermal_debugfs *thermal_dbg = tz->debugfs; struct thermal_debugfs *thermal_dbg = tz->debugfs;
int trip_id = thermal_zone_trip_id(tz, trip);
ktime_t now = ktime_get();
struct tz_episode *tze; struct tz_episode *tze;
struct tz_debugfs *tz_dbg; struct tz_debugfs *tz_dbg;
ktime_t delta, now = ktime_get();
int trip_id = thermal_zone_trip_id(tz, trip);
int i; int i;
if (!thermal_dbg) if (!thermal_dbg)
return; return;
mutex_lock(&thermal_dbg->lock);
tz_dbg = &thermal_dbg->tz_dbg; tz_dbg = &thermal_dbg->tz_dbg;
mutex_lock(&thermal_dbg->lock);
/* /*
* The temperature crosses the way down but there was not * The temperature crosses the way down but there was not
* mitigation detected before. That may happen when the * mitigation detected before. That may happen when the
@ -695,13 +706,7 @@ void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node); tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
delta = ktime_sub(now, tze->trip_stats[trip_id].timestamp); tz_episode_close_trip(tze, trip_id, now);
tze->trip_stats[trip_id].duration =
ktime_add(delta, tze->trip_stats[trip_id].duration);
/* Mark the end of mitigation for this trip point. */
tze->trip_stats[trip_id].timestamp = KTIME_MAX;
/* /*
* This event closes the mitigation as we are crossing the * This event closes the mitigation as we are crossing the
@ -724,20 +729,22 @@ void thermal_debug_update_trip_stats(struct thermal_zone_device *tz)
if (!thermal_dbg) if (!thermal_dbg)
return; return;
mutex_lock(&thermal_dbg->lock);
tz_dbg = &thermal_dbg->tz_dbg; tz_dbg = &thermal_dbg->tz_dbg;
mutex_lock(&thermal_dbg->lock);
if (!tz_dbg->nr_trips) if (!tz_dbg->nr_trips)
goto out; goto out;
tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node); tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
if (tz->temperature > tze->max_temp)
tze->max_temp = tz->temperature;
for (i = 0; i < tz_dbg->nr_trips; i++) { for (i = 0; i < tz_dbg->nr_trips; i++) {
int trip_id = tz_dbg->trips_crossed[i]; int trip_id = tz_dbg->trips_crossed[i];
struct trip_stats *trip_stats = &tze->trip_stats[trip_id]; struct trip_stats *trip_stats = &tze->trip_stats[trip_id];
trip_stats->max = max(trip_stats->max, tz->temperature);
trip_stats->min = min(trip_stats->min, tz->temperature); trip_stats->min = min(trip_stats->min, tz->temperature);
trip_stats->avg += (tz->temperature - trip_stats->avg) / trip_stats->avg += (tz->temperature - trip_stats->avg) /
++trip_stats->count; ++trip_stats->count;
@ -777,7 +784,6 @@ static int tze_seq_show(struct seq_file *s, void *v)
struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz; struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz;
struct thermal_trip_desc *td; struct thermal_trip_desc *td;
struct tz_episode *tze; struct tz_episode *tze;
const char *type;
u64 duration_ms; u64 duration_ms;
int trip_id; int trip_id;
char c; char c;
@ -793,10 +799,10 @@ static int tze_seq_show(struct seq_file *s, void *v)
c = '='; c = '=';
} }
seq_printf(s, ",-Mitigation at %lluus, duration%c%llums\n", seq_printf(s, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n",
ktime_to_us(tze->timestamp), c, duration_ms); ktime_to_ms(tze->timestamp), c, duration_ms, tze->max_temp);
seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n"); seq_printf(s, "| trip | type | temp(m°C) | hyst(m°C) | duration(ms) | avg(m°C) | min(m°C) |\n");
for_each_trip_desc(tz, td) { for_each_trip_desc(tz, td) {
const struct thermal_trip *trip = &td->trip; const struct thermal_trip *trip = &td->trip;
@ -814,16 +820,9 @@ static int tze_seq_show(struct seq_file *s, void *v)
trip_stats = &tze->trip_stats[trip_id]; trip_stats = &tze->trip_stats[trip_id];
/* Skip trips without any stats. */ /* Skip trips without any stats. */
if (trip_stats->min > trip_stats->max) if (trip_stats->trip_temp == THERMAL_TEMP_INVALID)
continue; continue;
if (trip->type == THERMAL_TRIP_PASSIVE)
type = "passive";
else if (trip->type == THERMAL_TRIP_ACTIVE)
type = "active";
else
type = "hot";
if (trip_stats->timestamp != KTIME_MAX) { if (trip_stats->timestamp != KTIME_MAX) {
/* Mitigation in progress. */ /* Mitigation in progress. */
ktime_t delta = ktime_sub(ktime_get(), ktime_t delta = ktime_sub(ktime_get(),
@ -837,15 +836,14 @@ static int tze_seq_show(struct seq_file *s, void *v)
c = ' '; c = ' ';
} }
seq_printf(s, "| %*d | %*s | %*d | %*d | %c%*lld | %*d | %*d | %*d |\n", seq_printf(s, "| %*d | %*s | %*d | %*d | %c%*lld | %*d | %*d |\n",
4 , trip_id, 4 , trip_id,
8, type, 8, thermal_trip_type_name(trip->type),
9, trip_stats->trip_temp, 9, trip_stats->trip_temp,
9, trip_stats->trip_hyst, 9, trip_stats->trip_hyst,
c, 10, duration_ms, c, 11, duration_ms,
9, trip_stats->avg, 9, trip_stats->avg,
9, trip_stats->min, 9, trip_stats->min);
9, trip_stats->max);
} }
return 0; return 0;
@ -922,3 +920,39 @@ void thermal_debug_tz_remove(struct thermal_zone_device *tz)
thermal_debugfs_remove_id(thermal_dbg); thermal_debugfs_remove_id(thermal_dbg);
kfree(trips_crossed); kfree(trips_crossed);
} }
void thermal_debug_tz_resume(struct thermal_zone_device *tz)
{
struct thermal_debugfs *thermal_dbg = tz->debugfs;
ktime_t now = ktime_get();
struct tz_debugfs *tz_dbg;
struct tz_episode *tze;
int i;
if (!thermal_dbg)
return;
mutex_lock(&thermal_dbg->lock);
tz_dbg = &thermal_dbg->tz_dbg;
if (!tz_dbg->nr_trips)
goto out;
/*
* A mitigation episode was in progress before the preceding system
* suspend transition, so close it because the zone handling is starting
* over from scratch.
*/
tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
for (i = 0; i < tz_dbg->nr_trips; i++)
tz_episode_close_trip(tze, tz_dbg->trips_crossed[i], now);
tze->duration = ktime_sub(now, tze->timestamp);
tz_dbg->nr_trips = 0;
out:
mutex_unlock(&thermal_dbg->lock);
}

View File

@ -7,6 +7,7 @@ void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev);
void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, int state); void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, int state);
void thermal_debug_tz_add(struct thermal_zone_device *tz); void thermal_debug_tz_add(struct thermal_zone_device *tz);
void thermal_debug_tz_remove(struct thermal_zone_device *tz); void thermal_debug_tz_remove(struct thermal_zone_device *tz);
void thermal_debug_tz_resume(struct thermal_zone_device *tz);
void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
const struct thermal_trip *trip); const struct thermal_trip *trip);
void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
@ -20,6 +21,7 @@ static inline void thermal_debug_cdev_state_update(const struct thermal_cooling_
int state) {} int state) {}
static inline void thermal_debug_tz_add(struct thermal_zone_device *tz) {} static inline void thermal_debug_tz_add(struct thermal_zone_device *tz) {}
static inline void thermal_debug_tz_remove(struct thermal_zone_device *tz) {} static inline void thermal_debug_tz_remove(struct thermal_zone_device *tz) {}
static inline void thermal_debug_tz_resume(struct thermal_zone_device *tz) {}
static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
const struct thermal_trip *trip) {}; const struct thermal_trip *trip) {};
static inline void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, static inline void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,

View File

@ -88,18 +88,7 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1) if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1)
return -EINVAL; return -EINVAL;
switch (tz->trips[trip_id].trip.type) { return sprintf(buf, "%s\n", thermal_trip_type_name(tz->trips[trip_id].trip.type));
case THERMAL_TRIP_CRITICAL:
return sprintf(buf, "critical\n");
case THERMAL_TRIP_HOT:
return sprintf(buf, "hot\n");
case THERMAL_TRIP_PASSIVE:
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
default:
return sprintf(buf, "unknown\n");
}
} }
static ssize_t static ssize_t
@ -150,7 +139,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1) if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
return -EINVAL; return -EINVAL;
return sprintf(buf, "%d\n", tz->trips[trip_id].trip.temperature); return sprintf(buf, "%d\n", READ_ONCE(tz->trips[trip_id].trip.temperature));
} }
static ssize_t static ssize_t
@ -174,7 +163,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
trip = &tz->trips[trip_id].trip; trip = &tz->trips[trip_id].trip;
if (hyst != trip->hysteresis) { if (hyst != trip->hysteresis) {
trip->hysteresis = hyst; WRITE_ONCE(trip->hysteresis, hyst);
thermal_zone_trip_updated(tz, trip); thermal_zone_trip_updated(tz, trip);
} }
@ -194,7 +183,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1) if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
return -EINVAL; return -EINVAL;
return sprintf(buf, "%d\n", tz->trips[trip_id].trip.hysteresis); return sprintf(buf, "%d\n", READ_ONCE(tz->trips[trip_id].trip.hysteresis));
} }
static ssize_t static ssize_t

View File

@ -9,6 +9,21 @@
*/ */
#include "thermal_core.h" #include "thermal_core.h"
static const char *trip_type_names[] = {
[THERMAL_TRIP_ACTIVE] = "active",
[THERMAL_TRIP_PASSIVE] = "passive",
[THERMAL_TRIP_HOT] = "hot",
[THERMAL_TRIP_CRITICAL] = "critical",
};
const char *thermal_trip_type_name(enum thermal_trip_type trip_type)
{
if (trip_type < THERMAL_TRIP_ACTIVE || trip_type > THERMAL_TRIP_CRITICAL)
return "unknown";
return trip_type_names[trip_type];
}
int for_each_thermal_trip(struct thermal_zone_device *tz, int for_each_thermal_trip(struct thermal_zone_device *tz,
int (*cb)(struct thermal_trip *, void *), int (*cb)(struct thermal_trip *, void *),
void *data) void *data)
@ -47,7 +62,7 @@ int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips); EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
/** /**
* __thermal_zone_set_trips - Computes the next trip points for the driver * thermal_zone_set_trips - Computes the next trip points for the driver
* @tz: a pointer to a thermal zone device structure * @tz: a pointer to a thermal zone device structure
* *
* The function computes the next temperature boundaries by browsing * The function computes the next temperature boundaries by browsing
@ -61,7 +76,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
* *
* It does not return a value * It does not return a value
*/ */
void __thermal_zone_set_trips(struct thermal_zone_device *tz) void thermal_zone_set_trips(struct thermal_zone_device *tz)
{ {
const struct thermal_trip_desc *td; const struct thermal_trip_desc *td;
int low = -INT_MAX, high = INT_MAX; int low = -INT_MAX, high = INT_MAX;
@ -73,17 +88,11 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
return; return;
for_each_trip_desc(tz, td) { for_each_trip_desc(tz, td) {
const struct thermal_trip *trip = &td->trip; if (td->threshold < tz->temperature && td->threshold > low)
int trip_low; low = td->threshold;
trip_low = trip->temperature - trip->hysteresis; if (td->threshold > tz->temperature && td->threshold < high)
high = td->threshold;
if (trip_low < tz->temperature && trip_low > low)
low = trip_low;
if (trip->temperature > tz->temperature &&
trip->temperature < high)
high = trip->temperature;
} }
/* No need to change trip points */ /* No need to change trip points */
@ -152,7 +161,7 @@ void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
if (trip->temperature == temp) if (trip->temperature == temp)
return; return;
trip->temperature = temp; WRITE_ONCE(trip->temperature, temp);
thermal_notify_tz_trip_change(tz, trip); thermal_notify_tz_trip_change(tz, trip);
if (temp == THERMAL_TEMP_INVALID) { if (temp == THERMAL_TEMP_INVALID) {