Commit 6babf38d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'thermal-acpi'

Merge a fix for a recent thermal-related regression in the ACPI
processor driver.

* thermal-acpi:
  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 f1b80a38 22c52fa5
...@@ -263,6 +263,12 @@ static int __init acpi_processor_driver_init(void) ...@@ -263,6 +263,12 @@ static int __init acpi_processor_driver_init(void)
if (acpi_disabled) if (acpi_disabled)
return 0; 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); result = driver_register(&acpi_processor_driver);
if (result < 0) if (result < 0)
return result; return result;
...@@ -276,12 +282,6 @@ static int __init acpi_processor_driver_init(void) ...@@ -276,12 +282,6 @@ static int __init acpi_processor_driver_init(void)
cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead", cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
NULL, acpi_soft_cpu_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(); acpi_processor_throttling_init();
return 0; return 0;
err: err:
......
...@@ -140,9 +140,13 @@ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy) ...@@ -140,9 +140,13 @@ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
ret = freq_qos_add_request(&policy->constraints, ret = freq_qos_add_request(&policy->constraints,
&pr->thermal_req, &pr->thermal_req,
FREQ_QOS_MAX, INT_MAX); FREQ_QOS_MAX, INT_MAX);
if (ret < 0) if (ret < 0) {
pr_err("Failed to add freq constraint for CPU%d (%d)\n", pr_err("Failed to add freq constraint for CPU%d (%d)\n",
cpu, ret); cpu, ret);
continue;
}
thermal_cooling_device_update(pr->cdev);
} }
} }
...@@ -153,8 +157,12 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy) ...@@ -153,8 +157,12 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
for_each_cpu(cpu, policy->related_cpus) { for_each_cpu(cpu, policy->related_cpus) {
struct acpi_processor *pr = per_cpu(processors, cpu); struct acpi_processor *pr = per_cpu(processors, cpu);
if (pr) if (!pr)
freq_qos_remove_request(&pr->thermal_req); continue;
freq_qos_remove_request(&pr->thermal_req);
thermal_cooling_device_update(pr->cdev);
} }
} }
#else /* ! CONFIG_CPU_FREQ */ #else /* ! CONFIG_CPU_FREQ */
......
...@@ -613,6 +613,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ...@@ -613,6 +613,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
struct thermal_instance *pos; struct thermal_instance *pos;
struct thermal_zone_device *pos1; struct thermal_zone_device *pos1;
struct thermal_cooling_device *pos2; struct thermal_cooling_device *pos2;
bool upper_no_limit;
int result; int result;
if (trip >= tz->num_trips || trip < 0) if (trip >= tz->num_trips || trip < 0)
...@@ -632,7 +633,13 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ...@@ -632,7 +633,13 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
/* lower default 0, upper default max_state */ /* lower default 0, upper default max_state */
lower = lower == THERMAL_NO_LIMIT ? 0 : lower; 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) if (lower > upper || upper > cdev->max_state)
return -EINVAL; return -EINVAL;
...@@ -644,6 +651,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ...@@ -644,6 +651,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
dev->cdev = cdev; dev->cdev = cdev;
dev->trip = trip; dev->trip = trip;
dev->upper = upper; dev->upper = upper;
dev->upper_no_limit = upper_no_limit;
dev->lower = lower; dev->lower = lower;
dev->target = THERMAL_NO_TARGET; dev->target = THERMAL_NO_TARGET;
dev->weight = weight; dev->weight = weight;
...@@ -1045,6 +1053,91 @@ devm_thermal_of_cooling_device_register(struct device *dev, ...@@ -1045,6 +1053,91 @@ devm_thermal_of_cooling_device_register(struct device *dev,
} }
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register); 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, static void __unbind(struct thermal_zone_device *tz, int mask,
struct thermal_cooling_device *cdev) struct thermal_cooling_device *cdev)
{ {
...@@ -1067,20 +1160,17 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) ...@@ -1067,20 +1160,17 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
int i; int i;
const struct thermal_zone_params *tzp; const struct thermal_zone_params *tzp;
struct thermal_zone_device *tz; struct thermal_zone_device *tz;
struct thermal_cooling_device *pos = NULL;
if (!cdev) if (!cdev)
return; return;
mutex_lock(&thermal_list_lock); mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_cdev_list, node)
if (pos == cdev) if (!thermal_cooling_device_present(cdev)) {
break;
if (pos != cdev) {
/* thermal cooling device not found */
mutex_unlock(&thermal_list_lock); mutex_unlock(&thermal_list_lock);
return; return;
} }
list_del(&cdev->node); list_del(&cdev->node);
/* Unbind all thermal zones associated with 'this' cdev */ /* Unbind all thermal zones associated with 'this' cdev */
......
...@@ -101,6 +101,7 @@ struct thermal_instance { ...@@ -101,6 +101,7 @@ struct thermal_instance {
struct list_head tz_node; /* node in tz->thermal_instances */ struct list_head tz_node; /* node in tz->thermal_instances */
struct list_head cdev_node; /* node in cdev->thermal_instances */ struct list_head cdev_node; /* node in cdev->thermal_instances */
unsigned int weight; /* The weight of the cooling device */ unsigned int weight; /* The weight of the cooling device */
bool upper_no_limit;
}; };
#define to_thermal_zone(_dev) \ #define to_thermal_zone(_dev) \
...@@ -127,6 +128,7 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *, int); ...@@ -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_zone_destroy_device_groups(struct thermal_zone_device *);
void thermal_cooling_device_setup_sysfs(struct thermal_cooling_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_destroy_sysfs(struct thermal_cooling_device *cdev);
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev);
/* used only at binding time */ /* used only at binding time */
ssize_t trip_point_show(struct device *, struct device_attribute *, char *); ssize_t trip_point_show(struct device *, struct device_attribute *, char *);
ssize_t weight_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, ...@@ -685,6 +685,8 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
{ {
struct cooling_dev_stats *stats = cdev->stats; struct cooling_dev_stats *stats = cdev->stats;
lockdep_assert_held(&cdev->lock);
if (!stats) if (!stats)
return; return;
...@@ -706,13 +708,22 @@ static ssize_t total_trans_show(struct device *dev, ...@@ -706,13 +708,22 @@ static ssize_t total_trans_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct thermal_cooling_device *cdev = to_cooling_device(dev); struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats; struct cooling_dev_stats *stats;
int ret; int ret = 0;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
spin_lock(&stats->lock); spin_lock(&stats->lock);
ret = sprintf(buf, "%u\n", stats->total_trans); ret = sprintf(buf, "%u\n", stats->total_trans);
spin_unlock(&stats->lock); spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return ret; return ret;
} }
...@@ -721,11 +732,18 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ...@@ -721,11 +732,18 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct thermal_cooling_device *cdev = to_cooling_device(dev); 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; ssize_t len = 0;
int i; int i;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
spin_lock(&stats->lock); spin_lock(&stats->lock);
update_time_in_state(stats); update_time_in_state(stats);
for (i = 0; i <= cdev->max_state; i++) { for (i = 0; i <= cdev->max_state; i++) {
...@@ -734,6 +752,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ...@@ -734,6 +752,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
} }
spin_unlock(&stats->lock); spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return len; return len;
} }
...@@ -742,8 +763,16 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, ...@@ -742,8 +763,16 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count) size_t count)
{ {
struct thermal_cooling_device *cdev = to_cooling_device(dev); struct thermal_cooling_device *cdev = to_cooling_device(dev);
struct cooling_dev_stats *stats = cdev->stats; struct cooling_dev_stats *stats;
int i, states = cdev->max_state + 1; int i, states;
mutex_lock(&cdev->lock);
stats = cdev->stats;
if (!stats)
goto unlock;
states = cdev->max_state + 1;
spin_lock(&stats->lock); spin_lock(&stats->lock);
...@@ -757,6 +786,9 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, ...@@ -757,6 +786,9 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
spin_unlock(&stats->lock); spin_unlock(&stats->lock);
unlock:
mutex_unlock(&cdev->lock);
return count; return count;
} }
...@@ -764,10 +796,18 @@ static ssize_t trans_table_show(struct device *dev, ...@@ -764,10 +796,18 @@ static ssize_t trans_table_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct thermal_cooling_device *cdev = to_cooling_device(dev); 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; ssize_t len = 0;
int i, j; 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, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : "); len += snprintf(buf + len, PAGE_SIZE - len, " : ");
for (i = 0; i <= cdev->max_state; i++) { for (i = 0; i <= cdev->max_state; i++) {
...@@ -775,8 +815,10 @@ static ssize_t trans_table_show(struct device *dev, ...@@ -775,8 +815,10 @@ static ssize_t trans_table_show(struct device *dev,
break; break;
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i); len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
} }
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE) {
return PAGE_SIZE; len = PAGE_SIZE;
goto unlock;
}
len += snprintf(buf + len, PAGE_SIZE - len, "\n"); len += snprintf(buf + len, PAGE_SIZE - len, "\n");
...@@ -799,8 +841,12 @@ static ssize_t trans_table_show(struct device *dev, ...@@ -799,8 +841,12 @@ static ssize_t trans_table_show(struct device *dev,
if (len >= PAGE_SIZE) { if (len >= PAGE_SIZE) {
pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n"); pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
return -EFBIG; len = -EFBIG;
} }
unlock:
mutex_unlock(&cdev->lock);
return len; return len;
} }
...@@ -830,6 +876,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) ...@@ -830,6 +876,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
unsigned long states = cdev->max_state + 1; unsigned long states = cdev->max_state + 1;
int var; int var;
lockdep_assert_held(&cdev->lock);
var = sizeof(*stats); var = sizeof(*stats);
var += sizeof(*stats->time_in_state) * states; var += sizeof(*stats->time_in_state) * states;
var += sizeof(*stats->trans_table) * states * states; var += sizeof(*stats->trans_table) * states * states;
...@@ -855,6 +903,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) ...@@ -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) static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
{ {
lockdep_assert_held(&cdev->lock);
kfree(cdev->stats); kfree(cdev->stats);
cdev->stats = NULL; cdev->stats = NULL;
} }
...@@ -879,6 +929,12 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) ...@@ -879,6 +929,12 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
cooling_device_stats_destroy(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 */ /* these helper will be used only at the time of bindig */
ssize_t ssize_t
trip_point_show(struct device *dev, struct device_attribute *attr, char *buf) 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, ...@@ -384,6 +384,7 @@ devm_thermal_of_cooling_device_register(struct device *dev,
struct device_node *np, struct device_node *np,
char *type, void *devdata, char *type, void *devdata,
const struct thermal_cooling_device_ops *ops); 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 *); void thermal_cooling_device_unregister(struct thermal_cooling_device *);
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); 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); 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