Skip to content

Commit fd3d06f

Browse files
committed
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()
2 parents 1868d19 + 6babf38 commit fd3d06f

File tree

6 files changed

+183
-26
lines changed

6 files changed

+183
-26
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: 98 additions & 8 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 */
@@ -1309,7 +1399,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
13091399
struct thermal_trip trip;
13101400

13111401
result = thermal_zone_get_trip(tz, count, &trip);
1312-
if (result)
1402+
if (result || !trip.temperature)
13131403
set_bit(count, &tz->trips_disabled);
13141404
}
13151405

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)

0 commit comments

Comments
 (0)