Commit fd3d06ff authored by Linus Torvalds's avatar Linus Torvalds

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

Pull thermal control fixes from Rafael Wysocki:
 "These address two recent regressions related to thermal control.

  Specifics:

   - Restore the thermal core behavior regarding zero-temperature trip
     points to avoid a driver regression (Ido Schimmel)

   - Fix a recent regression in the ACPI processor driver preventing it
     from changing the number of CPU cooling device states exposed via
     sysfs after the given CPU cooling device has been registered
     (Rafael Wysocki)"

* tag 'thermal-6.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  thermal: core: Restore behavior regarding invalid trip points
  ACPI: processor: thermal: Update CPU cooling devices on cpufreq policy changes
  thermal: core: Introduce thermal_cooling_device_update()
  thermal: core: Introduce thermal_cooling_device_present()
  ACPI: processor: Reorder acpi_processor_driver_init()
parents 1868d192 6babf38d
......@@ -263,6 +263,12 @@ static int __init acpi_processor_driver_init(void)
if (acpi_disabled)
return 0;
if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
CPUFREQ_POLICY_NOTIFIER)) {
acpi_processor_cpufreq_init = true;
acpi_processor_ignore_ppc_init();
}
result = driver_register(&acpi_processor_driver);
if (result < 0)
return result;
......@@ -276,12 +282,6 @@ static int __init acpi_processor_driver_init(void)
cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
NULL, acpi_soft_cpu_dead);
if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
CPUFREQ_POLICY_NOTIFIER)) {
acpi_processor_cpufreq_init = true;
acpi_processor_ignore_ppc_init();
}
acpi_processor_throttling_init();
return 0;
err:
......
......@@ -140,9 +140,13 @@ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
ret = freq_qos_add_request(&policy->constraints,
&pr->thermal_req,
FREQ_QOS_MAX, INT_MAX);
if (ret < 0)
if (ret < 0) {
pr_err("Failed to add freq constraint for CPU%d (%d)\n",
cpu, ret);
continue;
}
thermal_cooling_device_update(pr->cdev);
}
}
......@@ -153,8 +157,12 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
for_each_cpu(cpu, policy->related_cpus) {
struct acpi_processor *pr = per_cpu(processors, cpu);
if (pr)
freq_qos_remove_request(&pr->thermal_req);
if (!pr)
continue;
freq_qos_remove_request(&pr->thermal_req);
thermal_cooling_device_update(pr->cdev);
}
}
#else /* ! CONFIG_CPU_FREQ */
......
......@@ -613,6 +613,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
struct thermal_instance *pos;
struct thermal_zone_device *pos1;
struct thermal_cooling_device *pos2;
bool upper_no_limit;
int result;
if (trip >= tz->num_trips || trip < 0)
......@@ -632,7 +633,13 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
/* lower default 0, upper default max_state */
lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
upper = upper == THERMAL_NO_LIMIT ? cdev->max_state : upper;
if (upper == THERMAL_NO_LIMIT) {
upper = cdev->max_state;
upper_no_limit = true;
} else {
upper_no_limit = false;
}
if (lower > upper || upper > cdev->max_state)
return -EINVAL;
......@@ -644,6 +651,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
dev->cdev = cdev;
dev->trip = trip;
dev->upper = upper;
dev->upper_no_limit = upper_no_limit;
dev->lower = lower;
dev->target = THERMAL_NO_TARGET;
dev->weight = weight;
......@@ -1045,6 +1053,91 @@ devm_thermal_of_cooling_device_register(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device *pos = NULL;
list_for_each_entry(pos, &thermal_cdev_list, node) {
if (pos == cdev)
return true;
}
return false;
}
/**
* thermal_cooling_device_update - Update a cooling device object
* @cdev: Target cooling device.
*
* Update @cdev to reflect a change of the underlying hardware or platform.
*
* Must be called when the maximum cooling state of @cdev becomes invalid and so
* its .get_max_state() callback needs to be run to produce the new maximum
* cooling state value.
*/
void thermal_cooling_device_update(struct thermal_cooling_device *cdev)
{
struct thermal_instance *ti;
unsigned long state;
if (IS_ERR_OR_NULL(cdev))
return;
/*
* Hold thermal_list_lock throughout the update to prevent the device
* from going away while being updated.
*/
mutex_lock(&thermal_list_lock);
if (!thermal_cooling_device_present(cdev))
goto unlock_list;
/*
* Update under the cdev lock to prevent the state from being set beyond
* the new limit concurrently.
*/
mutex_lock(&cdev->lock);
if (cdev->ops->get_max_state(cdev, &cdev->max_state))
goto unlock;
thermal_cooling_device_stats_reinit(cdev);
list_for_each_entry(ti, &cdev->thermal_instances, cdev_node) {
if (ti->upper == cdev->max_state)
continue;
if (ti->upper < cdev->max_state) {
if (ti->upper_no_limit)
ti->upper = cdev->max_state;
continue;
}
ti->upper = cdev->max_state;
if (ti->lower > ti->upper)
ti->lower = ti->upper;
if (ti->target == THERMAL_NO_TARGET)
continue;
if (ti->target > ti->upper)
ti->target = ti->upper;
}
if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state)
goto unlock;
thermal_cooling_device_stats_update(cdev, state);
unlock:
mutex_unlock(&cdev->lock);
unlock_list:
mutex_unlock(&thermal_list_lock);
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_update);
static void __unbind(struct thermal_zone_device *tz, int mask,
struct thermal_cooling_device *cdev)
{
......@@ -1067,20 +1160,17 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
int i;
const struct thermal_zone_params *tzp;
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos = NULL;
if (!cdev)
return;
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_cdev_list, node)
if (pos == cdev)
break;
if (pos != cdev) {
/* thermal cooling device not found */
if (!thermal_cooling_device_present(cdev)) {
mutex_unlock(&thermal_list_lock);
return;
}
list_del(&cdev->node);
/* Unbind all thermal zones associated with 'this' cdev */
......@@ -1309,7 +1399,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
struct thermal_trip trip;
result = thermal_zone_get_trip(tz, count, &trip);
if (result)
if (result || !trip.temperature)
set_bit(count, &tz->trips_disabled);
}
......
......@@ -101,6 +101,7 @@ struct thermal_instance {
struct list_head tz_node; /* node in tz->thermal_instances */
struct list_head cdev_node; /* node in cdev->thermal_instances */
unsigned int weight; /* The weight of the cooling device */
bool upper_no_limit;
};
#define to_thermal_zone(_dev) \
......@@ -127,6 +128,7 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
void thermal_zone_destroy_device_groups(struct thermal_zone_device *);
void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *);
void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev);
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev);
/* used only at binding time */
ssize_t trip_point_show(struct device *, struct device_attribute *, char *);
ssize_t weight_show(struct device *, struct device_attribute *, char *);
......
......@@ -685,6 +685,8 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
{
struct cooling_dev_stats *stats = cdev->stats;
lockdep_assert_held(&cdev->lock);
if (!stats)
return;
......@@ -706,13 +708,22 @@ static ssize_t total_trans_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats;
int ret;
struct cooling_dev_stats *stats;
int ret = 0;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
spin_lock(&stats->lock);
ret = sprintf(buf, "%u\n", stats->total_trans);
spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return ret;
}
......@@ -721,11 +732,18 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats;
struct cooling_dev_stats *stats;
ssize_t len = 0;
int i;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
spin_lock(&stats->lock);
update_time_in_state(stats);
for (i = 0; i <= cdev->max_state; i++) {
......@@ -734,6 +752,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
}
spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return len;
}
......@@ -742,8 +763,16 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats;
int i, states = cdev->max_state + 1;
struct cooling_dev_stats *stats;
int i, states;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
states = cdev->max_state + 1;
spin_lock(&stats->lock);
......@@ -757,6 +786,9 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return count;
}
......@@ -764,10 +796,18 @@ static ssize_t trans_table_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats;
struct cooling_dev_stats *stats;
ssize_t len = 0;
int i, j;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats) {
len = -ENODATA;
goto unlock;
}
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
for (i = 0; i <= cdev->max_state; i++) {
......@@ -775,8 +815,10 @@ static ssize_t trans_table_show(struct device *dev,
break;
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
}
if (len >= PAGE_SIZE)
return PAGE_SIZE;
if (len >= PAGE_SIZE) {
len = PAGE_SIZE;
goto unlock;
}
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
......@@ -799,8 +841,12 @@ static ssize_t trans_table_show(struct device *dev,
if (len >= PAGE_SIZE) {
pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
return -EFBIG;
len = -EFBIG;
}
unlock:
mutex_unlock(&cdev->lock);
return len;
}
......@@ -830,6 +876,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
unsigned long states = cdev->max_state + 1;
int var;
lockdep_assert_held(&cdev->lock);
var = sizeof(*stats);
var += sizeof(*stats->time_in_state) * states;
var += sizeof(*stats->trans_table) * states * states;
......@@ -855,6 +903,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
{
lockdep_assert_held(&cdev->lock);
kfree(cdev->stats);
cdev->stats = NULL;
}
......@@ -879,6 +929,12 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
cooling_device_stats_destroy(cdev);
}
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev)
{
cooling_device_stats_destroy(cdev);
cooling_device_stats_setup(cdev);
}
/* these helper will be used only at the time of bindig */
ssize_t
trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
......
......@@ -384,6 +384,7 @@ devm_thermal_of_cooling_device_register(struct device *dev,
struct device_node *np,
char *type, void *devdata,
const struct thermal_cooling_device_ops *ops);
void thermal_cooling_device_update(struct thermal_cooling_device *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
......
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