diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-06-25 16:27:38 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-06-25 16:27:38 +0200 |
commit | 06d55c4278dcbd8f69e70fed312db738b6b03410 (patch) | |
tree | 4d917fe7908bbd1cc58d7bcaab418469306446c7 /drivers/thermal | |
parent | 3995904d54384093f79f4a5a12318261c55e2ec1 (diff) | |
parent | 72196c20c38b50c4293696377145e6c4ad9a7c67 (diff) |
Merge branch 'thermal-core'
Merge thermal core changes for v6.11:
- Fix and clean up several minor shortcomings in thermal debug (Rafael
Wysocki).
- Rename __thermal_zone_set_trips() to thermal_zone_set_trips() and
make it use trip thresholds (Rafael Wysocki).
- Use READ_ONCE() for lockless access to trip temperature and
hysteresis (Rafael Wysocki).
- Drop unnecessary cooling device target state checks from the
Bang-Bang thermal governor (Rafael Wysocki).
- Avoid invoking thermal governor .trip_crossed() callback for critical
and hot trip points (Rafael Wysocki).
* thermal-core:
thermal: core: Avoid calling .trip_crossed() for critical and hot trips
thermal: gov_bang_bang: Drop unnecessary cooling device target state checks
thermal: trip: Use READ_ONCE() for lockless access to trip properties
thermal: trip: Make thermal_zone_set_trips() use trip thresholds
thermal: trip: Rename __thermal_zone_set_trips() to thermal_zone_set_trips()
thermal: trip: Use common set of trip type names
thermal/debugfs: Move some statements from under thermal_dbg->lock
thermal/debugfs: Compute maximum temperature for mitigation episode as a whole
thermal/debugfs: Adjust check for trips without statistics in tze_seq_show()
thermal/debugfs: Fix up units in "mitigations" files
thermal/debugfs: Print mitigation timestamp value in milliseconds
thermal/debugfs: Do not extend mitigation episodes beyond system resume
thermal/debugfs: Use helper to update trip point overstepping duration
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/gov_bang_bang.c | 14 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 8 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.h | 4 | ||||
-rw-r--r-- | drivers/thermal/thermal_debugfs.c | 110 | ||||
-rw-r--r-- | drivers/thermal/thermal_debugfs.h | 2 | ||||
-rw-r--r-- | drivers/thermal/thermal_sysfs.c | 19 | ||||
-rw-r--r-- | drivers/thermal/thermal_trip.c | 35 |
7 files changed, 112 insertions, 80 deletions
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index acb52c9ee10f..4a2e869b9538 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -57,24 +57,16 @@ static void bang_bang_control(struct thermal_zone_device *tz, if (instance->trip != trip) continue; - if (instance->target == THERMAL_NO_TARGET) - instance->target = 0; - - if (instance->target != 0 && instance->target != 1) { + if (instance->target != 0 && instance->target != 1 && + instance->target != THERMAL_NO_TARGET) pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", instance->target, instance->name); - instance->target = 1; - } - /* * Enable the fan when the trip is crossed on the way up and * disable it when the trip is crossed on the way down. */ - if (instance->target == 0 && crossed_up) - instance->target = 1; - else if (instance->target == 1 && !crossed_up) - instance->target = 0; + instance->target = crossed_up; dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 1b0ab2790860..2aa04c46a425 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -463,6 +463,9 @@ static void thermal_governor_trip_crossed(struct thermal_governor *governor, const struct thermal_trip *trip, bool crossed_up) { + if (trip->type == THERMAL_TRIP_HOT || trip->type == THERMAL_TRIP_CRITICAL) + return; + if (governor->trip_crossed) 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) return; - __thermal_zone_set_trips(tz); - tz->notify_event = event; for_each_trip_desc(tz, td) 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_for_each_entry(td, &way_up_list, notify_list_node) 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; + thermal_debug_tz_resume(tz); thermal_zone_device_init(tz); __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 66f67e54e0c8..16b3f06832d4 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -244,7 +244,9 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz, #define trip_to_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, const struct thermal_trip *trip); void thermal_zone_trip_updated(struct thermal_zone_device *tz, diff --git a/drivers/thermal/thermal_debugfs.c b/drivers/thermal/thermal_debugfs.c index 942447229157..7dd67bf48571 100644 --- a/drivers/thermal/thermal_debugfs.c +++ b/drivers/thermal/thermal_debugfs.c @@ -94,7 +94,6 @@ struct cdev_record { * @trip_temp: trip temperature at mitigation start * @trip_hyst: trip hysteresis at mitigation start * @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 * @avg: average temperature above the trip point */ @@ -104,7 +103,6 @@ struct trip_stats { int trip_temp; int trip_hyst; int count; - int max; int min; int avg; }; @@ -122,12 +120,14 @@ struct trip_stats { * @timestamp: first trip point crossed the way up * @duration: total duration of the mitigation episode * @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 */ struct tz_episode { ktime_t timestamp; ktime_t duration; struct list_head node; + int max_temp; 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); tze->timestamp = now; tze->duration = KTIME_MIN; + tze->max_temp = INT_MIN; 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].max = INT_MIN; } 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, const struct thermal_trip *trip) { - struct tz_episode *tze; - struct tz_debugfs *tz_dbg; struct thermal_debugfs *thermal_dbg = tz->debugfs; int trip_id = thermal_zone_trip_id(tz, trip); ktime_t now = ktime_get(); struct trip_stats *trip_stats; + struct tz_debugfs *tz_dbg; + struct tz_episode *tze; if (!thermal_dbg) return; - mutex_lock(&thermal_dbg->lock); - tz_dbg = &thermal_dbg->tz_dbg; + mutex_lock(&thermal_dbg->lock); + /* * The mitigation is starting. A mitigation can contain * several episodes where each of them is related to a @@ -653,23 +654,33 @@ unlock: 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, const struct thermal_trip *trip) { 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_debugfs *tz_dbg; - ktime_t delta, now = ktime_get(); - int trip_id = thermal_zone_trip_id(tz, trip); int i; if (!thermal_dbg) return; - mutex_lock(&thermal_dbg->lock); - tz_dbg = &thermal_dbg->tz_dbg; + mutex_lock(&thermal_dbg->lock); + /* * The temperature crosses the way down but there was not * 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); - delta = ktime_sub(now, tze->trip_stats[trip_id].timestamp); - - 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; + tz_episode_close_trip(tze, trip_id, now); /* * 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) return; - mutex_lock(&thermal_dbg->lock); - tz_dbg = &thermal_dbg->tz_dbg; + mutex_lock(&thermal_dbg->lock); + if (!tz_dbg->nr_trips) goto out; 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++) { int trip_id = tz_dbg->trips_crossed[i]; 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->avg += (tz->temperature - trip_stats->avg) / ++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_trip_desc *td; struct tz_episode *tze; - const char *type; u64 duration_ms; int trip_id; char c; @@ -793,10 +799,10 @@ static int tze_seq_show(struct seq_file *s, void *v) c = '='; } - seq_printf(s, ",-Mitigation at %lluus, duration%c%llums\n", - ktime_to_us(tze->timestamp), c, duration_ms); + seq_printf(s, ",-Mitigation at %llums, duration%c%llums, max. temp=%dm°C\n", + 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) { 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]; /* Skip trips without any stats. */ - if (trip_stats->min > trip_stats->max) + if (trip_stats->trip_temp == THERMAL_TEMP_INVALID) 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) { /* Mitigation in progress. */ ktime_t delta = ktime_sub(ktime_get(), @@ -837,15 +836,14 @@ static int tze_seq_show(struct seq_file *s, void *v) 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, - 8, type, + 8, thermal_trip_type_name(trip->type), 9, trip_stats->trip_temp, 9, trip_stats->trip_hyst, - c, 10, duration_ms, + c, 11, duration_ms, 9, trip_stats->avg, - 9, trip_stats->min, - 9, trip_stats->max); + 9, trip_stats->min); } return 0; @@ -922,3 +920,39 @@ void thermal_debug_tz_remove(struct thermal_zone_device *tz) thermal_debugfs_remove_id(thermal_dbg); 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); +} diff --git a/drivers/thermal/thermal_debugfs.h b/drivers/thermal/thermal_debugfs.h index 74ee65ee82ff..1c957ce2ec8f 100644 --- a/drivers/thermal/thermal_debugfs.h +++ b/drivers/thermal/thermal_debugfs.h @@ -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_tz_add(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, const struct thermal_trip *trip); 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) {} 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_resume(struct thermal_zone_device *tz) {} static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz, const struct thermal_trip *trip) {}; static inline void thermal_debug_tz_trip_down(struct thermal_zone_device *tz, diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 88211ccdfbd6..434b577950be 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -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) return -EINVAL; - switch (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"); - } + return sprintf(buf, "%s\n", thermal_trip_type_name(tz->trips[trip_id].trip.type)); } 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) 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 @@ -174,7 +163,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, trip = &tz->trips[trip_id].trip; if (hyst != trip->hysteresis) { - trip->hysteresis = hyst; + WRITE_ONCE(trip->hysteresis, hyst); 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) 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 diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c index 49e63db68517..2a876d3b93aa 100644 --- a/drivers/thermal/thermal_trip.c +++ b/drivers/thermal/thermal_trip.c @@ -9,6 +9,21 @@ */ #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 (*cb)(struct thermal_trip *, void *), 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); /** - * __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 * * 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 */ -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; int low = -INT_MAX, high = INT_MAX; @@ -73,17 +88,11 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz) return; for_each_trip_desc(tz, td) { - const struct thermal_trip *trip = &td->trip; - int trip_low; - - trip_low = trip->temperature - trip->hysteresis; - - if (trip_low < tz->temperature && trip_low > low) - low = trip_low; + if (td->threshold < tz->temperature && td->threshold > low) + low = td->threshold; - if (trip->temperature > tz->temperature && - trip->temperature < high) - high = trip->temperature; + if (td->threshold > tz->temperature && td->threshold < high) + high = td->threshold; } /* 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) return; - trip->temperature = temp; + WRITE_ONCE(trip->temperature, temp); thermal_notify_tz_trip_change(tz, trip); if (temp == THERMAL_TEMP_INVALID) { |