Commit 296c871d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-6.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull thermal control fix from Rafael Wysocki:
 "Fix a Bang-bang thermal governor issue causing it to fail to reset the
  state of cooling devices if they are 'on' to start with, but the
  thermal zone temperature is always below the corresponding trip point
  (Rafael Wysocki)"

* tag 'thermal-6.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  thermal: gov_bang_bang: Use governor_data to reduce overhead
  thermal: gov_bang_bang: Add .manage() callback
  thermal: gov_bang_bang: Split bang_bang_control()
  thermal: gov_bang_bang: Call __thermal_cdev_update() directly
parents 64ab5e40 6e6f58a1
......@@ -13,6 +13,28 @@
#include "thermal_core.h"
static void bang_bang_set_instance_target(struct thermal_instance *instance,
unsigned int target)
{
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);
/*
* Enable the fan when the trip is crossed on the way up and disable it
* when the trip is crossed on the way down.
*/
instance->target = target;
instance->initialized = true;
dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);
mutex_lock(&instance->cdev->lock);
__thermal_cdev_update(instance->cdev);
mutex_unlock(&instance->cdev->lock);
}
/**
* bang_bang_control - controls devices associated with the given zone
* @tz: thermal_zone_device
......@@ -54,33 +76,60 @@ static void bang_bang_control(struct thermal_zone_device *tz,
tz->temperature, trip->hysteresis);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if (instance->trip != trip)
continue;
if (instance->trip == trip)
bang_bang_set_instance_target(instance, crossed_up);
}
}
static void bang_bang_manage(struct thermal_zone_device *tz)
{
const struct thermal_trip_desc *td;
struct thermal_instance *instance;
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);
/* If the code below has run already, nothing needs to be done. */
if (tz->governor_data)
return;
/*
* Enable the fan when the trip is crossed on the way up and
* disable it when the trip is crossed on the way down.
*/
instance->target = crossed_up;
for_each_trip_desc(tz, td) {
const struct thermal_trip *trip = &td->trip;
dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);
if (tz->temperature >= td->threshold ||
trip->temperature == THERMAL_TEMP_INVALID ||
trip->type == THERMAL_TRIP_CRITICAL ||
trip->type == THERMAL_TRIP_HOT)
continue;
mutex_lock(&instance->cdev->lock);
instance->cdev->updated = false; /* cdev needs update */
mutex_unlock(&instance->cdev->lock);
/*
* If the initial cooling device state is "on", but the zone
* temperature is not above the trip point, the core will not
* call bang_bang_control() until the zone temperature reaches
* the trip point temperature which may be never. In those
* cases, set the initial state of the cooling device to 0.
*/
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if (!instance->initialized && instance->trip == trip)
bang_bang_set_instance_target(instance, 0);
}
}
list_for_each_entry(instance, &tz->thermal_instances, tz_node)
thermal_cdev_update(instance->cdev);
tz->governor_data = (void *)true;
}
static void bang_bang_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason)
{
/*
* Let bang_bang_manage() know that it needs to walk trips after binding
* a new cdev and after system resume.
*/
if (reason == THERMAL_TZ_BIND_CDEV || reason == THERMAL_TZ_RESUME)
tz->governor_data = NULL;
}
static struct thermal_governor thermal_gov_bang_bang = {
.name = "bang_bang",
.trip_crossed = bang_bang_control,
.manage = bang_bang_manage,
.update_tz = bang_bang_update_tz,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);
......@@ -1728,7 +1728,8 @@ static void thermal_zone_device_resume(struct work_struct *work)
thermal_debug_tz_resume(tz);
thermal_zone_device_init(tz);
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
thermal_governor_update_tz(tz, THERMAL_TZ_RESUME);
__thermal_zone_device_update(tz, THERMAL_TZ_RESUME);
complete(&tz->resume);
tz->resuming = false;
......
......@@ -55,6 +55,7 @@ enum thermal_notify_event {
THERMAL_TZ_BIND_CDEV, /* Cooling dev is bind to the thermal zone */
THERMAL_TZ_UNBIND_CDEV, /* Cooling dev is unbind from the thermal zone */
THERMAL_INSTANCE_WEIGHT_CHANGED, /* Thermal instance weight changed */
THERMAL_TZ_RESUME, /* Thermal zone is resuming after system sleep */
};
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment