Skip to content

Commit 6babf38

Browse files
committed
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()
2 parents f1b80a3 + 22c52fa commit 6babf38

File tree

6 files changed

+182
-25
lines changed

6 files changed

+182
-25
lines changed

drivers/acpi/processor_driver.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ static int __init acpi_processor_driver_init(void)
263263
if (acpi_disabled)
264264
return 0;
265265

266+
if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
267+
CPUFREQ_POLICY_NOTIFIER)) {
268+
acpi_processor_cpufreq_init = true;
269+
acpi_processor_ignore_ppc_init();
270+
}
271+
266272
result = driver_register(&acpi_processor_driver);
267273
if (result < 0)
268274
return result;
@@ -276,12 +282,6 @@ static int __init acpi_processor_driver_init(void)
276282
cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
277283
NULL, acpi_soft_cpu_dead);
278284

279-
if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
280-
CPUFREQ_POLICY_NOTIFIER)) {
281-
acpi_processor_cpufreq_init = true;
282-
acpi_processor_ignore_ppc_init();
283-
}
284-
285285
acpi_processor_throttling_init();
286286
return 0;
287287
err:

drivers/acpi/processor_thermal.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,13 @@ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
140140
ret = freq_qos_add_request(&policy->constraints,
141141
&pr->thermal_req,
142142
FREQ_QOS_MAX, INT_MAX);
143-
if (ret < 0)
143+
if (ret < 0) {
144144
pr_err("Failed to add freq constraint for CPU%d (%d)\n",
145145
cpu, ret);
146+
continue;
147+
}
148+
149+
thermal_cooling_device_update(pr->cdev);
146150
}
147151
}
148152

@@ -153,8 +157,12 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
153157
for_each_cpu(cpu, policy->related_cpus) {
154158
struct acpi_processor *pr = per_cpu(processors, cpu);
155159

156-
if (pr)
157-
freq_qos_remove_request(&pr->thermal_req);
160+
if (!pr)
161+
continue;
162+
163+
freq_qos_remove_request(&pr->thermal_req);
164+
165+
thermal_cooling_device_update(pr->cdev);
158166
}
159167
}
160168
#else /* ! CONFIG_CPU_FREQ */

drivers/thermal/thermal_core.c

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
613613
struct thermal_instance *pos;
614614
struct thermal_zone_device *pos1;
615615
struct thermal_cooling_device *pos2;
616+
bool upper_no_limit;
616617
int result;
617618

618619
if (trip >= tz->num_trips || trip < 0)
@@ -632,7 +633,13 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
632633

633634
/* lower default 0, upper default max_state */
634635
lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
635-
upper = upper == THERMAL_NO_LIMIT ? cdev->max_state : upper;
636+
637+
if (upper == THERMAL_NO_LIMIT) {
638+
upper = cdev->max_state;
639+
upper_no_limit = true;
640+
} else {
641+
upper_no_limit = false;
642+
}
636643

637644
if (lower > upper || upper > cdev->max_state)
638645
return -EINVAL;
@@ -644,6 +651,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
644651
dev->cdev = cdev;
645652
dev->trip = trip;
646653
dev->upper = upper;
654+
dev->upper_no_limit = upper_no_limit;
647655
dev->lower = lower;
648656
dev->target = THERMAL_NO_TARGET;
649657
dev->weight = weight;
@@ -1045,6 +1053,91 @@ devm_thermal_of_cooling_device_register(struct device *dev,
10451053
}
10461054
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
10471055

1056+
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
1057+
{
1058+
struct thermal_cooling_device *pos = NULL;
1059+
1060+
list_for_each_entry(pos, &thermal_cdev_list, node) {
1061+
if (pos == cdev)
1062+
return true;
1063+
}
1064+
1065+
return false;
1066+
}
1067+
1068+
/**
1069+
* thermal_cooling_device_update - Update a cooling device object
1070+
* @cdev: Target cooling device.
1071+
*
1072+
* Update @cdev to reflect a change of the underlying hardware or platform.
1073+
*
1074+
* Must be called when the maximum cooling state of @cdev becomes invalid and so
1075+
* its .get_max_state() callback needs to be run to produce the new maximum
1076+
* cooling state value.
1077+
*/
1078+
void thermal_cooling_device_update(struct thermal_cooling_device *cdev)
1079+
{
1080+
struct thermal_instance *ti;
1081+
unsigned long state;
1082+
1083+
if (IS_ERR_OR_NULL(cdev))
1084+
return;
1085+
1086+
/*
1087+
* Hold thermal_list_lock throughout the update to prevent the device
1088+
* from going away while being updated.
1089+
*/
1090+
mutex_lock(&thermal_list_lock);
1091+
1092+
if (!thermal_cooling_device_present(cdev))
1093+
goto unlock_list;
1094+
1095+
/*
1096+
* Update under the cdev lock to prevent the state from being set beyond
1097+
* the new limit concurrently.
1098+
*/
1099+
mutex_lock(&cdev->lock);
1100+
1101+
if (cdev->ops->get_max_state(cdev, &cdev->max_state))
1102+
goto unlock;
1103+
1104+
thermal_cooling_device_stats_reinit(cdev);
1105+
1106+
list_for_each_entry(ti, &cdev->thermal_instances, cdev_node) {
1107+
if (ti->upper == cdev->max_state)
1108+
continue;
1109+
1110+
if (ti->upper < cdev->max_state) {
1111+
if (ti->upper_no_limit)
1112+
ti->upper = cdev->max_state;
1113+
1114+
continue;
1115+
}
1116+
1117+
ti->upper = cdev->max_state;
1118+
if (ti->lower > ti->upper)
1119+
ti->lower = ti->upper;
1120+
1121+
if (ti->target == THERMAL_NO_TARGET)
1122+
continue;
1123+
1124+
if (ti->target > ti->upper)
1125+
ti->target = ti->upper;
1126+
}
1127+
1128+
if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state)
1129+
goto unlock;
1130+
1131+
thermal_cooling_device_stats_update(cdev, state);
1132+
1133+
unlock:
1134+
mutex_unlock(&cdev->lock);
1135+
1136+
unlock_list:
1137+
mutex_unlock(&thermal_list_lock);
1138+
}
1139+
EXPORT_SYMBOL_GPL(thermal_cooling_device_update);
1140+
10481141
static void __unbind(struct thermal_zone_device *tz, int mask,
10491142
struct thermal_cooling_device *cdev)
10501143
{
@@ -1067,20 +1160,17 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
10671160
int i;
10681161
const struct thermal_zone_params *tzp;
10691162
struct thermal_zone_device *tz;
1070-
struct thermal_cooling_device *pos = NULL;
10711163

10721164
if (!cdev)
10731165
return;
10741166

10751167
mutex_lock(&thermal_list_lock);
1076-
list_for_each_entry(pos, &thermal_cdev_list, node)
1077-
if (pos == cdev)
1078-
break;
1079-
if (pos != cdev) {
1080-
/* thermal cooling device not found */
1168+
1169+
if (!thermal_cooling_device_present(cdev)) {
10811170
mutex_unlock(&thermal_list_lock);
10821171
return;
10831172
}
1173+
10841174
list_del(&cdev->node);
10851175

10861176
/* Unbind all thermal zones associated with 'this' cdev */

drivers/thermal/thermal_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ struct thermal_instance {
101101
struct list_head tz_node; /* node in tz->thermal_instances */
102102
struct list_head cdev_node; /* node in cdev->thermal_instances */
103103
unsigned int weight; /* The weight of the cooling device */
104+
bool upper_no_limit;
104105
};
105106

106107
#define to_thermal_zone(_dev) \
@@ -127,6 +128,7 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
127128
void thermal_zone_destroy_device_groups(struct thermal_zone_device *);
128129
void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *);
129130
void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev);
131+
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev);
130132
/* used only at binding time */
131133
ssize_t trip_point_show(struct device *, struct device_attribute *, char *);
132134
ssize_t weight_show(struct device *, struct device_attribute *, char *);

drivers/thermal/thermal_sysfs.c

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,8 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
685685
{
686686
struct cooling_dev_stats *stats = cdev->stats;
687687

688+
lockdep_assert_held(&cdev->lock);
689+
688690
if (!stats)
689691
return;
690692

@@ -706,13 +708,22 @@ static ssize_t total_trans_show(struct device *dev,
706708
struct device_attribute *attr, char *buf)
707709
{
708710
struct thermal_cooling_device *cdev = to_cooling_device(dev);
709-
struct cooling_dev_stats *stats = cdev->stats;
710-
int ret;
711+
struct cooling_dev_stats *stats;
712+
int ret = 0;
713+
714+
mutex_lock(&cdev->lock);
715+
716+
stats = cdev->stats;
717+
if (!stats)
718+
goto unlock;
711719

712720
spin_lock(&stats->lock);
713721
ret = sprintf(buf, "%u\n", stats->total_trans);
714722
spin_unlock(&stats->lock);
715723

724+
unlock:
725+
mutex_unlock(&cdev->lock);
726+
716727
return ret;
717728
}
718729

@@ -721,11 +732,18 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
721732
char *buf)
722733
{
723734
struct thermal_cooling_device *cdev = to_cooling_device(dev);
724-
struct cooling_dev_stats *stats = cdev->stats;
735+
struct cooling_dev_stats *stats;
725736
ssize_t len = 0;
726737
int i;
727738

739+
mutex_lock(&cdev->lock);
740+
741+
stats = cdev->stats;
742+
if (!stats)
743+
goto unlock;
744+
728745
spin_lock(&stats->lock);
746+
729747
update_time_in_state(stats);
730748

731749
for (i = 0; i <= cdev->max_state; i++) {
@@ -734,6 +752,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
734752
}
735753
spin_unlock(&stats->lock);
736754

755+
unlock:
756+
mutex_unlock(&cdev->lock);
757+
737758
return len;
738759
}
739760

@@ -742,8 +763,16 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
742763
size_t count)
743764
{
744765
struct thermal_cooling_device *cdev = to_cooling_device(dev);
745-
struct cooling_dev_stats *stats = cdev->stats;
746-
int i, states = cdev->max_state + 1;
766+
struct cooling_dev_stats *stats;
767+
int i, states;
768+
769+
mutex_lock(&cdev->lock);
770+
771+
stats = cdev->stats;
772+
if (!stats)
773+
goto unlock;
774+
775+
states = cdev->max_state + 1;
747776

748777
spin_lock(&stats->lock);
749778

@@ -757,26 +786,39 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
757786

758787
spin_unlock(&stats->lock);
759788

789+
unlock:
790+
mutex_unlock(&cdev->lock);
791+
760792
return count;
761793
}
762794

763795
static ssize_t trans_table_show(struct device *dev,
764796
struct device_attribute *attr, char *buf)
765797
{
766798
struct thermal_cooling_device *cdev = to_cooling_device(dev);
767-
struct cooling_dev_stats *stats = cdev->stats;
799+
struct cooling_dev_stats *stats;
768800
ssize_t len = 0;
769801
int i, j;
770802

803+
mutex_lock(&cdev->lock);
804+
805+
stats = cdev->stats;
806+
if (!stats) {
807+
len = -ENODATA;
808+
goto unlock;
809+
}
810+
771811
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
772812
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
773813
for (i = 0; i <= cdev->max_state; i++) {
774814
if (len >= PAGE_SIZE)
775815
break;
776816
len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
777817
}
778-
if (len >= PAGE_SIZE)
779-
return PAGE_SIZE;
818+
if (len >= PAGE_SIZE) {
819+
len = PAGE_SIZE;
820+
goto unlock;
821+
}
780822

781823
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
782824

@@ -799,8 +841,12 @@ static ssize_t trans_table_show(struct device *dev,
799841

800842
if (len >= PAGE_SIZE) {
801843
pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
802-
return -EFBIG;
844+
len = -EFBIG;
803845
}
846+
847+
unlock:
848+
mutex_unlock(&cdev->lock);
849+
804850
return len;
805851
}
806852

@@ -830,6 +876,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
830876
unsigned long states = cdev->max_state + 1;
831877
int var;
832878

879+
lockdep_assert_held(&cdev->lock);
880+
833881
var = sizeof(*stats);
834882
var += sizeof(*stats->time_in_state) * states;
835883
var += sizeof(*stats->trans_table) * states * states;
@@ -855,6 +903,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
855903

856904
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
857905
{
906+
lockdep_assert_held(&cdev->lock);
907+
858908
kfree(cdev->stats);
859909
cdev->stats = NULL;
860910
}
@@ -879,6 +929,12 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
879929
cooling_device_stats_destroy(cdev);
880930
}
881931

932+
void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev)
933+
{
934+
cooling_device_stats_destroy(cdev);
935+
cooling_device_stats_setup(cdev);
936+
}
937+
882938
/* these helper will be used only at the time of bindig */
883939
ssize_t
884940
trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)

include/linux/thermal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ devm_thermal_of_cooling_device_register(struct device *dev,
384384
struct device_node *np,
385385
char *type, void *devdata,
386386
const struct thermal_cooling_device_ops *ops);
387+
void thermal_cooling_device_update(struct thermal_cooling_device *);
387388
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
388389
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
389390
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);

0 commit comments

Comments
 (0)