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()
This commit is contained in:
commit
6babf38d89
|
@ -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 */
|
||||
|
|
|
@ -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 @@ out:
|
|||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue