mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 05:33:09 +00:00
529038146b
Commitb684682698
("thermal: gov_step_wise: Restore passive polling management") attempted to fix a Step-Wise thermal governor issue introduced by commit042a3d80f1
("thermal: core: Move passive polling management to the core"), which caused the governor to leave cooling devices in high states, by partially reverting that commit. However, this turns out to be insufficient on some systems due to interactions between the governor code restored by commitb684682698
and the passive polling management in the thermal core. For this reason, revert commitb684682698
and make the governor set the target cooling device state to the "lower" one as soon as the zone temperature falls below the threshold of the trip point corresponding to the given thermal instance, which means that thermal mitigation is not necessary any more. Before this change the "lower" cooling device state would be reached in steps through the passive polling mechanism which was questionable for three reasons: (1) cooling device were kept in high states when that was not necessary (and it could adversely impact performance), (2) it only worked for thermal zones with nonzero passive_delay_jiffies value, and (3) passive polling belongs to the core and should not be hijacked by governors for their internal purposes. Fixes:b684682698
("thermal: gov_step_wise: Restore passive polling management") Closes: https://lore.kernel.org/linux-pm/6759ce9f-281d-4fcd-bb4c-b784a1cc5f6e@oldschoolsolutions.biz Reported-by: Jens Glathe <jens.glathe@oldschoolsolutions.biz> Tested-by: Jens Glathe <jens.glathe@oldschoolsolutions.biz> Link: https://patch.msgid.link/12464461.O9o76ZdvQC@rjwysocki.net Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Steev Klimaszewski <steev@kali.org> Tested-by: Johan Hovold <johan+linaro@kernel.org>
142 lines
4.1 KiB
C
142 lines
4.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* step_wise.c - A step-by-step Thermal throttling governor
|
|
*
|
|
* Copyright (C) 2012 Intel Corp
|
|
* Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*/
|
|
|
|
#include <linux/thermal.h>
|
|
#include <linux/minmax.h>
|
|
#include "thermal_trace.h"
|
|
|
|
#include "thermal_core.h"
|
|
|
|
/*
|
|
* If the temperature is higher than a trip point,
|
|
* a. if the trend is THERMAL_TREND_RAISING, use higher cooling
|
|
* state for this trip point
|
|
* b. if the trend is THERMAL_TREND_DROPPING, do nothing
|
|
* If the temperature is lower than a trip point,
|
|
* a. if the trend is THERMAL_TREND_RAISING, do nothing
|
|
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
|
|
* state for this trip point, if the cooling state already
|
|
* equals lower limit, deactivate the thermal instance
|
|
*/
|
|
static unsigned long get_target_state(struct thermal_instance *instance,
|
|
enum thermal_trend trend, bool throttle)
|
|
{
|
|
struct thermal_cooling_device *cdev = instance->cdev;
|
|
unsigned long cur_state;
|
|
|
|
/*
|
|
* We keep this instance the way it is by default.
|
|
* Otherwise, we use the current state of the
|
|
* cdev in use to determine the next_target.
|
|
*/
|
|
cdev->ops->get_cur_state(cdev, &cur_state);
|
|
dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state);
|
|
|
|
if (!instance->initialized) {
|
|
if (throttle)
|
|
return clamp(cur_state + 1, instance->lower, instance->upper);
|
|
|
|
return THERMAL_NO_TARGET;
|
|
}
|
|
|
|
if (throttle) {
|
|
if (trend == THERMAL_TREND_RAISING)
|
|
return clamp(cur_state + 1, instance->lower, instance->upper);
|
|
} else if (trend == THERMAL_TREND_DROPPING) {
|
|
if (cur_state <= instance->lower)
|
|
return THERMAL_NO_TARGET;
|
|
|
|
/*
|
|
* If 'throttle' is false, no mitigation is necessary, so
|
|
* request the lower state for this instance.
|
|
*/
|
|
return instance->lower;
|
|
}
|
|
|
|
return instance->target;
|
|
}
|
|
|
|
static void thermal_zone_trip_update(struct thermal_zone_device *tz,
|
|
const struct thermal_trip *trip,
|
|
int trip_threshold)
|
|
{
|
|
enum thermal_trend trend = get_tz_trend(tz, trip);
|
|
int trip_id = thermal_zone_trip_id(tz, trip);
|
|
struct thermal_instance *instance;
|
|
bool throttle = false;
|
|
|
|
if (tz->temperature >= trip_threshold) {
|
|
throttle = true;
|
|
trace_thermal_zone_trip(tz, trip_id, trip->type);
|
|
}
|
|
|
|
dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
|
|
trip_id, trip->type, trip_threshold, trend, throttle);
|
|
|
|
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
|
int old_target;
|
|
|
|
if (instance->trip != trip)
|
|
continue;
|
|
|
|
old_target = instance->target;
|
|
instance->target = get_target_state(instance, trend, throttle);
|
|
|
|
dev_dbg(&instance->cdev->device, "old_target=%d, target=%ld\n",
|
|
old_target, instance->target);
|
|
|
|
if (instance->initialized && old_target == instance->target)
|
|
continue;
|
|
|
|
instance->initialized = true;
|
|
|
|
mutex_lock(&instance->cdev->lock);
|
|
instance->cdev->updated = false; /* cdev needs update */
|
|
mutex_unlock(&instance->cdev->lock);
|
|
}
|
|
}
|
|
|
|
static void step_wise_manage(struct thermal_zone_device *tz)
|
|
{
|
|
const struct thermal_trip_desc *td;
|
|
struct thermal_instance *instance;
|
|
|
|
lockdep_assert_held(&tz->lock);
|
|
|
|
/*
|
|
* Throttling Logic: Use the trend of the thermal zone to throttle.
|
|
* If the thermal zone is 'heating up', throttle all of the cooling
|
|
* devices associated with each trip point by one step. If the zone
|
|
* is 'cooling down', it brings back the performance of the devices
|
|
* by one step.
|
|
*/
|
|
for_each_trip_desc(tz, td) {
|
|
const struct thermal_trip *trip = &td->trip;
|
|
|
|
if (trip->temperature == THERMAL_TEMP_INVALID ||
|
|
trip->type == THERMAL_TRIP_CRITICAL ||
|
|
trip->type == THERMAL_TRIP_HOT)
|
|
continue;
|
|
|
|
thermal_zone_trip_update(tz, trip, td->threshold);
|
|
}
|
|
|
|
list_for_each_entry(instance, &tz->thermal_instances, tz_node)
|
|
thermal_cdev_update(instance->cdev);
|
|
}
|
|
|
|
static struct thermal_governor thermal_gov_step_wise = {
|
|
.name = "step_wise",
|
|
.manage = step_wise_manage,
|
|
};
|
|
THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise);
|