History

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

Pull thermal control updates from Rafael Wysocki: "These are thermal core changes, including the addition of support for temperature thresholds that can be set from user space, fixes related to thermal zone initialization, suspend/resume and exit, locking rework and rearrangement of the code handling thermal zone temperature updates. Specifics: - Add support for thermal thresholds that can be added and removed from user space via netlink along with a related library update (Daniel Lezcano) - Fix thermal zone initialization, suspend/resume and exit synchronization issues (Rafael Wysocki) - Rearrange locking in the thermal core to use guards (Rafael Wysocki) - Make the code handling thermal zone temperature updates use sorted lists of trip points to reduce the number of trip points table walks in the thermal core (Rafael Wysocki) - Fix and clean up the thermal testing facility code (Rafael Wysocki) - Fix a Power Allocator thermal governor issue (ZhengShaobo)" * tag 'thermal-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (45 commits) thermal: testing: Initialize some variables annoteded with _free() thermal: testing: Use DEFINE_FREE() and __free() to simplify code thermal: testing: Simplify tt_get_tt_zone() thermal: gov_power_allocator: Granted power set to max when nobody request power thermal: core: Relocate thermal zone initialization routine thermal: core: Use trip lists for trip crossing detection thermal: core: Eliminate thermal_zone_trip_down() thermal: core: Relocate functions that update trip points thermal: core: Move some trip processing to thermal_trip_crossed() thermal: core: Pass trip descriptor to thermal_trip_crossed() thermal: core: Rearrange __thermal_zone_device_update() thermal: core: Prepare for moving trips between sorted lists thermal: core: Rename trip list node in struct thermal_trip_desc thermal: core: Build sorted lists instead of sorting them later thermal/lib: Fix memory leak on error in thermal_genl_auto() thermal: thresholds: Fix thermal lock annotation issue tools/thermal/thermal-engine: Take into account the thresholds API tools/lib/thermal: Add the threshold netlink ABI tools/lib/thermal: Make more generic the command encoding function thermal: netlink: Add the commands and the events for the thresholds ...

Linus Torvalds committed 1 year ago

Commit cd7fa3e2 parents ad52c55 0104dcd26 files · +1650 −733Browse files

Unified · Split

26 files
  1. drivers/thermal/Makefile +1 −0
  2. drivers/thermal/gov_bang_bang.c +6 −9
  3. drivers/thermal/gov_fair_share.c +6 −14
  4. drivers/thermal/gov_power_allocator.c +46 −40
  5. drivers/thermal/gov_step_wise.c +11 −11
  6. drivers/thermal/testing/zone.c +15 −26
  7. drivers/thermal/thermal_core.c +503 −380
  8. drivers/thermal/thermal_core.h +28 −13
  9. drivers/thermal/thermal_debugfs.c +30 −20
  10. drivers/thermal/thermal_helpers.c +23 −23
  11. drivers/thermal/thermal_hwmon.c +1 −4
  12. drivers/thermal/thermal_netlink.c +232 −21
  13. drivers/thermal/thermal_netlink.h +34 −0
  14. drivers/thermal/thermal_sysfs.c +53 −79
  15. drivers/thermal/thermal_thresholds.c +240 −0
  16. drivers/thermal/thermal_thresholds.h +19 −0
  17. drivers/thermal/thermal_trip.c +2 −46
  18. include/linux/thermal.h +6 −0
  19. include/uapi/linux/thermal.h +22 −7
  20. tools/lib/thermal/commands.c +175 −13
  21. tools/lib/thermal/events.c +42 −13
  22. tools/lib/thermal/include/thermal.h +40 −0
  23. tools/lib/thermal/libthermal.map +5 −0
  24. tools/lib/thermal/thermal.c +17 −0
  25. tools/thermal/lib/Makefile +1 −1
  26. tools/thermal/thermal-engine/thermal-engine.c +92 −13
drivers/thermal/Makefile+1−0
@@ -6,6 +6,7 @@ CFLAGS_thermal_core.o := -I$(src) · 5 unmodified lines
66 obj-$(CONFIG_THERMAL) += thermal_sys.o
77 thermal_sys-y += thermal_core.o thermal_sysfs.o
88 thermal_sys-y += thermal_trip.o thermal_helpers.o
9+thermal_sys-y += thermal_thresholds.o
910
1011 # netlink interface to manage the thermal framework
1112 thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
drivers/thermal/gov_bang_bang.c+6−9
@@ -30,9 +30,7 @@ static void bang_bang_set_instance_target(struct thermal_instance *instance, · 29 unmodified lines
3030
3131 dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);
3232
33− mutex_lock(&instance->cdev->lock);
34− __thermal_cdev_update(instance->cdev);
35− mutex_unlock(&instance->cdev->lock);
33+ thermal_cdev_update_nocheck(instance->cdev);
3634 }
3735
3836 /**
@@ -67,6 +65,7 @@ static void bang_bang_control(struct thermal_zone_device *tz, · 28 unmodified lines
6765 const struct thermal_trip *trip,
6866 bool crossed_up)
6967 {
68+ const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
7069 struct thermal_instance *instance;
7170
7271 lockdep_assert_held(&tz->lock);
@@ -75,10 +74,8 @@ static void bang_bang_control(struct thermal_zone_device *tz, · 2 unmodified lines
7574 thermal_zone_trip_id(tz, trip), trip->temperature,
7675 tz->temperature, trip->hysteresis);
7776
78− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
79− if (instance->trip == trip)
80− bang_bang_set_instance_target(instance, crossed_up);
81− }
77+ list_for_each_entry(instance, &td->thermal_instances, trip_node)
78+ bang_bang_set_instance_target(instance, crossed_up);
8279 }
8380
8481 static void bang_bang_manage(struct thermal_zone_device *tz)
@@ -104,8 +101,8 @@ static void bang_bang_manage(struct thermal_zone_device *tz) · 19 unmodified lines
104101 * to the thermal zone temperature and the trip point threshold.
105102 */
106103 turn_on = tz->temperature >= td->threshold;
107− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
108− if (!instance->initialized && instance->trip == trip)
104+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
105+ if (!instance->initialized)
109106 bang_bang_set_instance_target(instance, turn_on);
110107 }
111108 }
drivers/thermal/gov_fair_share.c+6−14
@@ -44,7 +44,7 @@ static int get_trip_level(struct thermal_zone_device *tz) · 43 unmodified lines
4444 /**
4545 * fair_share_throttle - throttles devices associated with the given zone
4646 * @tz: thermal_zone_device
47− * @trip: trip point
47+ * @td: trip point descriptor
4848 * @trip_level: number of trips crossed by the zone temperature
4949 *
5050 * Throttling Logic: This uses three parameters to calculate the new
@@ -61,29 +61,23 @@ static int get_trip_level(struct thermal_zone_device *tz) · 10 unmodified lines
6161 * new_state of cooling device = P3 * P2 * P1
6262 */
6363 static void fair_share_throttle(struct thermal_zone_device *tz,
64− const struct thermal_trip *trip,
64+ const struct thermal_trip_desc *td,
6565 int trip_level)
6666 {
6767 struct thermal_instance *instance;
6868 int total_weight = 0;
6969 int nr_instances = 0;
7070
71− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
72− if (instance->trip != trip)
73− continue;
74−
71+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
7572 total_weight += instance->weight;
7673 nr_instances++;
7774 }
7875
79− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
76+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
8077 struct thermal_cooling_device *cdev = instance->cdev;
8178 u64 dividend;
8279 u32 divisor;
8380
84− if (instance->trip != trip)
85− continue;
86−
8781 dividend = trip_level;
8882 dividend *= cdev->max_state;
8983 divisor = tz->num_trips;
@@ -95,9 +89,7 @@ static void fair_share_throttle(struct thermal_zone_device *tz, · 5 unmodified lines
9589 }
9690 instance->target = div_u64(dividend, divisor);
9791
98− mutex_lock(&cdev->lock);
99− __thermal_cdev_update(cdev);
100− mutex_unlock(&cdev->lock);
92+ thermal_cdev_update_nocheck(cdev);
10193 }
10294 }
10395
@@ -116,7 +108,7 @@ static void fair_share_manage(struct thermal_zone_device *tz) · 12 unmodified lines
116108 trip->type == THERMAL_TRIP_HOT)
117109 continue;
118110
119− fair_share_throttle(tz, trip, trip_level);
111+ fair_share_throttle(tz, td, trip_level);
120112 }
121113 }
122114
drivers/thermal/gov_power_allocator.c+46−40
@@ -97,11 +97,9 @@ struct power_allocator_params { · 96 unmodified lines
9797 struct power_actor *power;
9898 };
9999
100−static bool power_actor_is_valid(struct power_allocator_params *params,
101− struct thermal_instance *instance)
100+static bool power_actor_is_valid(struct thermal_instance *instance)
102101 {
103− return (instance->trip == params->trip_max &&
104− cdev_is_power_actor(instance->cdev));
102+ return cdev_is_power_actor(instance->cdev);
105103 }
106104
107105 /**
@@ -118,13 +116,14 @@ static bool power_actor_is_valid(struct power_allocator_params *params, · 10 unmodified lines
118116 static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
119117 {
120118 struct power_allocator_params *params = tz->governor_data;
119+ const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
121120 struct thermal_cooling_device *cdev;
122121 struct thermal_instance *instance;
123122 u32 sustainable_power = 0;
124123 u32 min_power;
125124
126− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
127− if (!power_actor_is_valid(params, instance))
125+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
126+ if (!power_actor_is_valid(instance))
128127 continue;
129128
130129 cdev = instance->cdev;
@@ -323,9 +322,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev, · 192 unmodified lines
323322 return ret;
324323
325324 instance->target = clamp_val(state, instance->lower, instance->upper);
326− mutex_lock(&cdev->lock);
327− __thermal_cdev_update(cdev);
328− mutex_unlock(&cdev->lock);
325+
326+ thermal_cdev_update_nocheck(cdev);
329327
330328 return 0;
331329 }
@@ -356,11 +354,19 @@ static void divvy_up_power(struct power_actor *power, int num_actors, · 24 unmodified lines
356354 u32 extra_power = 0;
357355 int i;
358356
359− /*
360− * Prevent division by 0 if none of the actors request power.
361− */
362− if (!total_req_power)
363− total_req_power = 1;
357+ if (!total_req_power) {
358+ /*
359+ * Nobody requested anything, just give everybody
360+ * the maximum power
361+ */
362+ for (i = 0; i < num_actors; i++) {
363+ struct power_actor *pa = &power[i];
364+
365+ pa->granted_power = pa->max_power;
366+ }
367+
368+ return;
369+ }
364370
365371 for (i = 0; i < num_actors; i++) {
366372 struct power_actor *pa = &power[i];
@@ -400,6 +406,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors, · 33 unmodified lines
400406 static void allocate_power(struct thermal_zone_device *tz, int control_temp)
401407 {
402408 struct power_allocator_params *params = tz->governor_data;
409+ const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
403410 unsigned int num_actors = params->num_actors;
404411 struct power_actor *power = params->power;
405412 struct thermal_cooling_device *cdev;
@@ -417,10 +424,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) · 11 unmodified lines
417424 /* Clean all buffers for new power estimations */
418425 memset(power, 0, params->buffer_size);
419426
420− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
427+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
421428 struct power_actor *pa = &power[i];
422429
423− if (!power_actor_is_valid(params, instance))
430+ if (!power_actor_is_valid(instance))
424431 continue;
425432
426433 cdev = instance->cdev;
@@ -454,10 +461,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) · 27 unmodified lines
454461 power_range);
455462
456463 i = 0;
457− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
464+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
458465 struct power_actor *pa = &power[i];
459466
460− if (!power_actor_is_valid(params, instance))
467+ if (!power_actor_is_valid(instance))
461468 continue;
462469
463470 power_actor_set_power(instance->cdev, instance,
@@ -538,29 +545,29 @@ static void reset_pid_controller(struct power_allocator_params *params) · 74 unmodified lines
538545 static void allow_maximum_power(struct thermal_zone_device *tz)
539546 {
540547 struct power_allocator_params *params = tz->governor_data;
548+ const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
541549 struct thermal_cooling_device *cdev;
542550 struct thermal_instance *instance;
543551 u32 req_power;
544552
545− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
546− if (!power_actor_is_valid(params, instance))
553+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
554+ if (!power_actor_is_valid(instance))
547555 continue;
548556
549557 cdev = instance->cdev;
550558
551559 instance->target = 0;
552− mutex_lock(&cdev->lock);
553− /*
554− * Call for updating the cooling devices local stats and avoid
555− * periods of dozen of seconds when those have not been
556− * maintained.
557− */
558− cdev->ops->get_requested_power(cdev, &req_power);
559−
560− if (params->update_cdevs)
561− __thermal_cdev_update(cdev);
562−
563− mutex_unlock(&cdev->lock);
560+ scoped_guard(cooling_dev, cdev) {
561+ /*
562+ * Call for updating the cooling devices local stats and
563+ * avoid periods of dozen of seconds when those have not
564+ * been maintained.
565+ */
566+ cdev->ops->get_requested_power(cdev, &req_power);
567+
568+ if (params->update_cdevs)
569+ __thermal_cdev_update(cdev);
570+ }
564571 }
565572 }
566573
@@ -581,13 +588,11 @@ static void allow_maximum_power(struct thermal_zone_device *tz) · 14 unmodified lines
581588 static int check_power_actors(struct thermal_zone_device *tz,
582589 struct power_allocator_params *params)
583590 {
591+ const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
584592 struct thermal_instance *instance;
585593 int ret = 0;
586594
587− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
588− if (instance->trip != params->trip_max)
589− continue;
590−
595+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
591596 if (!cdev_is_power_actor(instance->cdev)) {
592597 dev_warn(&tz->device, "power_allocator: %s is not a power actor\n",
593598 instance->cdev->type);
@@ -635,14 +640,15 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, · 41 unmodified lines
635640 enum thermal_notify_event reason)
636641 {
637642 struct power_allocator_params *params = tz->governor_data;
643+ const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
638644 struct thermal_instance *instance;
639645 int num_actors = 0;
640646
641647 switch (reason) {
642648 case THERMAL_TZ_BIND_CDEV:
643649 case THERMAL_TZ_UNBIND_CDEV:
644− list_for_each_entry(instance, &tz->thermal_instances, tz_node)
645− if (power_actor_is_valid(params, instance))
650+ list_for_each_entry(instance, &td->thermal_instances, trip_node)
651+ if (power_actor_is_valid(instance))
646652 num_actors++;
647653
648654 if (num_actors == params->num_actors)
@@ -652,8 +658,8 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, · 3 unmodified lines
652658 break;
653659 case THERMAL_INSTANCE_WEIGHT_CHANGED:
654660 params->total_weight = 0;
655− list_for_each_entry(instance, &tz->thermal_instances, tz_node)
656− if (power_actor_is_valid(params, instance))
661+ list_for_each_entry(instance, &td->thermal_instances, trip_node)
662+ if (power_actor_is_valid(instance))
657663 params->total_weight += instance->weight;
658664 break;
659665 default:
drivers/thermal/gov_step_wise.c+11−11
@@ -66,9 +66,10 @@ static unsigned long get_target_state(struct thermal_instance *instance, · 65 unmodified lines
6666 }
6767
6868 static void thermal_zone_trip_update(struct thermal_zone_device *tz,
69− const struct thermal_trip *trip,
69+ const struct thermal_trip_desc *td,
7070 int trip_threshold)
7171 {
72+ const struct thermal_trip *trip = &td->trip;
7273 enum thermal_trend trend = get_tz_trend(tz, trip);
7374 int trip_id = thermal_zone_trip_id(tz, trip);
7475 struct thermal_instance *instance;
@@ -82,12 +83,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, · 7 unmodified lines
8283 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
8384 trip_id, trip->type, trip_threshold, trend, throttle);
8485
85− list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
86+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
8687 int old_target;
8788
88− if (instance->trip != trip)
89− continue;
90−
9189 old_target = instance->target;
9290 instance->target = get_target_state(instance, trend, throttle);
9391
@@ -99,9 +97,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, · 5 unmodified lines
9997
10098 instance->initialized = true;
10199
102− mutex_lock(&instance->cdev->lock);
103− instance->cdev->updated = false; /* cdev needs update */
104− mutex_unlock(&instance->cdev->lock);
100+ scoped_guard(cooling_dev, instance->cdev) {
101+ instance->cdev->updated = false; /* cdev needs update */
102+ }
105103 }
106104 }
107105
@@ -127,11 +125,13 @@ static void step_wise_manage(struct thermal_zone_device *tz) · 19 unmodified lines
127125 trip->type == THERMAL_TRIP_HOT)
128126 continue;
129127
130− thermal_zone_trip_update(tz, trip, td->threshold);
128+ thermal_zone_trip_update(tz, td, td->threshold);
131129 }
132130
133− list_for_each_entry(instance, &tz->thermal_instances, tz_node)
134− thermal_cdev_update(instance->cdev);
131+ for_each_trip_desc(tz, td) {
132+ list_for_each_entry(instance, &td->thermal_instances, trip_node)
133+ thermal_cdev_update(instance->cdev);
134+ }
135135 }
136136
137137 static struct thermal_governor thermal_gov_step_wise = {
drivers/thermal/testing/zone.c+15−26
@@ -185,7 +185,7 @@ static void tt_add_tz_work_fn(struct work_struct *work) · 184 unmodified lines
185185 int tt_add_tz(void)
186186 {
187187 struct tt_thermal_zone *tt_zone __free(kfree);
188− struct tt_work *tt_work __free(kfree);
188+ struct tt_work *tt_work __free(kfree) = NULL;
189189 int ret;
190190
191191 tt_zone = kzalloc(sizeof(*tt_zone), GFP_KERNEL);
@@ -237,7 +237,7 @@ static void tt_zone_unregister_tz(struct tt_thermal_zone *tt_zone) · 45 unmodified lines
237237
238238 int tt_del_tz(const char *arg)
239239 {
240− struct tt_work *tt_work __free(kfree);
240+ struct tt_work *tt_work __free(kfree) = NULL;
241241 struct tt_thermal_zone *tt_zone, *aux;
242242 int ret;
243243 int id;
@@ -288,19 +288,14 @@ static struct tt_thermal_zone *tt_get_tt_zone(const char *arg) · 44 unmodified lines
288288
289289 guard(mutex)(&tt_thermal_zones_lock);
290290
291− ret = -EINVAL;
292291 list_for_each_entry(tt_zone, &tt_thermal_zones, list_node) {
293292 if (tt_zone->id == id) {
294293 tt_zone->refcount++;
295− ret = 0;
296− break;
294+ return tt_zone;
297295 }
298296 }
299297
300− if (ret)
301− return ERR_PTR(ret);
302−
303− return tt_zone;
298+ return ERR_PTR(-EINVAL);
304299 }
305300
306301 static void tt_put_tt_zone(struct tt_thermal_zone *tt_zone)
@@ -310,6 +305,9 @@ static void tt_put_tt_zone(struct tt_thermal_zone *tt_zone) · 3 unmodified lines
310305 tt_zone->refcount--;
311306 }
312307
308+DEFINE_FREE(put_tt_zone, struct tt_thermal_zone *,
309+ if (!IS_ERR_OR_NULL(_T)) tt_put_tt_zone(_T))
310+
313311 static void tt_zone_add_trip_work_fn(struct work_struct *work)
314312 {
315313 struct tt_work *tt_work = tt_work_of_work(work);
@@ -332,9 +330,9 @@ static void tt_zone_add_trip_work_fn(struct work_struct *work) · 16 unmodified lines
332330
333331 int tt_zone_add_trip(const char *arg)
334332 {
333+ struct tt_thermal_zone *tt_zone __free(put_tt_zone) = NULL;
334+ struct tt_trip *tt_trip __free(kfree) = NULL;
335335 struct tt_work *tt_work __free(kfree);
336− struct tt_trip *tt_trip __free(kfree);
337− struct tt_thermal_zone *tt_zone;
338336 int id;
339337
340338 tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL);
@@ -350,10 +348,8 @@ int tt_zone_add_trip(const char *arg) · 9 unmodified lines
350348 return PTR_ERR(tt_zone);
351349
352350 id = ida_alloc(&tt_zone->ida, GFP_KERNEL);
353− if (id < 0) {
354− tt_put_tt_zone(tt_zone);
351+ if (id < 0)
355352 return id;
356− }
357353
358354 tt_trip->trip.type = THERMAL_TRIP_ACTIVE;
359355 tt_trip->trip.temperature = THERMAL_TEMP_INVALID;
@@ -366,7 +362,7 @@ int tt_zone_add_trip(const char *arg) · 6 unmodified lines
366362 tt_zone->num_trips++;
367363
368364 INIT_WORK(&tt_work->work, tt_zone_add_trip_work_fn);
369− tt_work->tt_zone = tt_zone;
365+ tt_work->tt_zone = no_free_ptr(tt_zone);
370366 tt_work->tt_trip = no_free_ptr(tt_trip);
371367 schedule_work(&(no_free_ptr(tt_work)->work));
372368
@@ -391,7 +387,7 @@ static struct thermal_zone_device_ops tt_zone_ops = { · 18 unmodified lines
391387
392388 static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone)
393389 {
394− struct thermal_trip *trips __free(kfree);
390+ struct thermal_trip *trips __free(kfree) = NULL;
395391 struct thermal_zone_device *tz;
396392 struct tt_trip *tt_trip;
397393 int i;
@@ -425,23 +421,18 @@ static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) · 27 unmodified lines
425421
426422 int tt_zone_reg(const char *arg)
427423 {
428− struct tt_thermal_zone *tt_zone;
429− int ret;
424+ struct tt_thermal_zone *tt_zone __free(put_tt_zone);
430425
431426 tt_zone = tt_get_tt_zone(arg);
432427 if (IS_ERR(tt_zone))
433428 return PTR_ERR(tt_zone);
434429
435− ret = tt_zone_register_tz(tt_zone);
436−
437− tt_put_tt_zone(tt_zone);
438−
439− return ret;
430+ return tt_zone_register_tz(tt_zone);
440431 }
441432
442433 int tt_zone_unreg(const char *arg)
443434 {
444− struct tt_thermal_zone *tt_zone;
435+ struct tt_thermal_zone *tt_zone __free(put_tt_zone);
445436
446437 tt_zone = tt_get_tt_zone(arg);
447438 if (IS_ERR(tt_zone))
@@ -449,8 +440,6 @@ int tt_zone_unreg(const char *arg) · 1 unmodified line
449440
450441 tt_zone_unregister_tz(tt_zone);
451442
452− tt_put_tt_zone(tt_zone);
453−
454443 return 0;
455444 }
456445
drivers/thermal/thermal_core.c+503−380
@@ -15,7 +15,6 @@ · 14 unmodified lines
1515 #include <linux/slab.h>
1616 #include <linux/kdev_t.h>
1717 #include <linux/idr.h>
18−#include <linux/list_sort.h>
1918 #include <linux/thermal.h>
2019 #include <linux/reboot.h>
2120 #include <linux/string.h>
@@ -40,6 +39,8 @@ static DEFINE_MUTEX(thermal_governor_lock); · 18 unmodified lines
4039
4140 static struct thermal_governor *def_governor;
4241
42+static bool thermal_pm_suspended;
43+
4344 /*
4445 * Governor section: set of functions to handle thermal governors
4546 *
@@ -122,7 +123,7 @@ int thermal_register_governor(struct thermal_governor *governor) · 76 unmodified lines
122123 if (!governor)
123124 return -EINVAL;
124125
125− mutex_lock(&thermal_governor_lock);
126+ guard(mutex)(&thermal_governor_lock);
126127
127128 err = -EBUSY;
128129 if (!__find_governor(governor->name)) {
@@ -138,7 +139,7 @@ int thermal_register_governor(struct thermal_governor *governor) · 9 unmodified lines
138139 def_governor = governor;
139140 }
140141
141− mutex_lock(&thermal_list_lock);
142+ guard(mutex)(&thermal_list_lock);
142143
143144 list_for_each_entry(pos, &thermal_tz_list, node) {
144145 /*
@@ -161,9 +162,6 @@ int thermal_register_governor(struct thermal_governor *governor) · 16 unmodified lines
161162 }
162163 }
163164
164− mutex_unlock(&thermal_list_lock);
165− mutex_unlock(&thermal_governor_lock);
166−
167165 return err;
168166 }
169167
@@ -174,23 +172,20 @@ void thermal_unregister_governor(struct thermal_governor *governor) · 4 unmodified lines
174172 if (!governor)
175173 return;
176174
177− mutex_lock(&thermal_governor_lock);
175+ guard(mutex)(&thermal_governor_lock);
178176
179177 if (!__find_governor(governor->name))
180− goto exit;
178+ return;
181179
182− mutex_lock(&thermal_list_lock);
180+ list_del(&governor->governor_list);
181+
182+ guard(mutex)(&thermal_list_lock);
183183
184184 list_for_each_entry(pos, &thermal_tz_list, node) {
185185 if (!strncasecmp(pos->governor->name, governor->name,
186186 THERMAL_NAME_LENGTH))
187187 thermal_set_governor(pos, NULL);
188188 }
189−
190− mutex_unlock(&thermal_list_lock);
191− list_del(&governor->governor_list);
192−exit:
193− mutex_unlock(&thermal_governor_lock);
194189 }
195190
196191 int thermal_zone_device_set_policy(struct thermal_zone_device *tz,
@@ -199,18 +194,12 @@ int thermal_zone_device_set_policy(struct thermal_zone_device *tz, · 2 unmodified lines
199194 struct thermal_governor *gov;
200195 int ret = -EINVAL;
201196
202− mutex_lock(&thermal_governor_lock);
203− mutex_lock(&tz->lock);
197+ guard(mutex)(&thermal_governor_lock);
198+ guard(thermal_zone)(tz);
204199
205200 gov = __find_governor(strim(policy));
206− if (!gov)
207− goto exit;
208−
209− ret = thermal_set_governor(tz, gov);
210−
211−exit:
212− mutex_unlock(&tz->lock);
213− mutex_unlock(&thermal_governor_lock);
201+ if (gov)
202+ ret = thermal_set_governor(tz, gov);
214203
215204 thermal_notify_tz_gov_change(tz, policy);
216205
@@ -222,15 +211,13 @@ int thermal_build_list_of_policies(char *buf) · 5 unmodified lines
222211 struct thermal_governor *pos;
223212 ssize_t count = 0;
224213
225− mutex_lock(&thermal_governor_lock);
214+ guard(mutex)(&thermal_governor_lock);
226215
227216 list_for_each_entry(pos, &thermal_governor_list, governor_list) {
228217 count += sysfs_emit_at(buf, count, "%s ", pos->name);
229218 }
230219 count += sysfs_emit_at(buf, count, "\n");
231220
232− mutex_unlock(&thermal_governor_lock);
233−
234221 return count;
235222 }
236223
@@ -421,83 +408,46 @@ static void handle_critical_trips(struct thermal_zone_device *tz, · 184 unmodified lines
421408 tz->ops.hot(tz);
422409 }
423410
424−static void handle_thermal_trip(struct thermal_zone_device *tz,
425− struct thermal_trip_desc *td,
426− struct list_head *way_up_list,
427− struct list_head *way_down_list)
411+static void move_trip_to_sorted_list(struct thermal_trip_desc *td,
412+ struct list_head *list)
428413 {
429− const struct thermal_trip *trip = &td->trip;
430− int old_threshold;
431−
432− if (trip->temperature == THERMAL_TEMP_INVALID)
433− return;
414+ struct thermal_trip_desc *entry;
434415
435416 /*
436− * If the trip temperature or hysteresis has been updated recently,
437− * the threshold needs to be computed again using the new values.
438− * However, its initial value still reflects the old ones and that
439− * is what needs to be compared with the previous zone temperature
440− * to decide which action to take.
417+ * Delete upfront and then add to make relocation within the same list
418+ * work.
441419 */
442− old_threshold = td->threshold;
443− td->threshold = trip->temperature;
420+ list_del(&td->list_node);
444421
445− if (tz->last_temperature >= old_threshold &&
446− tz->last_temperature != THERMAL_TEMP_INIT) {
447− /*
448− * Mitigation is under way, so it needs to stop if the zone
449− * temperature falls below the low temperature of the trip.
450− * In that case, the trip temperature becomes the new threshold.
451− */
452− if (tz->temperature < trip->temperature - trip->hysteresis) {
453− list_add(&td->notify_list_node, way_down_list);
454− td->notify_temp = trip->temperature - trip->hysteresis;
455−
456− if (trip->type == THERMAL_TRIP_PASSIVE) {
457− tz->passive--;
458− WARN_ON(tz->passive < 0);
459− }
460− } else {
461− td->threshold -= trip->hysteresis;
422+ /* Assume that the new entry is likely to be the last one. */
423+ list_for_each_entry_reverse(entry, list, list_node) {
424+ if (entry->threshold <= td->threshold) {
425+ list_add(&td->list_node, &entry->list_node);
426+ return;
462427 }
463− } else if (tz->temperature >= trip->temperature) {
464− /*
465− * There is no mitigation under way, so it needs to be started
466− * if the zone temperature exceeds the trip one. The new
467− * threshold is then set to the low temperature of the trip.
468− */
469− list_add_tail(&td->notify_list_node, way_up_list);
470− td->notify_temp = trip->temperature;
471− td->threshold -= trip->hysteresis;
472−
473− if (trip->type == THERMAL_TRIP_PASSIVE)
474− tz->passive++;
475− else if (trip->type == THERMAL_TRIP_CRITICAL ||
476− trip->type == THERMAL_TRIP_HOT)
477− handle_critical_trips(tz, trip);
478428 }
429+ list_add(&td->list_node, list);
479430 }
480431
481−static void thermal_zone_device_check(struct work_struct *work)
432+static void move_to_trips_high(struct thermal_zone_device *tz,
433+ struct thermal_trip_desc *td)
482434 {
483− struct thermal_zone_device *tz = container_of(work, struct
484− thermal_zone_device,
485− poll_queue.work);
486− thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
435+ td->threshold = td->trip.temperature;
436+ move_trip_to_sorted_list(td, &tz->trips_high);
487437 }
488438
489−static void thermal_zone_device_init(struct thermal_zone_device *tz)
439+static void move_to_trips_reached(struct thermal_zone_device *tz,
440+ struct thermal_trip_desc *td)
490441 {
491− struct thermal_instance *pos;
492−
493− INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
442+ td->threshold = td->trip.temperature - td->trip.hysteresis;
443+ move_trip_to_sorted_list(td, &tz->trips_reached);
444+}
494445
495− tz->temperature = THERMAL_TEMP_INIT;
496− tz->passive = 0;
497− tz->prev_low_trip = -INT_MAX;
498− tz->prev_high_trip = INT_MAX;
499− list_for_each_entry(pos, &tz->thermal_instances, tz_node)
500− pos->initialized = false;
446+static void move_to_trips_invalid(struct thermal_zone_device *tz,
447+ struct thermal_trip_desc *td)
448+{
449+ td->threshold = INT_MAX;
450+ list_move(&td->list_node, &tz->trips_invalid);
501451 }
502452
503453 static void thermal_governor_trip_crossed(struct thermal_governor *governor,
@@ -513,41 +463,154 @@ static void thermal_governor_trip_crossed(struct thermal_governor *governor, · 9 unmodified lines
513463 }
514464
515465 static void thermal_trip_crossed(struct thermal_zone_device *tz,
516− const struct thermal_trip *trip,
466+ struct thermal_trip_desc *td,
517467 struct thermal_governor *governor,
518468 bool crossed_up)
519469 {
470+ const struct thermal_trip *trip = &td->trip;
471+
520472 if (crossed_up) {
473+ if (trip->type == THERMAL_TRIP_PASSIVE)
474+ tz->passive++;
475+ else if (trip->type == THERMAL_TRIP_CRITICAL ||
476+ trip->type == THERMAL_TRIP_HOT)
477+ handle_critical_trips(tz, trip);
478+
521479 thermal_notify_tz_trip_up(tz, trip);
522480 thermal_debug_tz_trip_up(tz, trip);
523481 } else {
482+ if (trip->type == THERMAL_TRIP_PASSIVE) {
483+ tz->passive--;
484+ WARN_ON(tz->passive < 0);
485+ }
524486 thermal_notify_tz_trip_down(tz, trip);
525487 thermal_debug_tz_trip_down(tz, trip);
526488 }
527489 thermal_governor_trip_crossed(governor, tz, trip, crossed_up);
528490 }
529491
530−static int thermal_trip_notify_cmp(void *not_used, const struct list_head *a,
531− const struct list_head *b)
492+void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
493+ struct thermal_trip *trip, int hyst)
532494 {
533− struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc,
534− notify_list_node);
535− struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc,
536− notify_list_node);
537− return tda->notify_temp - tdb->notify_temp;
495+ struct thermal_trip_desc *td = trip_to_trip_desc(trip);
496+
497+ WRITE_ONCE(trip->hysteresis, hyst);
498+ thermal_notify_tz_trip_change(tz, trip);
499+ /*
500+ * If the zone temperature is above or at the trip tmperature, the trip
501+ * is in the trips_reached list and its threshold is equal to its low
502+ * temperature. It needs to stay in that list, but its threshold needs
503+ * to be updated and the list ordering may need to be restored.
504+ */
505+ if (tz->temperature >= td->threshold)
506+ move_to_trips_reached(tz, td);
507+}
508+
509+void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
510+ struct thermal_trip *trip, int temp)
511+{
512+ struct thermal_trip_desc *td = trip_to_trip_desc(trip);
513+ int old_temp = trip->temperature;
514+
515+ if (old_temp == temp)
516+ return;
517+
518+ WRITE_ONCE(trip->temperature, temp);
519+ thermal_notify_tz_trip_change(tz, trip);
520+
521+ if (old_temp == THERMAL_TEMP_INVALID) {
522+ /*
523+ * The trip was invalid before the change, so move it to the
524+ * trips_high list regardless of the new temperature value
525+ * because there is no mitigation under way for it. If a
526+ * mitigation needs to be started, the trip will be moved to the
527+ * trips_reached list later.
528+ */
529+ move_to_trips_high(tz, td);
530+ return;
531+ }
532+
533+ if (temp == THERMAL_TEMP_INVALID) {
534+ /*
535+ * If the trip is in the trips_reached list, mitigation is under
536+ * way for it and it needs to be stopped because the trip is
537+ * effectively going away.
538+ */
539+ if (tz->temperature >= td->threshold)
540+ thermal_trip_crossed(tz, td, thermal_get_tz_governor(tz), false);
541+
542+ move_to_trips_invalid(tz, td);
543+ return;
544+ }
545+
546+ /*
547+ * The trip stays on its current list, but its threshold needs to be
548+ * updated due to the temperature change and the list ordering may need
549+ * to be restored.
550+ */
551+ if (tz->temperature >= td->threshold)
552+ move_to_trips_reached(tz, td);
553+ else
554+ move_to_trips_high(tz, td);
555+}
556+EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
557+
558+static void thermal_zone_handle_trips(struct thermal_zone_device *tz,
559+ struct thermal_governor *governor,
560+ int *low, int *high)
561+{
562+ struct thermal_trip_desc *td, *next;
563+ LIST_HEAD(way_down_list);
564+
565+ /* Check the trips that were below or at the zone temperature. */
566+ list_for_each_entry_safe_reverse(td, next, &tz->trips_reached, list_node) {
567+ if (td->threshold <= tz->temperature)
568+ break;
569+
570+ thermal_trip_crossed(tz, td, governor, false);
571+ /*
572+ * The current trips_high list needs to be processed before
573+ * adding new entries to it, so put them on a temporary list.
574+ */
575+ list_move(&td->list_node, &way_down_list);
576+ }
577+ /* Check the trips that were previously above the zone temperature. */
578+ list_for_each_entry_safe(td, next, &tz->trips_high, list_node) {
579+ if (td->threshold > tz->temperature)
580+ break;
581+
582+ thermal_trip_crossed(tz, td, governor, true);
583+ move_to_trips_reached(tz, td);
584+ }
585+ /* Move all of the trips from the temporary list to trips_high. */
586+ list_for_each_entry_safe(td, next, &way_down_list, list_node)
587+ move_to_trips_high(tz, td);
588+
589+ if (!list_empty(&tz->trips_reached)) {
590+ td = list_last_entry(&tz->trips_reached,
591+ struct thermal_trip_desc, list_node);
592+ /*
593+ * Set the "low" value below the current trip threshold in case
594+ * the zone temperature is at that threshold and stays there,
595+ * which would trigger a new interrupt immediately in vain.
596+ */
597+ *low = td->threshold - 1;
598+ }
599+ if (!list_empty(&tz->trips_high)) {
600+ td = list_first_entry(&tz->trips_high,
601+ struct thermal_trip_desc, list_node);
602+ *high = td->threshold;
603+ }
538604 }
539605
540606 void __thermal_zone_device_update(struct thermal_zone_device *tz,
541607 enum thermal_notify_event event)
542608 {
543609 struct thermal_governor *governor = thermal_get_tz_governor(tz);
544− struct thermal_trip_desc *td;
545− LIST_HEAD(way_down_list);
546− LIST_HEAD(way_up_list);
547610 int low = -INT_MAX, high = INT_MAX;
548611 int temp, ret;
549612
550− if (tz->suspended || tz->mode != THERMAL_DEVICE_ENABLED)
613+ if (tz->state != TZ_STATE_READY || tz->mode != THERMAL_DEVICE_ENABLED)
551614 return;
552615
553616 ret = __thermal_zone_get_temp(tz, &temp);
@@ -575,26 +638,12 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, · 21 unmodified lines
575638
576639 tz->notify_event = event;
577640
578− for_each_trip_desc(tz, td) {
579− handle_thermal_trip(tz, td, &way_up_list, &way_down_list);
641+ thermal_zone_handle_trips(tz, governor, &low, &high);
580642
581− if (td->threshold <= tz->temperature && td->threshold > low)
582− low = td->threshold;
583−
584− if (td->threshold >= tz->temperature && td->threshold < high)
585− high = td->threshold;
586− }
643+ thermal_thresholds_handle(tz, &low, &high);
587644
588645 thermal_zone_set_trips(tz, low, high);
589646
590− list_sort(NULL, &way_up_list, thermal_trip_notify_cmp);
591− list_for_each_entry(td, &way_up_list, notify_list_node)
592− thermal_trip_crossed(tz, &td->trip, governor, true);
593−
594− list_sort(NULL, &way_down_list, thermal_trip_notify_cmp);
595− list_for_each_entry_reverse(td, &way_down_list, notify_list_node)
596− thermal_trip_crossed(tz, &td->trip, governor, false);
597−
598647 if (governor->manage)
599648 governor->manage(tz);
600649
@@ -609,26 +658,18 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, · 8 unmodified lines
609658 {
610659 int ret;
611660
612− mutex_lock(&tz->lock);
661+ guard(thermal_zone)(tz);
613662
614663 /* do nothing if mode isn't changing */
615− if (mode == tz->mode) {
616− mutex_unlock(&tz->lock);
617−
664+ if (mode == tz->mode)
618665 return 0;
619− }
620666
621667 ret = __thermal_zone_device_set_mode(tz, mode);
622− if (ret) {
623− mutex_unlock(&tz->lock);
624−
668+ if (ret)
625669 return ret;
626− }
627670
628671 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
629672
630− mutex_unlock(&tz->lock);
631−
632673 if (mode == THERMAL_DEVICE_ENABLED)
633674 thermal_notify_tz_enable(tz);
634675 else
@@ -657,85 +698,81 @@ static bool thermal_zone_is_present(struct thermal_zone_device *tz) · 22 unmodified lines
657698 void thermal_zone_device_update(struct thermal_zone_device *tz,
658699 enum thermal_notify_event event)
659700 {
660− mutex_lock(&tz->lock);
701+ guard(thermal_zone)(tz);
702+
661703 if (thermal_zone_is_present(tz))
662704 __thermal_zone_device_update(tz, event);
663− mutex_unlock(&tz->lock);
664705 }
665706 EXPORT_SYMBOL_GPL(thermal_zone_device_update);
666707
667−void thermal_zone_trip_down(struct thermal_zone_device *tz,
668− const struct thermal_trip *trip)
669−{
670− thermal_trip_crossed(tz, trip, thermal_get_tz_governor(tz), false);
671−}
672−
673708 int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
674709 void *data)
675710 {
676711 struct thermal_governor *gov;
677− int ret = 0;
678712
679− mutex_lock(&thermal_governor_lock);
713+ guard(mutex)(&thermal_governor_lock);
714+
680715 list_for_each_entry(gov, &thermal_governor_list, governor_list) {
716+ int ret;
717+
681718 ret = cb(gov, data);
682719 if (ret)
683− break;
720+ return ret;
684721 }
685− mutex_unlock(&thermal_governor_lock);
686722
687− return ret;
723+ return 0;
688724 }
689725
690726 int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
691727 void *), void *data)
692728 {
693729 struct thermal_cooling_device *cdev;
694− int ret = 0;
695730
696− mutex_lock(&thermal_list_lock);
731+ guard(mutex)(&thermal_list_lock);
732+
697733 list_for_each_entry(cdev, &thermal_cdev_list, node) {
734+ int ret;
735+
698736 ret = cb(cdev, data);
699737 if (ret)
700− break;
738+ return ret;
701739 }
702− mutex_unlock(&thermal_list_lock);
703740
704− return ret;
741+ return 0;
705742 }
706743
707744 int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *),
708745 void *data)
709746 {
710747 struct thermal_zone_device *tz;
711− int ret = 0;
712748
713− mutex_lock(&thermal_list_lock);
749+ guard(mutex)(&thermal_list_lock);
750+
714751 list_for_each_entry(tz, &thermal_tz_list, node) {
752+ int ret;
753+
715754 ret = cb(tz, data);
716755 if (ret)
717− break;
756+ return ret;
718757 }
719− mutex_unlock(&thermal_list_lock);
720758
721− return ret;
759+ return 0;
722760 }
723761
724762 struct thermal_zone_device *thermal_zone_get_by_id(int id)
725763 {
726− struct thermal_zone_device *tz, *match = NULL;
764+ struct thermal_zone_device *tz;
765+
766+ guard(mutex)(&thermal_list_lock);
727767
728− mutex_lock(&thermal_list_lock);
729768 list_for_each_entry(tz, &thermal_tz_list, node) {
730769 if (tz->id == id) {
731770 get_device(&tz->device);
732− match = tz;
733− break;
771+ return tz;
734772 }
735773 }
736− mutex_unlock(&thermal_list_lock);
737774
738− return match;
775+ return NULL;
739776 }
740777
741778 /*
@@ -748,12 +785,32 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) · 6 unmodified lines
748785 * binding, and unbinding.
749786 */
750787
788+static int thermal_instance_add(struct thermal_instance *new_instance,
789+ struct thermal_cooling_device *cdev,
790+ struct thermal_trip_desc *td)
791+{
792+ struct thermal_instance *instance;
793+
794+ list_for_each_entry(instance, &td->thermal_instances, trip_node) {
795+ if (instance->cdev == cdev)
796+ return -EEXIST;
797+ }
798+
799+ list_add_tail(&new_instance->trip_node, &td->thermal_instances);
800+
801+ guard(cooling_dev)(cdev);
802+
803+ list_add_tail(&new_instance->cdev_node, &cdev->thermal_instances);
804+
805+ return 0;
806+}
807+
751808 /**
752809 * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone
753810 * @tz: pointer to struct thermal_zone_device
754− * @trip: trip point the cooling devices is associated with in this zone.
811+ * @td: descriptor of the trip point to bind @cdev to
755812 * @cdev: pointer to struct thermal_cooling_device
756− * @cool_spec: cooling specification for @trip and @cdev
813+ * @cool_spec: cooling specification for the trip point and @cdev
757814 *
758815 * This interface function bind a thermal cooling device to the certain trip
759816 * point of a thermal zone device.
@@ -762,12 +819,11 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) · 2 unmodified lines
762819 * Return: 0 on success, the proper error value otherwise.
763820 */
764821 static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
765− const struct thermal_trip *trip,
822+ struct thermal_trip_desc *td,
766823 struct thermal_cooling_device *cdev,
767824 struct cooling_spec *cool_spec)
768825 {
769826 struct thermal_instance *dev;
770− struct thermal_instance *pos;
771827 bool upper_no_limit;
772828 int result;
773829
@@ -790,7 +846,7 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, · 16 unmodified lines
790846 return -ENOMEM;
791847
792848 dev->cdev = cdev;
793− dev->trip = trip;
849+ dev->trip = &td->trip;
794850 dev->upper = cool_spec->upper;
795851 dev->upper_no_limit = upper_no_limit;
796852 dev->lower = cool_spec->lower;
@@ -829,24 +885,15 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, · 32 unmodified lines
829885 if (result)
830886 goto remove_trip_file;
831887
832− mutex_lock(&cdev->lock);
833− list_for_each_entry(pos, &tz->thermal_instances, tz_node)
834− if (pos->trip == trip && pos->cdev == cdev) {
835− result = -EEXIST;
836− break;
837− }
838− if (!result) {
839− list_add_tail(&dev->tz_node, &tz->thermal_instances);
840− list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
841− atomic_set(&tz->need_update, 1);
888+ result = thermal_instance_add(dev, cdev, td);
889+ if (result)
890+ goto remove_weight_file;
842891
843− thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV);
844− }
845− mutex_unlock(&cdev->lock);
892+ thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV);
846893
847− if (!result)
848− return 0;
894+ return 0;
849895
896+remove_weight_file:
850897 device_remove_file(&tz->device, &dev->weight_attr);
851898 remove_trip_file:
852899 device_remove_file(&tz->device, &dev->attr);
@@ -859,10 +906,19 @@ free_mem: · 6 unmodified lines
859906 return result;
860907 }
861908
909+static void thermal_instance_delete(struct thermal_instance *instance)
910+{
911+ list_del(&instance->trip_node);
912+
913+ guard(cooling_dev)(instance->cdev);
914+
915+ list_del(&instance->cdev_node);
916+}
917+
862918 /**
863919 * thermal_unbind_cdev_from_trip - unbind a cooling device from a thermal zone.
864920 * @tz: pointer to a struct thermal_zone_device.
865− * @trip: trip point the cooling devices is associated with in this zone.
921+ * @td: descriptor of the trip point to unbind @cdev from
866922 * @cdev: pointer to a struct thermal_cooling_device.
867923 *
868924 * This interface function unbind a thermal cooling device from the certain
@@ -870,28 +926,23 @@ free_mem: · 1 unmodified line
870926 * This function is usually called in the thermal zone device .unbind callback.
871927 */
872928 static void thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
873− const struct thermal_trip *trip,
929+ struct thermal_trip_desc *td,
874930 struct thermal_cooling_device *cdev)
875931 {
876932 struct thermal_instance *pos, *next;
877933
878− mutex_lock(&cdev->lock);
879− list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
880− if (pos->trip == trip && pos->cdev == cdev) {
881− list_del(&pos->tz_node);
882− list_del(&pos->cdev_node);
883−
884− thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV);
885−
886− mutex_unlock(&cdev->lock);
934+ list_for_each_entry_safe(pos, next, &td->thermal_instances, trip_node) {
935+ if (pos->cdev == cdev) {
936+ thermal_instance_delete(pos);
887937 goto unbind;
888938 }
889939 }
890− mutex_unlock(&cdev->lock);
891940
892941 return;
893942
894943 unbind:
944+ thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV);
945+
895946 device_remove_file(&tz->device, &pos->weight_attr);
896947 device_remove_file(&tz->device, &pos->attr);
897948 sysfs_remove_link(&tz->device.kobj, pos->name);
@@ -924,25 +975,23 @@ static struct class *thermal_class; · 26 unmodified lines
924975
925976 static inline
926977 void print_bind_err_msg(struct thermal_zone_device *tz,
927− const struct thermal_trip *trip,
978+ const struct thermal_trip_desc *td,
928979 struct thermal_cooling_device *cdev, int ret)
929980 {
930981 dev_err(&tz->device, "binding cdev %s to trip %d failed: %d\n",
931− cdev->type, thermal_zone_trip_id(tz, trip), ret);
982+ cdev->type, thermal_zone_trip_id(tz, &td->trip), ret);
932983 }
933984
934−static void thermal_zone_cdev_bind(struct thermal_zone_device *tz,
935− struct thermal_cooling_device *cdev)
985+static bool __thermal_zone_cdev_bind(struct thermal_zone_device *tz,
986+ struct thermal_cooling_device *cdev)
936987 {
937988 struct thermal_trip_desc *td;
989+ bool update_tz = false;
938990
939991 if (!tz->ops.should_bind)
940− return;
941−
942− mutex_lock(&tz->lock);
992+ return false;
943993
944994 for_each_trip_desc(tz, td) {
945− struct thermal_trip *trip = &td->trip;
946995 struct cooling_spec c = {
947996 .upper = THERMAL_NO_LIMIT,
948997 .lower = THERMAL_NO_LIMIT,
@@ -950,15 +999,40 @@ static void thermal_zone_cdev_bind(struct thermal_zone_device *tz, · 1 unmodified line
950999 };
9511000 int ret;
9521001
953− if (!tz->ops.should_bind(tz, trip, cdev, &c))
1002+ if (!tz->ops.should_bind(tz, &td->trip, cdev, &c))
9541003 continue;
9551004
956− ret = thermal_bind_cdev_to_trip(tz, trip, cdev, &c);
957− if (ret)
958− print_bind_err_msg(tz, trip, cdev, ret);
1005+ ret = thermal_bind_cdev_to_trip(tz, td, cdev, &c);
1006+ if (ret) {
1007+ print_bind_err_msg(tz, td, cdev, ret);
1008+ continue;
1009+ }
1010+
1011+ update_tz = true;
9591012 }
9601013
961− mutex_unlock(&tz->lock);
1014+ return update_tz;
1015+}
1016+
1017+static void thermal_zone_cdev_bind(struct thermal_zone_device *tz,
1018+ struct thermal_cooling_device *cdev)
1019+{
1020+ guard(thermal_zone)(tz);
1021+
1022+ if (__thermal_zone_cdev_bind(tz, cdev))
1023+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
1024+}
1025+
1026+static void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
1027+{
1028+ struct thermal_zone_device *tz;
1029+
1030+ guard(mutex)(&thermal_list_lock);
1031+
1032+ list_add(&cdev->node, &thermal_cdev_list);
1033+
1034+ list_for_each_entry(tz, &thermal_tz_list, node)
1035+ thermal_zone_cdev_bind(tz, cdev);
9621036 }
9631037
9641038 /**
@@ -983,7 +1057,6 @@ __thermal_cooling_device_register(struct device_node *np, · 18 unmodified lines
9831057 const struct thermal_cooling_device_ops *ops)
9841058 {
9851059 struct thermal_cooling_device *cdev;
986− struct thermal_zone_device *pos = NULL;
9871060 unsigned long current_state;
9881061 int id, ret;
9891062
@@ -1050,21 +1123,7 @@ __thermal_cooling_device_register(struct device_node *np, · 60 unmodified lines
10501123 if (current_state <= cdev->max_state)
10511124 thermal_debug_cdev_add(cdev, current_state);
10521125
1053− /* Add 'this' new cdev to the global cdev list */
1054− mutex_lock(&thermal_list_lock);
1055−
1056− list_add(&cdev->node, &thermal_cdev_list);
1057−
1058− /* Update binding information for 'this' new cdev */
1059− list_for_each_entry(pos, &thermal_tz_list, node)
1060− thermal_zone_cdev_bind(pos, cdev);
1061−
1062− list_for_each_entry(pos, &thermal_tz_list, node)
1063− if (atomic_cmpxchg(&pos->need_update, 1, 0))
1064− thermal_zone_device_update(pos,
1065− THERMAL_EVENT_UNSPECIFIED);
1066−
1067− mutex_unlock(&thermal_list_lock);
1126+ thermal_cooling_device_init_complete(cdev);
10681127
10691128 return cdev;
10701129
@@ -1207,19 +1266,19 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) · 136 unmodified lines
12071266 * Hold thermal_list_lock throughout the update to prevent the device
12081267 * from going away while being updated.
12091268 */
1210− mutex_lock(&thermal_list_lock);
1269+ guard(mutex)(&thermal_list_lock);
12111270
12121271 if (!thermal_cooling_device_present(cdev))
1213− goto unlock_list;
1272+ return;
12141273
12151274 /*
12161275 * Update under the cdev lock to prevent the state from being set beyond
12171276 * the new limit concurrently.
12181277 */
1219− mutex_lock(&cdev->lock);
1278+ guard(cooling_dev)(cdev);
12201279
12211280 if (cdev->ops->get_max_state(cdev, &cdev->max_state))
1222− goto unlock;
1281+ return;
12231282
12241283 thermal_cooling_device_stats_reinit(cdev);
12251284
@@ -1246,63 +1305,59 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) · 20 unmodified lines
12461305 }
12471306
12481307 if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state)
1249− goto unlock;
1308+ return;
12501309
12511310 thermal_cooling_device_stats_update(cdev, state);
1252−
1253−unlock:
1254− mutex_unlock(&cdev->lock);
1255−
1256−unlock_list:
1257− mutex_unlock(&thermal_list_lock);
12581311 }
12591312 EXPORT_SYMBOL_GPL(thermal_cooling_device_update);
12601313
1261−static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz,
1262− struct thermal_cooling_device *cdev)
1314+static void __thermal_zone_cdev_unbind(struct thermal_zone_device *tz,
1315+ struct thermal_cooling_device *cdev)
12631316 {
12641317 struct thermal_trip_desc *td;
12651318
1266− mutex_lock(&tz->lock);
1267−
12681319 for_each_trip_desc(tz, td)
1269− thermal_unbind_cdev_from_trip(tz, &td->trip, cdev);
1270−
1271− mutex_unlock(&tz->lock);
1320+ thermal_unbind_cdev_from_trip(tz, td, cdev);
12721321 }
12731322
1274−/**
1275− * thermal_cooling_device_unregister - removes a thermal cooling device
1276− * @cdev: the thermal cooling device to remove.
1277− *
1278− * thermal_cooling_device_unregister() must be called when a registered
1279− * thermal cooling device is no longer needed.
1280− */
1281−void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
1323+static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz,
1324+ struct thermal_cooling_device *cdev)
12821325 {
1283− struct thermal_zone_device *tz;
1326+ guard(thermal_zone)(tz);
12841327
1285− if (!cdev)
1286− return;
1328+ __thermal_zone_cdev_unbind(tz, cdev);
1329+}
12871330
1288− thermal_debug_cdev_remove(cdev);
1331+static bool thermal_cooling_device_exit(struct thermal_cooling_device *cdev)
1332+{
1333+ struct thermal_zone_device *tz;
12891334
1290− mutex_lock(&thermal_list_lock);
1335+ guard(mutex)(&thermal_list_lock);
12911336
1292− if (!thermal_cooling_device_present(cdev)) {
1293− mutex_unlock(&thermal_list_lock);
1294− return;
1295− }
1337+ if (!thermal_cooling_device_present(cdev))
1338+ return false;
12961339
12971340 list_del(&cdev->node);
12981341
1299− /* Unbind all thermal zones associated with 'this' cdev */
13001342 list_for_each_entry(tz, &thermal_tz_list, node)
13011343 thermal_zone_cdev_unbind(tz, cdev);
13021344
1303− mutex_unlock(&thermal_list_lock);
1345+ return true;
1346+}
13041347
1305− device_unregister(&cdev->device);
1348+/**
1349+ * thermal_cooling_device_unregister() - removes a thermal cooling device
1350+ * @cdev: Thermal cooling device to remove.
1351+ */
1352+void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
1353+{
1354+ if (!cdev)
1355+ return;
1356+
1357+ thermal_debug_cdev_remove(cdev);
1358+
1359+ if (thermal_cooling_device_exit(cdev))
1360+ device_unregister(&cdev->device);
13061361 }
13071362 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
13081363
@@ -1314,7 +1369,7 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) · 5 unmodified lines
13141369 if (tz->ops.get_crit_temp)
13151370 return tz->ops.get_crit_temp(tz, temp);
13161371
1317− mutex_lock(&tz->lock);
1372+ guard(thermal_zone)(tz);
13181373
13191374 for_each_trip_desc(tz, td) {
13201375 const struct thermal_trip *trip = &td->trip;
@@ -1326,12 +1381,91 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) · 5 unmodified lines
13261381 }
13271382 }
13281383
1329− mutex_unlock(&tz->lock);
1330−
13311384 return ret;
13321385 }
13331386 EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp);
13341387
1388+static void thermal_zone_device_check(struct work_struct *work)
1389+{
1390+ struct thermal_zone_device *tz = container_of(work, struct
1391+ thermal_zone_device,
1392+ poll_queue.work);
1393+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
1394+}
1395+
1396+static void thermal_zone_device_init(struct thermal_zone_device *tz)
1397+{
1398+ struct thermal_trip_desc *td, *next;
1399+
1400+ INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
1401+
1402+ tz->temperature = THERMAL_TEMP_INIT;
1403+ tz->passive = 0;
1404+ tz->prev_low_trip = -INT_MAX;
1405+ tz->prev_high_trip = INT_MAX;
1406+ for_each_trip_desc(tz, td) {
1407+ struct thermal_instance *instance;
1408+
1409+ list_for_each_entry(instance, &td->thermal_instances, trip_node)
1410+ instance->initialized = false;
1411+ }
1412+ /*
1413+ * At this point, all valid trips need to be moved to trips_high so that
1414+ * mitigation can be started if the zone temperature is above them.
1415+ */
1416+ list_for_each_entry_safe(td, next, &tz->trips_invalid, list_node) {
1417+ if (td->trip.temperature != THERMAL_TEMP_INVALID)
1418+ move_to_trips_high(tz, td);
1419+ }
1420+ /* The trips_reached list may not be empty during system resume. */
1421+ list_for_each_entry_safe(td, next, &tz->trips_reached, list_node) {
1422+ if (td->trip.temperature == THERMAL_TEMP_INVALID)
1423+ move_to_trips_invalid(tz, td);
1424+ else
1425+ move_to_trips_high(tz, td);
1426+ }
1427+}
1428+
1429+static int thermal_zone_init_governor(struct thermal_zone_device *tz)
1430+{
1431+ struct thermal_governor *governor;
1432+
1433+ guard(mutex)(&thermal_governor_lock);
1434+
1435+ if (tz->tzp)
1436+ governor = __find_governor(tz->tzp->governor_name);
1437+ else
1438+ governor = def_governor;
1439+
1440+ return thermal_set_governor(tz, governor);
1441+}
1442+
1443+static void thermal_zone_init_complete(struct thermal_zone_device *tz)
1444+{
1445+ struct thermal_cooling_device *cdev;
1446+
1447+ guard(mutex)(&thermal_list_lock);
1448+
1449+ list_add_tail(&tz->node, &thermal_tz_list);
1450+
1451+ guard(thermal_zone)(tz);
1452+
1453+ /* Bind cooling devices for this zone. */
1454+ list_for_each_entry(cdev, &thermal_cdev_list, node)
1455+ __thermal_zone_cdev_bind(tz, cdev);
1456+
1457+ tz->state &= ~TZ_STATE_FLAG_INIT;
1458+ /*
1459+ * If system suspend or resume is in progress at this point, the
1460+ * new thermal zone needs to be marked as suspended because
1461+ * thermal_pm_notify() has run already.
1462+ */
1463+ if (thermal_pm_suspended)
1464+ tz->state |= TZ_STATE_FLAG_SUSPENDED;
1465+
1466+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
1467+}
1468+
13351469 /**
13361470 * thermal_zone_device_register_with_trips() - register a new thermal zone device
13371471 * @type: the thermal zone device type
@@ -1366,12 +1500,10 @@ thermal_zone_device_register_with_trips(const char *type, · 28 unmodified lines
13661500 unsigned int polling_delay)
13671501 {
13681502 const struct thermal_trip *trip = trips;
1369− struct thermal_cooling_device *cdev;
13701503 struct thermal_zone_device *tz;
13711504 struct thermal_trip_desc *td;
13721505 int id;
13731506 int result;
1374− struct thermal_governor *governor;
13751507
13761508 if (!type || strlen(type) == 0) {
13771509 pr_err("No thermal zone type defined\n");
@@ -1415,8 +1547,10 @@ thermal_zone_device_register_with_trips(const char *type, · 37 unmodified lines
14151547 }
14161548 }
14171549
1418− INIT_LIST_HEAD(&tz->thermal_instances);
14191550 INIT_LIST_HEAD(&tz->node);
1551+ INIT_LIST_HEAD(&tz->trips_high);
1552+ INIT_LIST_HEAD(&tz->trips_reached);
1553+ INIT_LIST_HEAD(&tz->trips_invalid);
14201554 ida_init(&tz->ida);
14211555 mutex_init(&tz->lock);
14221556 init_completion(&tz->removal);
@@ -1439,51 +1573,41 @@ thermal_zone_device_register_with_trips(const char *type, · 16 unmodified lines
14391573 tz->num_trips = num_trips;
14401574 for_each_trip_desc(tz, td) {
14411575 td->trip = *trip++;
1576+ INIT_LIST_HEAD(&td->thermal_instances);
1577+ INIT_LIST_HEAD(&td->list_node);
14421578 /*
14431579 * Mark all thresholds as invalid to start with even though
14441580 * this only matters for the trips that start as invalid and
14451581 * become valid later.
14461582 */
1447− td->threshold = INT_MAX;
1583+ move_to_trips_invalid(tz, td);
14481584 }
14491585
14501586 tz->polling_delay_jiffies = msecs_to_jiffies(polling_delay);
14511587 tz->passive_delay_jiffies = msecs_to_jiffies(passive_delay);
14521588 tz->recheck_delay_jiffies = THERMAL_RECHECK_DELAY;
14531589
1590+ tz->state = TZ_STATE_FLAG_INIT;
1591+
14541592 /* sys I/F */
14551593 /* Add nodes that are always present via .groups */
14561594 result = thermal_zone_create_device_groups(tz);
14571595 if (result)
14581596 goto remove_id;
14591597
1460− /* A new thermal zone needs to be updated anyway. */
1461− atomic_set(&tz->need_update, 1);
1462−
14631598 result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
14641599 if (result) {
14651600 thermal_zone_destroy_device_groups(tz);
14661601 goto remove_id;
14671602 }
1603+ thermal_zone_device_init(tz);
14681604 result = device_register(&tz->device);
14691605 if (result)
14701606 goto release_device;
14711607
1472− /* Update 'this' zone's governor information */
1473− mutex_lock(&thermal_governor_lock);
1474−
1475− if (tz->tzp)
1476− governor = __find_governor(tz->tzp->governor_name);
1477− else
1478− governor = def_governor;
1479−
1480− result = thermal_set_governor(tz, governor);
1481− if (result) {
1482− mutex_unlock(&thermal_governor_lock);
1608+ result = thermal_zone_init_governor(tz);
1609+ if (result)
14831610 goto unregister;
1484− }
1485−
1486− mutex_unlock(&thermal_governor_lock);
14871611
14881612 if (!tz->tzp || !tz->tzp->no_hwmon) {
14891613 result = thermal_add_hwmon_sysfs(tz);
@@ -1491,22 +1615,11 @@ thermal_zone_device_register_with_trips(const char *type, · 1 unmodified line
14911615 goto unregister;
14921616 }
14931617
1494− mutex_lock(&thermal_list_lock);
1495−
1496− mutex_lock(&tz->lock);
1497− list_add_tail(&tz->node, &thermal_tz_list);
1498− mutex_unlock(&tz->lock);
1499−
1500− /* Bind cooling devices for this zone */
1501− list_for_each_entry(cdev, &thermal_cdev_list, node)
1502− thermal_zone_cdev_bind(tz, cdev);
1503−
1504− mutex_unlock(&thermal_list_lock);
1618+ result = thermal_thresholds_init(tz);
1619+ if (result)
1620+ goto remove_hwmon;
15051621
1506− thermal_zone_device_init(tz);
1507− /* Update the new thermal zone and mark it as already updated. */
1508− if (atomic_cmpxchg(&tz->need_update, 1, 0))
1509− thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
1622+ thermal_zone_init_complete(tz);
15101623
15111624 thermal_notify_tz_create(tz);
15121625
@@ -1514,6 +1627,8 @@ thermal_zone_device_register_with_trips(const char *type, · 1 unmodified line
15141627
15151628 return tz;
15161629
1630+remove_hwmon:
1631+ thermal_remove_hwmon_sysfs(tz);
15171632 unregister:
15181633 device_del(&tz->device);
15191634 release_device:
@@ -1563,44 +1678,46 @@ struct device *thermal_zone_device(struct thermal_zone_device *tzd) · 43 unmodified lines
15631678 }
15641679 EXPORT_SYMBOL_GPL(thermal_zone_device);
15651680
1681+static bool thermal_zone_exit(struct thermal_zone_device *tz)
1682+{
1683+ struct thermal_cooling_device *cdev;
1684+
1685+ guard(mutex)(&thermal_list_lock);
1686+
1687+ if (list_empty(&tz->node))
1688+ return false;
1689+
1690+ guard(thermal_zone)(tz);
1691+
1692+ tz->state |= TZ_STATE_FLAG_EXIT;
1693+ list_del_init(&tz->node);
1694+
1695+ /* Unbind all cdevs associated with this thermal zone. */
1696+ list_for_each_entry(cdev, &thermal_cdev_list, node)
1697+ __thermal_zone_cdev_unbind(tz, cdev);
1698+
1699+ return true;
1700+}
1701+
15661702 /**
15671703 * thermal_zone_device_unregister - removes the registered thermal zone device
15681704 * @tz: the thermal zone device to remove
15691705 */
15701706 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
15711707 {
1572− struct thermal_cooling_device *cdev;
1573− struct thermal_zone_device *pos = NULL;
1574−
15751708 if (!tz)
15761709 return;
15771710
15781711 thermal_debug_tz_remove(tz);
15791712
1580− mutex_lock(&thermal_list_lock);
1581− list_for_each_entry(pos, &thermal_tz_list, node)
1582− if (pos == tz)
1583− break;
1584− if (pos != tz) {
1585− /* thermal zone device not found */
1586− mutex_unlock(&thermal_list_lock);
1713+ if (!thermal_zone_exit(tz))
15871714 return;
1588− }
1589−
1590− mutex_lock(&tz->lock);
1591− list_del(&tz->node);
1592− mutex_unlock(&tz->lock);
1593−
1594− /* Unbind all cdevs associated with 'this' thermal zone */
1595− list_for_each_entry(cdev, &thermal_cdev_list, node)
1596− thermal_zone_cdev_unbind(tz, cdev);
1597−
1598− mutex_unlock(&thermal_list_lock);
15991715
16001716 cancel_delayed_work_sync(&tz->poll_queue);
16011717
16021718 thermal_set_governor(tz, NULL);
16031719
1720+ thermal_thresholds_exit(tz);
16041721 thermal_remove_hwmon_sysfs(tz);
16051722 ida_free(&thermal_tz_ida, tz->id);
16061723 ida_destroy(&tz->ida);
@@ -1632,24 +1749,23 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name) · 25 unmodified lines
16321749 unsigned int found = 0;
16331750
16341751 if (!name)
1635− goto exit;
1752+ return ERR_PTR(-EINVAL);
1753+
1754+ guard(mutex)(&thermal_list_lock);
16361755
1637− mutex_lock(&thermal_list_lock);
16381756 list_for_each_entry(pos, &thermal_tz_list, node)
16391757 if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) {
16401758 found++;
16411759 ref = pos;
16421760 }
1643− mutex_unlock(&thermal_list_lock);
16441761
1645− /* nothing has been found, thus an error code for it */
1646− if (found == 0)
1647− ref = ERR_PTR(-ENODEV);
1648− else if (found > 1)
1649− /* Success only when an unique zone is found */
1650− ref = ERR_PTR(-EEXIST);
1762+ if (!found)
1763+ return ERR_PTR(-ENODEV);
1764+
1765+ /* Success only when one zone is found. */
1766+ if (found > 1)
1767+ return ERR_PTR(-EEXIST);
16511768
1652−exit:
16531769 return ref;
16541770 }
16551771 EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
@@ -1660,9 +1776,9 @@ static void thermal_zone_device_resume(struct work_struct *work) · 4 unmodified lines
16601776
16611777 tz = container_of(work, struct thermal_zone_device, poll_queue.work);
16621778
1663− mutex_lock(&tz->lock);
1779+ guard(thermal_zone)(tz);
16641780
1665− tz->suspended = false;
1781+ tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING);
16661782
16671783 thermal_debug_tz_resume(tz);
16681784 thermal_zone_device_init(tz);
@@ -1670,74 +1786,81 @@ static void thermal_zone_device_resume(struct work_struct *work) · 1 unmodified line
16701786 __thermal_zone_device_update(tz, THERMAL_TZ_RESUME);
16711787
16721788 complete(&tz->resume);
1673− tz->resuming = false;
1674−
1675− mutex_unlock(&tz->lock);
16761789 }
16771790
1678−static int thermal_pm_notify(struct notifier_block *nb,
1679− unsigned long mode, void *_unused)
1791+static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
16801792 {
1681− struct thermal_zone_device *tz;
1793+ guard(thermal_zone)(tz);
16821794
1683− switch (mode) {
1684− case PM_HIBERNATION_PREPARE:
1685− case PM_RESTORE_PREPARE:
1686− case PM_SUSPEND_PREPARE:
1687− mutex_lock(&thermal_list_lock);
1795+ if (tz->state & TZ_STATE_FLAG_RESUMING) {
1796+ /*
1797+ * thermal_zone_device_resume() queued up for this zone has not
1798+ * acquired the lock yet, so release it to let the function run
1799+ * and wait util it has done the work.
1800+ */
1801+ scoped_guard(thermal_zone_reverse, tz) {
1802+ wait_for_completion(&tz->resume);
1803+ }
1804+ }
16881805
1689− list_for_each_entry(tz, &thermal_tz_list, node) {
1690− mutex_lock(&tz->lock);
1806+ tz->state |= TZ_STATE_FLAG_SUSPENDED;
1807+}
16911808
1692− if (tz->resuming) {
1693− /*
1694− * thermal_zone_device_resume() queued up for
1695− * this zone has not acquired the lock yet, so
1696− * release it to let the function run and wait
1697− * util it has done the work.
1698− */
1699− mutex_unlock(&tz->lock);
1809+static void thermal_pm_notify_prepare(void)
1810+{
1811+ struct thermal_zone_device *tz;
17001812
1701− wait_for_completion(&tz->resume);
1813+ guard(mutex)(&thermal_list_lock);
17021814
1703− mutex_lock(&tz->lock);
1704− }
1815+ thermal_pm_suspended = true;
17051816
1706− tz->suspended = true;
1817+ list_for_each_entry(tz, &thermal_tz_list, node)
1818+ thermal_zone_pm_prepare(tz);
1819+}
17071820
1708− mutex_unlock(&tz->lock);
1709− }
1821+static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
1822+{
1823+ guard(thermal_zone)(tz);
17101824
1711− mutex_unlock(&thermal_list_lock);
1712− break;
1713− case PM_POST_HIBERNATION:
1714− case PM_POST_RESTORE:
1715− case PM_POST_SUSPEND:
1716− mutex_lock(&thermal_list_lock);
1825+ cancel_delayed_work(&tz->poll_queue);
17171826
1718− list_for_each_entry(tz, &thermal_tz_list, node) {
1719− mutex_lock(&tz->lock);
1827+ reinit_completion(&tz->resume);
1828+ tz->state |= TZ_STATE_FLAG_RESUMING;
1829+
1830+ /*
1831+ * Replace the work function with the resume one, which will restore the
1832+ * original work function and schedule the polling work if needed.
1833+ */
1834+ INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_resume);
1835+ /* Queue up the work without a delay. */
1836+ mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, 0);
1837+}
17201838
1721− cancel_delayed_work(&tz->poll_queue);
1839+static void thermal_pm_notify_complete(void)
1840+{
1841+ struct thermal_zone_device *tz;
17221842
1723− reinit_completion(&tz->resume);
1724− tz->resuming = true;
1843+ guard(mutex)(&thermal_list_lock);
17251844
1726− /*
1727− * Replace the work function with the resume one, which
1728− * will restore the original work function and schedule
1729− * the polling work if needed.
1730− */
1731− INIT_DELAYED_WORK(&tz->poll_queue,
1732− thermal_zone_device_resume);
1733− /* Queue up the work without a delay. */
1734− mod_delayed_work(system_freezable_power_efficient_wq,
1735− &tz->poll_queue, 0);
1845+ thermal_pm_suspended = false;
17361846
1737− mutex_unlock(&tz->lock);
1738− }
1847+ list_for_each_entry(tz, &thermal_tz_list, node)
1848+ thermal_zone_pm_complete(tz);
1849+}
17391850
1740− mutex_unlock(&thermal_list_lock);
1851+static int thermal_pm_notify(struct notifier_block *nb,
1852+ unsigned long mode, void *_unused)
1853+{
1854+ switch (mode) {
1855+ case PM_HIBERNATION_PREPARE:
1856+ case PM_RESTORE_PREPARE:
1857+ case PM_SUSPEND_PREPARE:
1858+ thermal_pm_notify_prepare();
1859+ break;
1860+ case PM_POST_HIBERNATION:
1861+ case PM_POST_RESTORE:
1862+ case PM_POST_SUSPEND:
1863+ thermal_pm_notify_complete();
17411864 break;
17421865 default:
17431866 break;
drivers/thermal/thermal_core.h+28−13
@@ -9,10 +9,12 @@ · 8 unmodified lines
99 #ifndef __THERMAL_CORE_H__
1010 #define __THERMAL_CORE_H__
1111
12+#include <linux/cleanup.h>
1213 #include <linux/device.h>
1314 #include <linux/thermal.h>
1415
1516 #include "thermal_netlink.h"
17+#include "thermal_thresholds.h"
1618 #include "thermal_debugfs.h"
1719
1820 struct thermal_attr {
@@ -29,8 +31,8 @@ struct thermal_trip_attrs { · 10 unmodified lines
2931 struct thermal_trip_desc {
3032 struct thermal_trip trip;
3133 struct thermal_trip_attrs trip_attrs;
32− struct list_head notify_list_node;
33− int notify_temp;
34+ struct list_head list_node;
35+ struct list_head thermal_instances;
3436 int threshold;
3537 };
3638
@@ -61,6 +63,13 @@ struct thermal_governor { · 24 unmodified lines
6163 struct list_head governor_list;
6264 };
6365
66+#define TZ_STATE_FLAG_SUSPENDED BIT(0)
67+#define TZ_STATE_FLAG_RESUMING BIT(1)
68+#define TZ_STATE_FLAG_INIT BIT(2)
69+#define TZ_STATE_FLAG_EXIT BIT(3)
70+
71+#define TZ_STATE_READY 0
72+
6473 /**
6574 * struct thermal_zone_device - structure for a thermal zone
6675 * @id: unique id number for each thermal zone
@@ -68,6 +77,9 @@ struct thermal_governor { · 1 unmodified line
6877 * @device: &struct device for this thermal zone
6978 * @removal: removal completion
7079 * @resume: resume completion
80+ * @trips_high: trips above the current zone temperature
81+ * @trips_reached: trips below or at the current zone temperature
82+ * @trips_invalid: trips with invalid temperature
7183 * @mode: current mode of this thermal zone
7284 * @devdata: private pointer for device private data
7385 * @num_trips: number of trip points the thermal zone supports
@@ -88,20 +100,17 @@ struct thermal_governor { · 14 unmodified lines
88100 trip point.
89101 * @prev_high_trip: the above current temperature if you've crossed a
90102 passive trip point.
91− * @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
92103 * @ops: operations this &thermal_zone_device supports
93104 * @tzp: thermal zone parameters
94105 * @governor: pointer to the governor for this thermal zone
95106 * @governor_data: private pointer for governor data
96− * @thermal_instances: list of &struct thermal_instance of this thermal zone
97107 * @ida: &struct ida to generate unique id for this zone's cooling
98108 * devices
99109 * @lock: lock to protect thermal_instances list
100110 * @node: node in thermal_tz_list (in thermal_core.c)
101111 * @poll_queue: delayed work for polling
102112 * @notify_event: Last notification event
103− * @suspended: thermal zone suspend indicator
104− * @resuming: indicates whether or not thermal zone resume is in progress
113+ * @state: current state of the thermal zone
105114 * @trips: array of struct thermal_trip objects
106115 */
107116 struct thermal_zone_device {
@@ -111,6 +120,9 @@ struct thermal_zone_device { · 3 unmodified lines
111120 struct completion removal;
112121 struct completion resume;
113122 struct attribute_group trips_attribute_group;
123+ struct list_head trips_high;
124+ struct list_head trips_reached;
125+ struct list_head trips_invalid;
114126 enum thermal_device_mode mode;
115127 void *devdata;
116128 int num_trips;
@@ -123,25 +135,29 @@ struct thermal_zone_device { · 6 unmodified lines
123135 int passive;
124136 int prev_low_trip;
125137 int prev_high_trip;
126− atomic_t need_update;
127138 struct thermal_zone_device_ops ops;
128139 struct thermal_zone_params *tzp;
129140 struct thermal_governor *governor;
130141 void *governor_data;
131− struct list_head thermal_instances;
132142 struct ida ida;
133143 struct mutex lock;
134144 struct list_head node;
135145 struct delayed_work poll_queue;
136146 enum thermal_notify_event notify_event;
137− bool suspended;
138− bool resuming;
147+ u8 state;
139148 #ifdef CONFIG_THERMAL_DEBUGFS
140149 struct thermal_debugfs *debugfs;
141150 #endif
151+ struct list_head user_thresholds;
142152 struct thermal_trip_desc trips[] __counted_by(num_trips);
143153 };
144154
155+DEFINE_GUARD(thermal_zone, struct thermal_zone_device *, mutex_lock(&_T->lock),
156+ mutex_unlock(&_T->lock))
157+
158+DEFINE_GUARD(thermal_zone_reverse, struct thermal_zone_device *,
159+ mutex_unlock(&_T->lock), mutex_lock(&_T->lock))
160+
145161 /* Initial thermal zone temperature. */
146162 #define THERMAL_TEMP_INIT INT_MIN
147163
@@ -204,6 +220,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) · 56 unmodified lines
204220 }
205221
206222 void thermal_cdev_update(struct thermal_cooling_device *);
223+void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev);
207224 void __thermal_cdev_update(struct thermal_cooling_device *cdev);
208225
209226 int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip);
@@ -226,7 +243,7 @@ struct thermal_instance { · 16 unmodified lines
226243 struct device_attribute attr;
227244 char weight_attr_name[THERMAL_NAME_LENGTH];
228245 struct device_attribute weight_attr;
229− struct list_head tz_node; /* node in tz->thermal_instances */
246+ struct list_head trip_node; /* node in trip->thermal_instances */
230247 struct list_head cdev_node; /* node in cdev->thermal_instances */
231248 unsigned int weight; /* The weight of the cooling device */
232249 bool upper_no_limit;
@@ -261,8 +278,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz, int low, int high); · 28 unmodified lines
261278 int thermal_zone_trip_id(const struct thermal_zone_device *tz,
262279 const struct thermal_trip *trip);
263280 int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
264−void thermal_zone_trip_down(struct thermal_zone_device *tz,
265− const struct thermal_trip *trip);
266281 void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
267282 struct thermal_trip *trip, int hyst);
268283
drivers/thermal/thermal_debugfs.c+30−20
@@ -516,6 +516,19 @@ void thermal_debug_cdev_add(struct thermal_cooling_device *cdev, int state) · 515 unmodified lines
516516 cdev->debugfs = thermal_dbg;
517517 }
518518
519+static struct thermal_debugfs *thermal_debug_cdev_clear(struct thermal_cooling_device *cdev)
520+{
521+ struct thermal_debugfs *thermal_dbg;
522+
523+ guard(cooling_dev)(cdev);
524+
525+ thermal_dbg = cdev->debugfs;
526+ if (thermal_dbg)
527+ cdev->debugfs = NULL;
528+
529+ return thermal_dbg;
530+}
531+
519532 /**
520533 * thermal_debug_cdev_remove - Remove a cooling device debugfs entry
521534 *
@@ -527,17 +540,9 @@ void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) · 5 unmodified lines
527540 {
528541 struct thermal_debugfs *thermal_dbg;
529542
530− mutex_lock(&cdev->lock);
531−
532− thermal_dbg = cdev->debugfs;
533− if (!thermal_dbg) {
534− mutex_unlock(&cdev->lock);
543+ thermal_dbg = thermal_debug_cdev_clear(cdev);
544+ if (!thermal_dbg)
535545 return;
536− }
537−
538− cdev->debugfs = NULL;
539−
540− mutex_unlock(&cdev->lock);
541546
542547 mutex_lock(&thermal_dbg->lock);
543548
@@ -885,6 +890,19 @@ void thermal_debug_tz_add(struct thermal_zone_device *tz) · 341 unmodified lines
885890 tz->debugfs = thermal_dbg;
886891 }
887892
893+static struct thermal_debugfs *thermal_debug_tz_clear(struct thermal_zone_device *tz)
894+{
895+ struct thermal_debugfs *thermal_dbg;
896+
897+ guard(thermal_zone)(tz);
898+
899+ thermal_dbg = tz->debugfs;
900+ if (thermal_dbg)
901+ tz->debugfs = NULL;
902+
903+ return thermal_dbg;
904+}
905+
888906 void thermal_debug_tz_remove(struct thermal_zone_device *tz)
889907 {
890908 struct thermal_debugfs *thermal_dbg;
@@ -892,17 +910,9 @@ void thermal_debug_tz_remove(struct thermal_zone_device *tz) · 1 unmodified line
892910 struct tz_debugfs *tz_dbg;
893911 int *trips_crossed;
894912
895− mutex_lock(&tz->lock);
896−
897− thermal_dbg = tz->debugfs;
898− if (!thermal_dbg) {
899− mutex_unlock(&tz->lock);
913+ thermal_dbg = thermal_debug_tz_clear(tz);
914+ if (!thermal_dbg)
900915 return;
901− }
902−
903− tz->debugfs = NULL;
904−
905− mutex_unlock(&tz->lock);
906916
907917 tz_dbg = &thermal_dbg->tz_dbg;
908918
drivers/thermal/thermal_helpers.c+23−23
@@ -43,10 +43,11 @@ static bool thermal_instance_present(struct thermal_zone_device *tz, · 42 unmodified lines
4343 struct thermal_cooling_device *cdev,
4444 const struct thermal_trip *trip)
4545 {
46+ const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
4647 struct thermal_instance *ti;
4748
48− list_for_each_entry(ti, &tz->thermal_instances, tz_node) {
49− if (ti->trip == trip && ti->cdev == cdev)
49+ list_for_each_entry(ti, &td->thermal_instances, trip_node) {
50+ if (ti->cdev == cdev)
5051 return true;
5152 }
5253
@@ -57,17 +58,10 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz, · 4 unmodified lines
5758 const struct thermal_trip *trip,
5859 struct thermal_cooling_device *cdev)
5960 {
60− bool ret;
61+ guard(thermal_zone)(tz);
62+ guard(cooling_dev)(cdev);
6163
62− mutex_lock(&tz->lock);
63− mutex_lock(&cdev->lock);
64−
65− ret = thermal_instance_present(tz, cdev, trip);
66−
67− mutex_unlock(&cdev->lock);
68− mutex_unlock(&tz->lock);
69−
70− return ret;
64+ return thermal_instance_present(tz, cdev, trip);
7165 }
7266 EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev);
7367
@@ -137,19 +131,14 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) · 63 unmodified lines
137131 if (IS_ERR_OR_NULL(tz))
138132 return -EINVAL;
139133
140− mutex_lock(&tz->lock);
134+ guard(thermal_zone)(tz);
141135
142− if (!tz->ops.get_temp) {
143− ret = -EINVAL;
144− goto unlock;
145− }
136+ if (!tz->ops.get_temp)
137+ return -EINVAL;
146138
147139 ret = __thermal_zone_get_temp(tz, temp);
148140 if (!ret && *temp <= THERMAL_TEMP_INVALID)
149− ret = -ENODATA;
150−
151−unlock:
152− mutex_unlock(&tz->lock);
141+ return -ENODATA;
153142
154143 return ret;
155144 }
@@ -201,12 +190,23 @@ void __thermal_cdev_update(struct thermal_cooling_device *cdev) · 45 unmodified lines
201190 */
202191 void thermal_cdev_update(struct thermal_cooling_device *cdev)
203192 {
204− mutex_lock(&cdev->lock);
193+ guard(cooling_dev)(cdev);
194+
205195 if (!cdev->updated) {
206196 __thermal_cdev_update(cdev);
207197 cdev->updated = true;
208198 }
209− mutex_unlock(&cdev->lock);
199+}
200+
201+/**
202+ * thermal_cdev_update_nocheck() - Unconditionally update cooling device state
203+ * @cdev: Target cooling device.
204+ */
205+void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev)
206+{
207+ guard(cooling_dev)(cdev);
208+
209+ __thermal_cdev_update(cdev);
210210 }
211211
212212 /**
drivers/thermal/thermal_hwmon.c+1−4
@@ -78,12 +78,9 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf) · 77 unmodified lines
7878 int temperature;
7979 int ret;
8080
81− mutex_lock(&tz->lock);
81+ guard(thermal_zone)(tz);
8282
8383 ret = tz->ops.get_crit_temp(tz, &temperature);
84−
85− mutex_unlock(&tz->lock);
86−
8784 if (ret)
8885 return ret;
8986
drivers/thermal/thermal_netlink.c+232−21
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <linux/module.h>
1010 #include <linux/notifier.h>
1111 #include <linux/kernel.h>
12+#include <net/sock.h>
1213 #include <net/genetlink.h>
1314 #include <uapi/linux/thermal.h>
1415
@@ -49,6 +50,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = · 34 unmodified lines
4950 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 },
5051 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 },
5152 [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 },
53+
54+ /* Thresholds */
55+ [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED },
56+ [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 },
57+ [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 },
5258 };
5359
5460 struct param {
@@ -62,6 +68,8 @@ struct param { · 7 unmodified lines
6268 int trip_type;
6369 int trip_hyst;
6470 int temp;
71+ int prev_temp;
72+ int direction;
6573 int cdev_state;
6674 int cdev_max_state;
6775 struct thermal_genl_cpu_caps *cpu_capabilities;
@@ -234,6 +242,34 @@ out_cancel_nest: · 166 unmodified lines
234242 return -EMSGSIZE;
235243 }
236244
245+static int thermal_genl_event_threshold_add(struct param *p)
246+{
247+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
248+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp) ||
249+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction))
250+ return -EMSGSIZE;
251+
252+ return 0;
253+}
254+
255+static int thermal_genl_event_threshold_flush(struct param *p)
256+{
257+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
258+ return -EMSGSIZE;
259+
260+ return 0;
261+}
262+
263+static int thermal_genl_event_threshold_up(struct param *p)
264+{
265+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
266+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_PREV_TEMP, p->prev_temp) ||
267+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
268+ return -EMSGSIZE;
269+
270+ return 0;
271+}
272+
237273 int thermal_genl_event_tz_delete(struct param *p)
238274 __attribute__((alias("thermal_genl_event_tz")));
239275
@@ -246,6 +282,12 @@ int thermal_genl_event_tz_disable(struct param *p) · 6 unmodified lines
246282 int thermal_genl_event_tz_trip_down(struct param *p)
247283 __attribute__((alias("thermal_genl_event_tz_trip_up")));
248284
285+int thermal_genl_event_threshold_delete(struct param *p)
286+ __attribute__((alias("thermal_genl_event_threshold_add")));
287+
288+int thermal_genl_event_threshold_down(struct param *p)
289+ __attribute__((alias("thermal_genl_event_threshold_up")));
290+
249291 static cb_t event_cb[] = {
250292 [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,
251293 [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,
@@ -259,6 +301,11 @@ static cb_t event_cb[] = { · 7 unmodified lines
259301 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
260302 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,
261303 [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,
304+ [THERMAL_GENL_EVENT_THRESHOLD_ADD] = thermal_genl_event_threshold_add,
305+ [THERMAL_GENL_EVENT_THRESHOLD_DELETE] = thermal_genl_event_threshold_delete,
306+ [THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = thermal_genl_event_threshold_flush,
307+ [THERMAL_GENL_EVENT_THRESHOLD_DOWN] = thermal_genl_event_threshold_down,
308+ [THERMAL_GENL_EVENT_THRESHOLD_UP] = thermal_genl_event_threshold_up,
262309 };
263310
264311 /*
@@ -401,6 +448,43 @@ int thermal_genl_cpu_capability_event(int count, · 136 unmodified lines
401448 }
402449 EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
403450
451+int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
452+ int temperature, int direction)
453+{
454+ struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
455+
456+ return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD, &p);
457+}
458+
459+int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
460+ int temperature, int direction)
461+{
462+ struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
463+
464+ return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE, &p);
465+}
466+
467+int thermal_notify_threshold_flush(const struct thermal_zone_device *tz)
468+{
469+ struct param p = { .tz_id = tz->id };
470+
471+ return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH, &p);
472+}
473+
474+int thermal_notify_threshold_down(const struct thermal_zone_device *tz)
475+{
476+ struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature };
477+
478+ return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN, &p);
479+}
480+
481+int thermal_notify_threshold_up(const struct thermal_zone_device *tz)
482+{
483+ struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature };
484+
485+ return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP, &p);
486+}
487+
404488 /*************************** Command encoding ********************************/
405489
406490 static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
@@ -459,7 +543,7 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) · 52 unmodified lines
459543 if (!start_trip)
460544 return -EMSGSIZE;
461545
462− mutex_lock(&tz->lock);
546+ guard(thermal_zone)(tz);
463547
464548 for_each_trip_desc(tz, td) {
465549 const struct thermal_trip *trip = &td->trip;
@@ -469,19 +553,12 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) · 3 unmodified lines
469553 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||
470554 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) ||
471555 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis))
472− goto out_cancel_nest;
556+ return -EMSGSIZE;
473557 }
474558
475− mutex_unlock(&tz->lock);
476−
477559 nla_nest_end(msg, start_trip);
478560
479561 return 0;
480−
481−out_cancel_nest:
482− mutex_unlock(&tz->lock);
483−
484− return -EMSGSIZE;
485562 }
486563
487564 static int thermal_genl_cmd_tz_get_temp(struct param *p)
@@ -512,7 +589,7 @@ static int thermal_genl_cmd_tz_get_temp(struct param *p) · 24 unmodified lines
512589 static int thermal_genl_cmd_tz_get_gov(struct param *p)
513590 {
514591 struct sk_buff *msg = p->msg;
515− int id, ret = 0;
592+ int id;
516593
517594 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
518595 return -EINVAL;
@@ -523,16 +600,14 @@ static int thermal_genl_cmd_tz_get_gov(struct param *p) · 4 unmodified lines
523600 if (!tz)
524601 return -EINVAL;
525602
526− mutex_lock(&tz->lock);
603+ guard(thermal_zone)(tz);
527604
528605 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
529606 nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
530607 tz->governor->name))
531− ret = -EMSGSIZE;
532−
533− mutex_unlock(&tz->lock);
608+ return -EMSGSIZE;
534609
535− return ret;
610+ return 0;
536611 }
537612
538613 static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
@@ -572,12 +647,128 @@ out_cancel_nest: · 33 unmodified lines
572647 return ret;
573648 }
574649
650+static int __thermal_genl_cmd_threshold_get(struct user_threshold *threshold, void *arg)
651+{
652+ struct sk_buff *msg = arg;
653+
654+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, threshold->temperature) ||
655+ nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, threshold->direction))
656+ return -1;
657+
658+ return 0;
659+}
660+
661+static int thermal_genl_cmd_threshold_get(struct param *p)
662+{
663+ struct sk_buff *msg = p->msg;
664+ struct nlattr *start_trip;
665+ int id, ret;
666+
667+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
668+ return -EINVAL;
669+
670+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
671+
672+ CLASS(thermal_zone_get_by_id, tz)(id);
673+ if (!tz)
674+ return -EINVAL;
675+
676+ start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_THRESHOLD);
677+ if (!start_trip)
678+ return -EMSGSIZE;
679+
680+ ret = thermal_thresholds_for_each(tz, __thermal_genl_cmd_threshold_get, msg);
681+ if (ret)
682+ return -EMSGSIZE;
683+
684+ nla_nest_end(msg, start_trip);
685+
686+ return 0;
687+}
688+
689+static int thermal_genl_cmd_threshold_add(struct param *p)
690+{
691+ int id, temp, direction;
692+
693+ if (!capable(CAP_SYS_ADMIN))
694+ return -EPERM;
695+
696+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] ||
697+ !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] ||
698+ !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION])
699+ return -EINVAL;
700+
701+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
702+ temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]);
703+ direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]);
704+
705+ CLASS(thermal_zone_get_by_id, tz)(id);
706+ if (!tz)
707+ return -EINVAL;
708+
709+ guard(thermal_zone)(tz);
710+
711+ return thermal_thresholds_add(tz, temp, direction);
712+}
713+
714+static int thermal_genl_cmd_threshold_delete(struct param *p)
715+{
716+ int id, temp, direction;
717+
718+ if (!capable(CAP_SYS_ADMIN))
719+ return -EPERM;
720+
721+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] ||
722+ !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] ||
723+ !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION])
724+ return -EINVAL;
725+
726+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
727+ temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]);
728+ direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]);
729+
730+ CLASS(thermal_zone_get_by_id, tz)(id);
731+ if (!tz)
732+ return -EINVAL;
733+
734+ guard(thermal_zone)(tz);
735+
736+ return thermal_thresholds_delete(tz, temp, direction);
737+}
738+
739+static int thermal_genl_cmd_threshold_flush(struct param *p)
740+{
741+ int id;
742+
743+ if (!capable(CAP_SYS_ADMIN))
744+ return -EPERM;
745+
746+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
747+ return -EINVAL;
748+
749+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
750+
751+ CLASS(thermal_zone_get_by_id, tz)(id);
752+ if (!tz)
753+ return -EINVAL;
754+
755+ guard(thermal_zone)(tz);
756+
757+ thermal_thresholds_flush(tz);
758+
759+ return 0;
760+}
761+
575762 static cb_t cmd_cb[] = {
576− [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id,
577− [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip,
578− [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp,
579− [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov,
580− [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get,
763+ [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id,
764+ [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip,
765+ [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp,
766+ [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov,
767+ [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get,
768+ [THERMAL_GENL_CMD_THRESHOLD_GET] = thermal_genl_cmd_threshold_get,
769+ [THERMAL_GENL_CMD_THRESHOLD_ADD] = thermal_genl_cmd_threshold_add,
770+ [THERMAL_GENL_CMD_THRESHOLD_DELETE] = thermal_genl_cmd_threshold_delete,
771+ [THERMAL_GENL_CMD_THRESHOLD_FLUSH] = thermal_genl_cmd_threshold_flush,
581772 };
582773
583774 static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
@@ -688,6 +879,26 @@ static const struct genl_small_ops thermal_genl_ops[] = { · 104 unmodified lines
688879 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
689880 .dumpit = thermal_genl_cmd_dumpit,
690881 },
882+ {
883+ .cmd = THERMAL_GENL_CMD_THRESHOLD_GET,
884+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
885+ .doit = thermal_genl_cmd_doit,
886+ },
887+ {
888+ .cmd = THERMAL_GENL_CMD_THRESHOLD_ADD,
889+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
890+ .doit = thermal_genl_cmd_doit,
891+ },
892+ {
893+ .cmd = THERMAL_GENL_CMD_THRESHOLD_DELETE,
894+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
895+ .doit = thermal_genl_cmd_doit,
896+ },
897+ {
898+ .cmd = THERMAL_GENL_CMD_THRESHOLD_FLUSH,
899+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
900+ .doit = thermal_genl_cmd_doit,
901+ },
691902 };
692903
693904 static struct genl_family thermal_genl_family __ro_after_init = {
@@ -700,7 +911,7 @@ static struct genl_family thermal_genl_family __ro_after_init = { · 6 unmodified lines
700911 .unbind = thermal_genl_unbind,
701912 .small_ops = thermal_genl_ops,
702913 .n_small_ops = ARRAY_SIZE(thermal_genl_ops),
703− .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1,
914+ .resv_start_op = __THERMAL_GENL_CMD_MAX,
704915 .mcgrps = thermal_genl_mcgrps,
705916 .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
706917 };
drivers/thermal/thermal_netlink.h+34−0
@@ -53,6 +53,13 @@ int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, · 52 unmodified lines
5353 int thermal_genl_sampling_temp(int id, int temp);
5454 int thermal_genl_cpu_capability_event(int count,
5555 struct thermal_genl_cpu_caps *caps);
56+int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
57+ int temperature, int direction);
58+int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
59+ int temperature, int direction);
60+int thermal_notify_threshold_flush(const struct thermal_zone_device *tz);
61+int thermal_notify_threshold_down(const struct thermal_zone_device *tz);
62+int thermal_notify_threshold_up(const struct thermal_zone_device *tz);
5663 #else
5764 static inline int thermal_netlink_init(void)
5865 {
@@ -139,6 +146,33 @@ static inline int thermal_genl_cpu_capability_event(int count, struct thermal_ge · 80 unmodified lines
139146 return 0;
140147 }
141148
149+static inline int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
150+ int temperature, int direction)
151+{
152+ return 0;
153+}
154+
155+static inline int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
156+ int temperature, int direction)
157+{
158+ return 0;
159+}
160+
161+static inline int thermal_notify_threshold_flush(const struct thermal_zone_device *tz)
162+{
163+ return 0;
164+}
165+
166+static inline int thermal_notify_threshold_down(const struct thermal_zone_device *tz)
167+{
168+ return 0;
169+}
170+
171+static inline int thermal_notify_threshold_up(const struct thermal_zone_device *tz)
172+{
173+ return 0;
174+}
175+
142176 static inline void __init thermal_netlink_exit(void) {}
143177
144178 #endif /* CONFIG_THERMAL_NETLINK */
drivers/thermal/thermal_sysfs.c+53−79
@@ -50,13 +50,13 @@ static ssize_t · 49 unmodified lines
5050 mode_show(struct device *dev, struct device_attribute *attr, char *buf)
5151 {
5252 struct thermal_zone_device *tz = to_thermal_zone(dev);
53− int enabled;
5453
55− mutex_lock(&tz->lock);
56− enabled = tz->mode == THERMAL_DEVICE_ENABLED;
57− mutex_unlock(&tz->lock);
54+ guard(thermal_zone)(tz);
5855
59− return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
56+ if (tz->mode == THERMAL_DEVICE_ENABLED)
57+ return sprintf(buf, "enabled\n");
58+
59+ return sprintf(buf, "disabled\n");
6060 }
6161
6262 static ssize_t
@@ -103,38 +103,34 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, · 40 unmodified lines
103103 {
104104 struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);
105105 struct thermal_zone_device *tz = to_thermal_zone(dev);
106− int ret, temp;
106+ int temp;
107107
108− ret = kstrtoint(buf, 10, &temp);
109− if (ret)
108+ if (kstrtoint(buf, 10, &temp))
110109 return -EINVAL;
111110
112− mutex_lock(&tz->lock);
111+ guard(thermal_zone)(tz);
113112
114113 if (temp == trip->temperature)
115− goto unlock;
114+ return count;
116115
117116 /* Arrange the condition to avoid integer overflows. */
118117 if (temp != THERMAL_TEMP_INVALID &&
119− temp <= trip->hysteresis + THERMAL_TEMP_INVALID) {
120− ret = -EINVAL;
121− goto unlock;
122− }
118+ temp <= trip->hysteresis + THERMAL_TEMP_INVALID)
119+ return -EINVAL;
123120
124121 if (tz->ops.set_trip_temp) {
122+ int ret;
123+
125124 ret = tz->ops.set_trip_temp(tz, trip, temp);
126125 if (ret)
127− goto unlock;
126+ return ret;
128127 }
129128
130129 thermal_zone_set_trip_temp(tz, trip, temp);
131130
132131 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
133132
134−unlock:
135− mutex_unlock(&tz->lock);
136−
137− return ret ? ret : count;
133+ return count;
138134 }
139135
140136 static ssize_t
@@ -152,16 +148,15 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, · 11 unmodified lines
152148 {
153149 struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);
154150 struct thermal_zone_device *tz = to_thermal_zone(dev);
155− int ret, hyst;
151+ int hyst;
156152
157− ret = kstrtoint(buf, 10, &hyst);
158− if (ret || hyst < 0)
153+ if (kstrtoint(buf, 10, &hyst) || hyst < 0)
159154 return -EINVAL;
160155
161− mutex_lock(&tz->lock);
156+ guard(thermal_zone)(tz);
162157
163158 if (hyst == trip->hysteresis)
164− goto unlock;
159+ return count;
165160
166161 /*
167162 * Allow the hysteresis to be updated when the temperature is invalid
@@ -171,22 +166,17 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, · 3 unmodified lines
171166 */
172167 if (trip->temperature == THERMAL_TEMP_INVALID) {
173168 WRITE_ONCE(trip->hysteresis, hyst);
174− goto unlock;
169+ return count;
175170 }
176171
177− if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) {
178− ret = -EINVAL;
179− goto unlock;
180− }
172+ if (trip->temperature - hyst <= THERMAL_TEMP_INVALID)
173+ return -EINVAL;
181174
182175 thermal_zone_set_trip_hyst(tz, trip, hyst);
183176
184177 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
185178
186−unlock:
187− mutex_unlock(&tz->lock);
188−
189− return ret ? ret : count;
179+ return count;
190180 }
191181
192182 static ssize_t
@@ -236,25 +226,26 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, · 43 unmodified lines
236226 const char *buf, size_t count)
237227 {
238228 struct thermal_zone_device *tz = to_thermal_zone(dev);
239− int ret = 0;
240229 int temperature;
241230
242231 if (kstrtoint(buf, 10, &temperature))
243232 return -EINVAL;
244233
245− mutex_lock(&tz->lock);
234+ guard(thermal_zone)(tz);
246235
247− if (!tz->ops.set_emul_temp)
248− tz->emul_temperature = temperature;
249− else
250− ret = tz->ops.set_emul_temp(tz, temperature);
236+ if (tz->ops.set_emul_temp) {
237+ int ret;
251238
252− if (!ret)
253− __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
239+ ret = tz->ops.set_emul_temp(tz, temperature);
240+ if (ret)
241+ return ret;
242+ } else {
243+ tz->emul_temperature = temperature;
244+ }
254245
255− mutex_unlock(&tz->lock);
246+ __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
256247
257− return ret ? ret : count;
248+ return count;
258249 }
259250 static DEVICE_ATTR_WO(emul_temp);
260251 #endif
@@ -553,14 +544,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, · 292 unmodified lines
553544 if (state > cdev->max_state)
554545 return -EINVAL;
555546
556− mutex_lock(&cdev->lock);
547+ guard(cooling_dev)(cdev);
557548
558549 result = cdev->ops->set_cur_state(cdev, state);
559− if (!result)
560− thermal_cooling_device_stats_update(cdev, state);
550+ if (result)
551+ return result;
561552
562− mutex_unlock(&cdev->lock);
563− return result ? result : count;
553+ thermal_cooling_device_stats_update(cdev, state);
554+
555+ return count;
564556 }
565557
566558 static struct device_attribute
@@ -634,21 +626,18 @@ static ssize_t total_trans_show(struct device *dev, · 67 unmodified lines
634626 {
635627 struct thermal_cooling_device *cdev = to_cooling_device(dev);
636628 struct cooling_dev_stats *stats;
637− int ret = 0;
629+ int ret;
638630
639− mutex_lock(&cdev->lock);
631+ guard(cooling_dev)(cdev);
640632
641633 stats = cdev->stats;
642634 if (!stats)
643− goto unlock;
635+ return 0;
644636
645637 spin_lock(&stats->lock);
646638 ret = sprintf(buf, "%u\n", stats->total_trans);
647639 spin_unlock(&stats->lock);
648640
649−unlock:
650− mutex_unlock(&cdev->lock);
651−
652641 return ret;
653642 }
654643
@@ -661,11 +650,11 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 6 unmodified lines
661650 ssize_t len = 0;
662651 int i;
663652
664− mutex_lock(&cdev->lock);
653+ guard(cooling_dev)(cdev);
665654
666655 stats = cdev->stats;
667656 if (!stats)
668− goto unlock;
657+ return 0;
669658
670659 spin_lock(&stats->lock);
671660
@@ -677,9 +666,6 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 5 unmodified lines
677666 }
678667 spin_unlock(&stats->lock);
679668
680−unlock:
681− mutex_unlock(&cdev->lock);
682−
683669 return len;
684670 }
685671
@@ -691,11 +677,11 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 5 unmodified lines
691677 struct cooling_dev_stats *stats;
692678 int i, states;
693679
694− mutex_lock(&cdev->lock);
680+ guard(cooling_dev)(cdev);
695681
696682 stats = cdev->stats;
697683 if (!stats)
698− goto unlock;
684+ return count;
699685
700686 states = cdev->max_state + 1;
701687
@@ -711,9 +697,6 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 9 unmodified lines
711697
712698 spin_unlock(&stats->lock);
713699
714−unlock:
715− mutex_unlock(&cdev->lock);
716−
717700 return count;
718701 }
719702
@@ -725,13 +708,11 @@ static ssize_t trans_table_show(struct device *dev, · 5 unmodified lines
725708 ssize_t len = 0;
726709 int i, j;
727710
728− mutex_lock(&cdev->lock);
711+ guard(cooling_dev)(cdev);
729712
730713 stats = cdev->stats;
731− if (!stats) {
732− len = -ENODATA;
733− goto unlock;
734− }
714+ if (!stats)
715+ return -ENODATA;
735716
736717 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
737718 len += snprintf(buf + len, PAGE_SIZE - len, " : ");
@@ -740,10 +721,8 @@ static ssize_t trans_table_show(struct device *dev, · 2 unmodified lines
740721 break;
741722 len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
742723 }
743− if (len >= PAGE_SIZE) {
744− len = PAGE_SIZE;
745− goto unlock;
746− }
724+ if (len >= PAGE_SIZE)
725+ return PAGE_SIZE;
747726
748727 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
749728
@@ -769,9 +748,6 @@ static ssize_t trans_table_show(struct device *dev, · 19 unmodified lines
769748 len = -EFBIG;
770749 }
771750
772−unlock:
773− mutex_unlock(&cdev->lock);
774−
775751 return len;
776752 }
777753
@@ -894,13 +870,11 @@ ssize_t weight_store(struct device *dev, struct device_attribute *attr, · 116 unmodified lines
894870 instance = container_of(attr, struct thermal_instance, weight_attr);
895871
896872 /* Don't race with governors using the 'weight' value */
897− mutex_lock(&tz->lock);
873+ guard(thermal_zone)(tz);
898874
899875 instance->weight = weight;
900876
901877 thermal_governor_update_tz(tz, THERMAL_INSTANCE_WEIGHT_CHANGED);
902878
903− mutex_unlock(&tz->lock);
904−
905879 return count;
906880 }
drivers/thermal/thermal_thresholds.c+240−0
@@ -0,0 +1,240 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * Copyright 2024 Linaro Limited
4+ *
5+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
6+ *
7+ * Thermal thresholds
8+ */
9+#include <linux/list.h>
10+#include <linux/list_sort.h>
11+#include <linux/slab.h>
12+
13+#include "thermal_core.h"
14+#include "thermal_thresholds.h"
15+
16+int thermal_thresholds_init(struct thermal_zone_device *tz)
17+{
18+ INIT_LIST_HEAD(&tz->user_thresholds);
19+
20+ return 0;
21+}
22+
23+static void __thermal_thresholds_flush(struct thermal_zone_device *tz)
24+{
25+ struct list_head *thresholds = &tz->user_thresholds;
26+ struct user_threshold *entry, *tmp;
27+
28+ list_for_each_entry_safe(entry, tmp, thresholds, list_node) {
29+ list_del(&entry->list_node);
30+ kfree(entry);
31+ }
32+}
33+
34+void thermal_thresholds_flush(struct thermal_zone_device *tz)
35+{
36+ lockdep_assert_held(&tz->lock);
37+
38+ __thermal_thresholds_flush(tz);
39+
40+ thermal_notify_threshold_flush(tz);
41+
42+ __thermal_zone_device_update(tz, THERMAL_TZ_FLUSH_THRESHOLDS);
43+}
44+
45+void thermal_thresholds_exit(struct thermal_zone_device *tz)
46+{
47+ __thermal_thresholds_flush(tz);
48+}
49+
50+static int __thermal_thresholds_cmp(void *data,
51+ const struct list_head *l1,
52+ const struct list_head *l2)
53+{
54+ struct user_threshold *t1 = container_of(l1, struct user_threshold, list_node);
55+ struct user_threshold *t2 = container_of(l2, struct user_threshold, list_node);
56+
57+ return t1->temperature - t2->temperature;
58+}
59+
60+static struct user_threshold *__thermal_thresholds_find(const struct list_head *thresholds,
61+ int temperature)
62+{
63+ struct user_threshold *t;
64+
65+ list_for_each_entry(t, thresholds, list_node)
66+ if (t->temperature == temperature)
67+ return t;
68+
69+ return NULL;
70+}
71+
72+static bool __thermal_threshold_is_crossed(struct user_threshold *threshold, int temperature,
73+ int last_temperature, int direction,
74+ int *low, int *high)
75+{
76+
77+ if (temperature >= threshold->temperature) {
78+ if (threshold->temperature > *low &&
79+ THERMAL_THRESHOLD_WAY_DOWN & threshold->direction)
80+ *low = threshold->temperature;
81+
82+ if (last_temperature < threshold->temperature &&
83+ threshold->direction & direction)
84+ return true;
85+ } else {
86+ if (threshold->temperature < *high && THERMAL_THRESHOLD_WAY_UP
87+ & threshold->direction)
88+ *high = threshold->temperature;
89+
90+ if (last_temperature >= threshold->temperature &&
91+ threshold->direction & direction)
92+ return true;
93+ }
94+
95+ return false;
96+}
97+
98+static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int temperature,
99+ int last_temperature, int *low, int *high)
100+{
101+ struct user_threshold *t;
102+
103+ list_for_each_entry(t, thresholds, list_node) {
104+ if (__thermal_threshold_is_crossed(t, temperature, last_temperature,
105+ THERMAL_THRESHOLD_WAY_UP, low, high))
106+ return true;
107+ }
108+
109+ return false;
110+}
111+
112+static bool thermal_thresholds_handle_dropping(struct list_head *thresholds, int temperature,
113+ int last_temperature, int *low, int *high)
114+{
115+ struct user_threshold *t;
116+
117+ list_for_each_entry_reverse(t, thresholds, list_node) {
118+ if (__thermal_threshold_is_crossed(t, temperature, last_temperature,
119+ THERMAL_THRESHOLD_WAY_DOWN, low, high))
120+ return true;
121+ }
122+
123+ return false;
124+}
125+
126+void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high)
127+{
128+ struct list_head *thresholds = &tz->user_thresholds;
129+
130+ int temperature = tz->temperature;
131+ int last_temperature = tz->last_temperature;
132+
133+ lockdep_assert_held(&tz->lock);
134+
135+ /*
136+ * We need a second update in order to detect a threshold being crossed
137+ */
138+ if (last_temperature == THERMAL_TEMP_INVALID)
139+ return;
140+
141+ /*
142+ * The temperature is stable, so obviously we can not have
143+ * crossed a threshold.
144+ */
145+ if (last_temperature == temperature)
146+ return;
147+
148+ /*
149+ * Since last update the temperature:
150+ * - increased : thresholds are crossed the way up
151+ * - decreased : thresholds are crossed the way down
152+ */
153+ if (temperature > last_temperature) {
154+ if (thermal_thresholds_handle_raising(thresholds, temperature,
155+ last_temperature, low, high))
156+ thermal_notify_threshold_up(tz);
157+ } else {
158+ if (thermal_thresholds_handle_dropping(thresholds, temperature,
159+ last_temperature, low, high))
160+ thermal_notify_threshold_down(tz);
161+ }
162+}
163+
164+int thermal_thresholds_add(struct thermal_zone_device *tz,
165+ int temperature, int direction)
166+{
167+ struct list_head *thresholds = &tz->user_thresholds;
168+ struct user_threshold *t;
169+
170+ lockdep_assert_held(&tz->lock);
171+
172+ t = __thermal_thresholds_find(thresholds, temperature);
173+ if (t) {
174+ if (t->direction == direction)
175+ return -EEXIST;
176+
177+ t->direction |= direction;
178+ } else {
179+
180+ t = kmalloc(sizeof(*t), GFP_KERNEL);
181+ if (!t)
182+ return -ENOMEM;
183+
184+ INIT_LIST_HEAD(&t->list_node);
185+ t->temperature = temperature;
186+ t->direction = direction;
187+ list_add(&t->list_node, thresholds);
188+ list_sort(NULL, thresholds, __thermal_thresholds_cmp);
189+ }
190+
191+ thermal_notify_threshold_add(tz, temperature, direction);
192+
193+ __thermal_zone_device_update(tz, THERMAL_TZ_ADD_THRESHOLD);
194+
195+ return 0;
196+}
197+
198+int thermal_thresholds_delete(struct thermal_zone_device *tz,
199+ int temperature, int direction)
200+{
201+ struct list_head *thresholds = &tz->user_thresholds;
202+ struct user_threshold *t;
203+
204+ lockdep_assert_held(&tz->lock);
205+
206+ t = __thermal_thresholds_find(thresholds, temperature);
207+ if (!t)
208+ return -ENOENT;
209+
210+ if (t->direction == direction) {
211+ list_del(&t->list_node);
212+ kfree(t);
213+ } else {
214+ t->direction &= ~direction;
215+ }
216+
217+ thermal_notify_threshold_delete(tz, temperature, direction);
218+
219+ __thermal_zone_device_update(tz, THERMAL_TZ_DEL_THRESHOLD);
220+
221+ return 0;
222+}
223+
224+int thermal_thresholds_for_each(struct thermal_zone_device *tz,
225+ int (*cb)(struct user_threshold *, void *arg), void *arg)
226+{
227+ struct list_head *thresholds = &tz->user_thresholds;
228+ struct user_threshold *entry;
229+ int ret;
230+
231+ guard(thermal_zone)(tz);
232+
233+ list_for_each_entry(entry, thresholds, list_node) {
234+ ret = cb(entry, arg);
235+ if (ret)
236+ return ret;
237+ }
238+
239+ return 0;
240+}
drivers/thermal/thermal_thresholds.h+19−0
@@ -0,0 +1,19 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+#ifndef __THERMAL_THRESHOLDS_H__
3+#define __THERMAL_THRESHOLDS_H__
4+
5+struct user_threshold {
6+ struct list_head list_node;
7+ int temperature;
8+ int direction;
9+};
10+
11+int thermal_thresholds_init(struct thermal_zone_device *tz);
12+void thermal_thresholds_exit(struct thermal_zone_device *tz);
13+void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high);
14+void thermal_thresholds_flush(struct thermal_zone_device *tz);
15+int thermal_thresholds_add(struct thermal_zone_device *tz, int temperature, int direction);
16+int thermal_thresholds_delete(struct thermal_zone_device *tz, int temperature, int direction);
17+int thermal_thresholds_for_each(struct thermal_zone_device *tz,
18+ int (*cb)(struct user_threshold *, void *arg), void *arg);
19+#endif
drivers/thermal/thermal_trip.c+2−46
@@ -45,13 +45,9 @@ int thermal_zone_for_each_trip(struct thermal_zone_device *tz, · 44 unmodified lines
4545 int (*cb)(struct thermal_trip *, void *),
4646 void *data)
4747 {
48− int ret;
49−
50− mutex_lock(&tz->lock);
51− ret = for_each_thermal_trip(tz, cb, data);
52− mutex_unlock(&tz->lock);
48+ guard(thermal_zone)(tz);
5349
54− return ret;
50+ return for_each_thermal_trip(tz, cb, data);
5551 }
5652 EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);
5753
@@ -92,43 +88,3 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz, · 34 unmodified lines
9288 */
9389 return trip_to_trip_desc(trip) - tz->trips;
9490 }
95−
96−void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
97− struct thermal_trip *trip, int hyst)
98−{
99− WRITE_ONCE(trip->hysteresis, hyst);
100− thermal_notify_tz_trip_change(tz, trip);
101−}
102−
103−void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
104− struct thermal_trip *trip, int temp)
105−{
106− if (trip->temperature == temp)
107− return;
108−
109− WRITE_ONCE(trip->temperature, temp);
110− thermal_notify_tz_trip_change(tz, trip);
111−
112− if (temp == THERMAL_TEMP_INVALID) {
113− struct thermal_trip_desc *td = trip_to_trip_desc(trip);
114−
115− if (tz->temperature >= td->threshold) {
116− /*
117− * The trip has been crossed on the way up, so some
118− * adjustments are needed to compensate for the lack
119− * of it going forward.
120− */
121− if (trip->type == THERMAL_TRIP_PASSIVE) {
122− tz->passive--;
123− WARN_ON_ONCE(tz->passive < 0);
124− }
125− thermal_zone_trip_down(tz, trip);
126− }
127− /*
128− * Invalidate the threshold to avoid triggering a spurious
129− * trip crossing notification when the trip becomes valid.
130− */
131− td->threshold = INT_MAX;
132− }
133−}
134−EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
include/linux/thermal.h+6−0
@@ -56,6 +56,9 @@ enum thermal_notify_event { · 55 unmodified lines
5656 THERMAL_TZ_UNBIND_CDEV, /* Cooling dev is unbind from the thermal zone */
5757 THERMAL_INSTANCE_WEIGHT_CHANGED, /* Thermal instance weight changed */
5858 THERMAL_TZ_RESUME, /* Thermal zone is resuming after system sleep */
59+ THERMAL_TZ_ADD_THRESHOLD, /* Threshold added */
60+ THERMAL_TZ_DEL_THRESHOLD, /* Threshold deleted */
61+ THERMAL_TZ_FLUSH_THRESHOLDS, /* All thresholds deleted */
5962 };
6063
6164 /**
@@ -137,6 +140,9 @@ struct thermal_cooling_device { · 75 unmodified lines
137140 #endif
138141 };
139142
143+DEFINE_GUARD(cooling_dev, struct thermal_cooling_device *, mutex_lock(&_T->lock),
144+ mutex_unlock(&_T->lock))
145+
140146 /* Structure to define Thermal Zone parameters */
141147 struct thermal_zone_params {
142148 const char *governor_name;
include/uapi/linux/thermal.h+22−7
@@ -3,6 +3,8 @@ · 2 unmodified lines
33 #define _UAPI_LINUX_THERMAL_H
44
55 #define THERMAL_NAME_LENGTH 20
6+#define THERMAL_THRESHOLD_WAY_UP BIT(0)
7+#define THERMAL_THRESHOLD_WAY_DOWN BIT(1)
68
79 enum thermal_device_mode {
810 THERMAL_DEVICE_DISABLED = 0,
@@ -18,7 +20,7 @@ enum thermal_trip_type { · 9 unmodified lines
1820
1921 /* Adding event notification support elements */
2022 #define THERMAL_GENL_FAMILY_NAME "thermal"
21−#define THERMAL_GENL_VERSION 0x01
23+#define THERMAL_GENL_VERSION 0x02
2224 #define THERMAL_GENL_SAMPLING_GROUP_NAME "sampling"
2325 #define THERMAL_GENL_EVENT_GROUP_NAME "event"
2426
@@ -28,6 +30,7 @@ enum thermal_genl_attr { · 3 unmodified lines
2830 THERMAL_GENL_ATTR_TZ,
2931 THERMAL_GENL_ATTR_TZ_ID,
3032 THERMAL_GENL_ATTR_TZ_TEMP,
33+ THERMAL_GENL_ATTR_TZ_PREV_TEMP,
3134 THERMAL_GENL_ATTR_TZ_TRIP,
3235 THERMAL_GENL_ATTR_TZ_TRIP_ID,
3336 THERMAL_GENL_ATTR_TZ_TRIP_TYPE,
@@ -48,6 +51,9 @@ enum thermal_genl_attr { · 14 unmodified lines
4851 THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
4952 THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
5053 THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
54+ THERMAL_GENL_ATTR_THRESHOLD,
55+ THERMAL_GENL_ATTR_THRESHOLD_TEMP,
56+ THERMAL_GENL_ATTR_THRESHOLD_DIRECTION,
5157 __THERMAL_GENL_ATTR_MAX,
5258 };
5359 #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
@@ -75,6 +81,11 @@ enum thermal_genl_event { · 21 unmodified lines
7581 THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */
7682 THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */
7783 THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, /* CPU capability changed */
84+ THERMAL_GENL_EVENT_THRESHOLD_ADD, /* A thresold has been added */
85+ THERMAL_GENL_EVENT_THRESHOLD_DELETE, /* A thresold has been deleted */
86+ THERMAL_GENL_EVENT_THRESHOLD_FLUSH, /* All thresolds have been deleted */
87+ THERMAL_GENL_EVENT_THRESHOLD_UP, /* A thresold has been crossed the way up */
88+ THERMAL_GENL_EVENT_THRESHOLD_DOWN, /* A thresold has been crossed the way down */
7889 __THERMAL_GENL_EVENT_MAX,
7990 };
8091 #define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)
@@ -82,12 +93,16 @@ enum thermal_genl_event { · 1 unmodified line
8293 /* Commands supported by the thermal_genl_family */
8394 enum thermal_genl_cmd {
8495 THERMAL_GENL_CMD_UNSPEC,
85− THERMAL_GENL_CMD_TZ_GET_ID, /* List of thermal zones id */
86− THERMAL_GENL_CMD_TZ_GET_TRIP, /* List of thermal trips */
87− THERMAL_GENL_CMD_TZ_GET_TEMP, /* Get the thermal zone temperature */
88− THERMAL_GENL_CMD_TZ_GET_GOV, /* Get the thermal zone governor */
89− THERMAL_GENL_CMD_TZ_GET_MODE, /* Get the thermal zone mode */
90− THERMAL_GENL_CMD_CDEV_GET, /* List of cdev id */
96+ THERMAL_GENL_CMD_TZ_GET_ID, /* List of thermal zones id */
97+ THERMAL_GENL_CMD_TZ_GET_TRIP, /* List of thermal trips */
98+ THERMAL_GENL_CMD_TZ_GET_TEMP, /* Get the thermal zone temperature */
99+ THERMAL_GENL_CMD_TZ_GET_GOV, /* Get the thermal zone governor */
100+ THERMAL_GENL_CMD_TZ_GET_MODE, /* Get the thermal zone mode */
101+ THERMAL_GENL_CMD_CDEV_GET, /* List of cdev id */
102+ THERMAL_GENL_CMD_THRESHOLD_GET, /* List of thresholds */
103+ THERMAL_GENL_CMD_THRESHOLD_ADD, /* Add a threshold */
104+ THERMAL_GENL_CMD_THRESHOLD_DELETE, /* Delete a threshold */
105+ THERMAL_GENL_CMD_THRESHOLD_FLUSH, /* Flush all the thresholds */
91106 __THERMAL_GENL_CMD_MAX,
92107 };
93108 #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
tools/lib/thermal/commands.c+175−13
@@ -5,6 +5,7 @@ · 4 unmodified lines
55 #include <stdio.h>
66 #include <stdlib.h>
77 #include <unistd.h>
8+#include <limits.h>
89
910 #include <thermal.h>
1011 #include "thermal_nl.h"
@@ -33,6 +34,11 @@ static struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { · 22 unmodified lines
3334 [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 },
3435 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },
3536 [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING },
37+
38+ /* Thresholds */
39+ [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED },
40+ [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 },
41+ [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 },
3642 };
3743
3844 static int parse_tz_get(struct genl_info *info, struct thermal_zone **tz)
@@ -182,6 +188,48 @@ static int parse_tz_get_gov(struct genl_info *info, struct thermal_zone *tz) · 143 unmodified lines
182188 return THERMAL_SUCCESS;
183189 }
184190
191+static int parse_threshold_get(struct genl_info *info, struct thermal_zone *tz)
192+{
193+ struct nlattr *attr;
194+ struct thermal_threshold *__tt = NULL;
195+ size_t size = 0;
196+ int rem;
197+
198+ /*
199+ * The size contains the size of the array and we want to
200+ * access the last element, size - 1.
201+ *
202+ * The variable size is initialized to zero but it will be
203+ * then incremented by the first if() statement. The message
204+ * attributes are ordered, so the first if() statement will be
205+ * always called before the second one. If it happens that is
206+ * not the case, then it is a kernel bug.
207+ */
208+ nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_THRESHOLD], rem) {
209+
210+ if (nla_type(attr) == THERMAL_GENL_ATTR_THRESHOLD_TEMP) {
211+
212+ size++;
213+
214+ __tt = realloc(__tt, sizeof(*__tt) * (size + 2));
215+ if (!__tt)
216+ return THERMAL_ERROR;
217+
218+ __tt[size - 1].temperature = nla_get_u32(attr);
219+ }
220+
221+ if (nla_type(attr) == THERMAL_GENL_ATTR_THRESHOLD_DIRECTION)
222+ __tt[size - 1].direction = nla_get_u32(attr);
223+ }
224+
225+ if (__tt)
226+ __tt[size].temperature = INT_MAX;
227+
228+ tz->thresholds = __tt;
229+
230+ return THERMAL_SUCCESS;
231+}
232+
185233 static int handle_netlink(struct nl_cache_ops *unused,
186234 struct genl_cmd *cmd,
187235 struct genl_info *info, void *arg)
@@ -210,6 +258,10 @@ static int handle_netlink(struct nl_cache_ops *unused, · 22 unmodified lines
210258 ret = parse_tz_get_gov(info, arg);
211259 break;
212260
261+ case THERMAL_GENL_CMD_THRESHOLD_GET:
262+ ret = parse_threshold_get(info, arg);
263+ break;
264+
213265 default:
214266 return THERMAL_ERROR;
215267 }
@@ -253,6 +305,34 @@ static struct genl_cmd thermal_cmds[] = { · 37 unmodified lines
253305 .c_maxattr = THERMAL_GENL_ATTR_MAX,
254306 .c_attr_policy = thermal_genl_policy,
255307 },
308+ {
309+ .c_id = THERMAL_GENL_CMD_THRESHOLD_GET,
310+ .c_name = (char *)"Get thresholds list",
311+ .c_msg_parser = handle_netlink,
312+ .c_maxattr = THERMAL_GENL_ATTR_MAX,
313+ .c_attr_policy = thermal_genl_policy,
314+ },
315+ {
316+ .c_id = THERMAL_GENL_CMD_THRESHOLD_ADD,
317+ .c_name = (char *)"Add a threshold",
318+ .c_msg_parser = handle_netlink,
319+ .c_maxattr = THERMAL_GENL_ATTR_MAX,
320+ .c_attr_policy = thermal_genl_policy,
321+ },
322+ {
323+ .c_id = THERMAL_GENL_CMD_THRESHOLD_DELETE,
324+ .c_name = (char *)"Delete a threshold",
325+ .c_msg_parser = handle_netlink,
326+ .c_maxattr = THERMAL_GENL_ATTR_MAX,
327+ .c_attr_policy = thermal_genl_policy,
328+ },
329+ {
330+ .c_id = THERMAL_GENL_CMD_THRESHOLD_FLUSH,
331+ .c_name = (char *)"Flush the thresholds",
332+ .c_msg_parser = handle_netlink,
333+ .c_maxattr = THERMAL_GENL_ATTR_MAX,
334+ .c_attr_policy = thermal_genl_policy,
335+ },
256336 };
257337
258338 static struct genl_ops thermal_cmd_ops = {
@@ -261,9 +341,41 @@ static struct genl_ops thermal_cmd_ops = { · 2 unmodified lines
261341 .o_ncmds = ARRAY_SIZE(thermal_cmds),
262342 };
263343
264−static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int cmd,
265− int flags, void *arg)
344+struct cmd_param {
345+ int tz_id;
346+ int temp;
347+ int direction;
348+};
349+
350+typedef int (*cmd_cb_t)(struct nl_msg *, struct cmd_param *);
351+
352+static int thermal_genl_tz_id_encode(struct nl_msg *msg, struct cmd_param *p)
266353 {
354+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
355+ return -1;
356+
357+ return 0;
358+}
359+
360+static int thermal_genl_threshold_encode(struct nl_msg *msg, struct cmd_param *p)
361+{
362+ if (thermal_genl_tz_id_encode(msg, p))
363+ return -1;
364+
365+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp))
366+ return -1;
367+
368+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction))
369+ return -1;
370+
371+ return 0;
372+}
373+
374+static thermal_error_t thermal_genl_auto(struct thermal_handler *th, cmd_cb_t cmd_cb,
375+ struct cmd_param *param,
376+ int cmd, int flags, void *arg)
377+{
378+ thermal_error_t ret = THERMAL_ERROR;
267379 struct nl_msg *msg;
268380 void *hdr;
269381
@@ -274,45 +386,95 @@ static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int · 4 unmodified lines
274386 hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id,
275387 0, flags, cmd, THERMAL_GENL_VERSION);
276388 if (!hdr)
277− return THERMAL_ERROR;
389+ goto out;
278390
279− if (id >= 0 && nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id))
280− return THERMAL_ERROR;
391+ if (cmd_cb && cmd_cb(msg, param))
392+ goto out;
281393
282394 if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg))
283− return THERMAL_ERROR;
395+ goto out;
284396
397+ ret = THERMAL_SUCCESS;
398+out:
285399 nlmsg_free(msg);
286400
287− return THERMAL_SUCCESS;
401+ return ret;
288402 }
289403
290404 thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz)
291405 {
292− return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_TZ_GET_ID,
406+ return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_TZ_GET_ID,
293407 NLM_F_DUMP | NLM_F_ACK, tz);
294408 }
295409
296410 thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc)
297411 {
298− return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_CDEV_GET,
412+ return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_CDEV_GET,
299413 NLM_F_DUMP | NLM_F_ACK, tc);
300414 }
301415
302416 thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz)
303417 {
304− return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TRIP,
305− 0, tz);
418+ struct cmd_param p = { .tz_id = tz->id };
419+
420+ return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
421+ THERMAL_GENL_CMD_TZ_GET_TRIP, 0, tz);
306422 }
307423
308424 thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz)
309425 {
310− return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz);
426+ struct cmd_param p = { .tz_id = tz->id };
427+
428+ return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
429+ THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz);
311430 }
312431
313432 thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz)
314433 {
315− return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz);
434+ struct cmd_param p = { .tz_id = tz->id };
435+
436+ return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
437+ THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz);
438+}
439+
440+thermal_error_t thermal_cmd_threshold_get(struct thermal_handler *th,
441+ struct thermal_zone *tz)
442+{
443+ struct cmd_param p = { .tz_id = tz->id };
444+
445+ return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
446+ THERMAL_GENL_CMD_THRESHOLD_GET, 0, tz);
447+}
448+
449+thermal_error_t thermal_cmd_threshold_add(struct thermal_handler *th,
450+ struct thermal_zone *tz,
451+ int temperature,
452+ int direction)
453+{
454+ struct cmd_param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
455+
456+ return thermal_genl_auto(th, thermal_genl_threshold_encode, &p,
457+ THERMAL_GENL_CMD_THRESHOLD_ADD, 0, tz);
458+}
459+
460+thermal_error_t thermal_cmd_threshold_delete(struct thermal_handler *th,
461+ struct thermal_zone *tz,
462+ int temperature,
463+ int direction)
464+{
465+ struct cmd_param p = { .tz_id = tz->id, .temp = temperature, .direction = direction };
466+
467+ return thermal_genl_auto(th, thermal_genl_threshold_encode, &p,
468+ THERMAL_GENL_CMD_THRESHOLD_DELETE, 0, tz);
469+}
470+
471+thermal_error_t thermal_cmd_threshold_flush(struct thermal_handler *th,
472+ struct thermal_zone *tz)
473+{
474+ struct cmd_param p = { .tz_id = tz->id };
475+
476+ return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
477+ THERMAL_GENL_CMD_THRESHOLD_FLUSH, 0, tz);
316478 }
317479
318480 thermal_error_t thermal_cmd_exit(struct thermal_handler *th)
tools/lib/thermal/events.c+42−13
@@ -94,6 +94,30 @@ static int handle_thermal_event(struct nl_msg *n, void *arg) · 93 unmodified lines
9494 case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:
9595 return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
9696 nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg);
97+
98+ case THERMAL_GENL_EVENT_THRESHOLD_ADD:
99+ return ops->threshold_add(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
100+ nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]),
101+ nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]), arg);
102+
103+ case THERMAL_GENL_EVENT_THRESHOLD_DELETE:
104+ return ops->threshold_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
105+ nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]),
106+ nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]), arg);
107+
108+ case THERMAL_GENL_EVENT_THRESHOLD_FLUSH:
109+ return ops->threshold_flush(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg);
110+
111+ case THERMAL_GENL_EVENT_THRESHOLD_UP:
112+ return ops->threshold_up(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
113+ nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]),
114+ nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_PREV_TEMP]), arg);
115+
116+ case THERMAL_GENL_EVENT_THRESHOLD_DOWN:
117+ return ops->threshold_down(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
118+ nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]),
119+ nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_PREV_TEMP]), arg);
120+
97121 default:
98122 return -1;
99123 }
@@ -101,19 +125,24 @@ static int handle_thermal_event(struct nl_msg *n, void *arg) · 1 unmodified line
101125
102126 static void thermal_events_ops_init(struct thermal_events_ops *ops)
103127 {
104− enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create;
105− enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete;
106− enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable;
107− enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable;
108− enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high;
109− enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low;
110− enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change;
111− enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add;
112− enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete;
113− enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add;
114− enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete;
115− enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;
116− enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change;
128+ enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create;
129+ enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete;
130+ enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable;
131+ enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable;
132+ enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high;
133+ enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low;
134+ enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change;
135+ enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add;
136+ enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete;
137+ enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add;
138+ enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete;
139+ enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;
140+ enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change;
141+ enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_ADD] = !!ops->threshold_add;
142+ enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_DELETE] = !!ops->threshold_delete;
143+ enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = !!ops->threshold_flush;
144+ enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_UP] = !!ops->threshold_up;
145+ enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_DOWN] = !!ops->threshold_down;
117146 }
118147
119148 thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg)
tools/lib/thermal/include/thermal.h+40−0
@@ -4,11 +4,20 @@ · 3 unmodified lines
44 #define __LIBTHERMAL_H
55
66 #include <linux/thermal.h>
7+#include <sys/types.h>
78
89 #ifndef LIBTHERMAL_API
910 #define LIBTHERMAL_API __attribute__((visibility("default")))
1011 #endif
1112
13+#ifndef THERMAL_THRESHOLD_WAY_UP
14+#define THERMAL_THRESHOLD_WAY_UP 0x1
15+#endif
16+
17+#ifndef THERMAL_THRESHOLD_WAY_DOWN
18+#define THERMAL_THRESHOLD_WAY_DOWN 0x2
19+#endif
20+
1221 #ifdef __cplusplus
1322 extern "C" {
1423 #endif
@@ -31,6 +40,11 @@ struct thermal_events_ops { · 16 unmodified lines
3140 int (*cdev_delete)(int cdev_id, void *arg);
3241 int (*cdev_update)(int cdev_id, int cur_state, void *arg);
3342 int (*gov_change)(int tz_id, const char *gov_name, void *arg);
43+ int (*threshold_add)(int tz_id, int temperature, int direction, void *arg);
44+ int (*threshold_delete)(int tz_id, int temperature, int direction, void *arg);
45+ int (*threshold_flush)(int tz_id, void *arg);
46+ int (*threshold_up)(int tz_id, int temp, int prev_temp, void *arg);
47+ int (*threshold_down)(int tz_id, int temp, int prev_temp, void *arg);
3448 };
3549
3650 struct thermal_ops {
@@ -45,12 +59,18 @@ struct thermal_trip { · 8 unmodified lines
4559 int hyst;
4660 };
4761
62+struct thermal_threshold {
63+ int temperature;
64+ int direction;
65+};
66+
4867 struct thermal_zone {
4968 int id;
5069 int temp;
5170 char name[THERMAL_NAME_LENGTH];
5271 char governor[THERMAL_NAME_LENGTH];
5372 struct thermal_trip *trip;
73+ struct thermal_threshold *thresholds;
5474 };
5575
5676 struct thermal_cdev {
@@ -74,12 +94,16 @@ typedef int (*cb_tt_t)(struct thermal_trip *, void *); · 17 unmodified lines
7494
7595 typedef int (*cb_tc_t)(struct thermal_cdev *, void *);
7696
97+typedef int (*cb_th_t)(struct thermal_threshold *, void *);
98+
7799 LIBTHERMAL_API int for_each_thermal_zone(struct thermal_zone *tz, cb_tz_t cb, void *arg);
78100
79101 LIBTHERMAL_API int for_each_thermal_trip(struct thermal_trip *tt, cb_tt_t cb, void *arg);
80102
81103 LIBTHERMAL_API int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg);
82104
105+LIBTHERMAL_API int for_each_thermal_threshold(struct thermal_threshold *th, cb_th_t cb, void *arg);
106+
83107 LIBTHERMAL_API struct thermal_zone *thermal_zone_find_by_name(struct thermal_zone *tz,
84108 const char *name);
85109
@@ -124,6 +148,22 @@ LIBTHERMAL_API thermal_error_t thermal_cmd_get_governor(struct thermal_handler * · 38 unmodified lines
124148 LIBTHERMAL_API thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th,
125149 struct thermal_zone *tz);
126150
151+LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_get(struct thermal_handler *th,
152+ struct thermal_zone *tz);
153+
154+LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_add(struct thermal_handler *th,
155+ struct thermal_zone *tz,
156+ int temperature,
157+ int direction);
158+
159+LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_delete(struct thermal_handler *th,
160+ struct thermal_zone *tz,
161+ int temperature,
162+ int direction);
163+
164+LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_flush(struct thermal_handler *th,
165+ struct thermal_zone *tz);
166+
127167 /*
128168 * Netlink thermal samples
129169 */
tools/lib/thermal/libthermal.map+5−0
@@ -4,6 +4,7 @@ LIBTHERMAL_0.0.1 { · 3 unmodified lines
44 for_each_thermal_zone;
55 for_each_thermal_trip;
66 for_each_thermal_cdev;
7+ for_each_thermal_threshold;
78 thermal_zone_find_by_name;
89 thermal_zone_find_by_id;
910 thermal_zone_discover;
@@ -17,6 +18,10 @@ LIBTHERMAL_0.0.1 { · 7 unmodified lines
1718 thermal_cmd_get_trip;
1819 thermal_cmd_get_governor;
1920 thermal_cmd_get_temp;
21+ thermal_cmd_threshold_get;
22+ thermal_cmd_threshold_add;
23+ thermal_cmd_threshold_delete;
24+ thermal_cmd_threshold_flush;
2025 thermal_sampling_init;
2126 thermal_sampling_handle;
2227 thermal_sampling_fd;
tools/lib/thermal/thermal.c+17−0
@@ -1,10 +1,24 @@
11 // SPDX-License-Identifier: LGPL-2.1+
22 // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
33 #include <stdio.h>
4+#include <limits.h>
45 #include <thermal.h>
56
67 #include "thermal_nl.h"
78
9+int for_each_thermal_threshold(struct thermal_threshold *th, cb_th_t cb, void *arg)
10+{
11+ int i, ret = 0;
12+
13+ if (!th)
14+ return 0;
15+
16+ for (i = 0; th[i].temperature != INT_MAX; i++)
17+ ret |= cb(&th[i], arg);
18+
19+ return ret;
20+}
21+
822 int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg)
923 {
1024 int i, ret = 0;
@@ -80,6 +94,9 @@ static int __thermal_zone_discover(struct thermal_zone *tz, void *th) · 69 unmodified lines
8094 if (thermal_cmd_get_trip(th, tz) < 0)
8195 return -1;
8296
97+ if (thermal_cmd_threshold_get(th, tz))
98+ return -1;
99+
83100 if (thermal_cmd_get_governor(th, tz))
84101 return -1;
85102
tools/thermal/lib/Makefile+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
33
44 LIBTHERMAL_TOOLS_VERSION = 0
55 LIBTHERMAL_TOOLS_PATCHLEVEL = 0
6−LIBTHERMAL_TOOLS_EXTRAVERSION = 1
6+LIBTHERMAL_TOOLS_EXTRAVERSION = 2
77
88 MAKEFLAGS += --no-print-directory
99
tools/thermal/thermal-engine/thermal-engine.c+92−13
@@ -38,6 +38,14 @@ struct thermal_data { · 37 unmodified lines
3838 struct thermal_handler *th;
3939 };
4040
41+static int show_threshold(struct thermal_threshold *th, __maybe_unused void *arg)
42+{
43+ INFO("threshold temp=%d, direction=%d\n",
44+ th->temperature, th->direction);
45+
46+ return 0;
47+}
48+
4149 static int show_trip(struct thermal_trip *tt, __maybe_unused void *arg)
4250 {
4351 INFO("trip id=%d, type=%d, temp=%d, hyst=%d\n",
@@ -70,6 +78,8 @@ static int show_tz(struct thermal_zone *tz, __maybe_unused void *arg) · 26 unmodified lines
7078
7179 for_each_thermal_trip(tz->trip, show_trip, NULL);
7280
81+ for_each_thermal_threshold(tz->thresholds, show_threshold, NULL);
82+
7383 show_temp(tz, arg);
7484
7585 show_governor(tz, arg);
@@ -77,6 +87,30 @@ static int show_tz(struct thermal_zone *tz, __maybe_unused void *arg) · 1 unmodified line
7787 return 0;
7888 }
7989
90+static int set_threshold(struct thermal_zone *tz, __maybe_unused void *arg)
91+{
92+ struct thermal_handler *th = arg;
93+ int thresholds[] = { 43000, 65000, 49000, 55000, 57000 };
94+ size_t i;
95+
96+ INFO("Setting threshold for thermal zone '%s', id=%d\n", tz->name, tz->id);
97+
98+ if (thermal_cmd_threshold_flush(th, tz)) {
99+ ERROR("Failed to flush all previous thresholds\n");
100+ return -1;
101+ }
102+
103+ for (i = 0; i < sizeof(thresholds) / sizeof(thresholds[0]); i++)
104+ if (thermal_cmd_threshold_add(th, tz, thresholds[i],
105+ THERMAL_THRESHOLD_WAY_UP |
106+ THERMAL_THRESHOLD_WAY_DOWN)) {
107+ ERROR("Failed to set threshold\n");
108+ return -1;
109+ }
110+
111+ return 0;
112+}
113+
80114 static int tz_create(const char *name, int tz_id, __maybe_unused void *arg)
81115 {
82116 INFO("Thermal zone '%s'/%d created\n", name, tz_id);
@@ -197,20 +231,62 @@ static int gov_change(int tz_id, const char *name, __maybe_unused void *arg) · 114 unmodified lines
197231 return 0;
198232 }
199233
234+static int threshold_add(int tz_id, int temp, int direction, __maybe_unused void *arg)
235+{
236+ INFO("Threshold added tz_id=%d: temp=%d, direction=%d\n", tz_id, temp, direction);
237+
238+ return 0;
239+}
240+
241+static int threshold_delete(int tz_id, int temp, int direction, __maybe_unused void *arg)
242+{
243+ INFO("Threshold deleted tz_id=%d: temp=%d, direction=%d\n", tz_id, temp, direction);
244+
245+ return 0;
246+}
247+
248+static int threshold_flush(int tz_id, __maybe_unused void *arg)
249+{
250+ INFO("Thresholds flushed tz_id=%d\n", tz_id);
251+
252+ return 0;
253+}
254+
255+static int threshold_up(int tz_id, int temp, int prev_temp, __maybe_unused void *arg)
256+{
257+ INFO("Threshold crossed way up tz_id=%d: temp=%d, prev_temp=%d\n",
258+ tz_id, temp, prev_temp);
259+
260+ return 0;
261+}
262+
263+static int threshold_down(int tz_id, int temp, int prev_temp, __maybe_unused void *arg)
264+{
265+ INFO("Threshold crossed way down tz_id=%d: temp=%d, prev_temp=%d\n",
266+ tz_id, temp, prev_temp);
267+
268+ return 0;
269+}
270+
200271 static struct thermal_ops ops = {
201− .events.tz_create = tz_create,
202− .events.tz_delete = tz_delete,
203− .events.tz_disable = tz_disable,
204− .events.tz_enable = tz_enable,
205− .events.trip_high = trip_high,
206− .events.trip_low = trip_low,
207− .events.trip_add = trip_add,
208− .events.trip_delete = trip_delete,
209− .events.trip_change = trip_change,
210− .events.cdev_add = cdev_add,
211− .events.cdev_delete = cdev_delete,
212− .events.cdev_update = cdev_update,
213− .events.gov_change = gov_change
272+ .events.tz_create = tz_create,
273+ .events.tz_delete = tz_delete,
274+ .events.tz_disable = tz_disable,
275+ .events.tz_enable = tz_enable,
276+ .events.trip_high = trip_high,
277+ .events.trip_low = trip_low,
278+ .events.trip_add = trip_add,
279+ .events.trip_delete = trip_delete,
280+ .events.trip_change = trip_change,
281+ .events.cdev_add = cdev_add,
282+ .events.cdev_delete = cdev_delete,
283+ .events.cdev_update = cdev_update,
284+ .events.gov_change = gov_change,
285+ .events.threshold_add = threshold_add,
286+ .events.threshold_delete = threshold_delete,
287+ .events.threshold_flush = threshold_flush,
288+ .events.threshold_up = threshold_up,
289+ .events.threshold_down = threshold_down,
214290 };
215291
216292 static int thermal_event(__maybe_unused int fd, __maybe_unused void *arg)
@@ -280,6 +356,7 @@ enum { · 63 unmodified lines
280356 THERMAL_ENGINE_DAEMON_ERROR,
281357 THERMAL_ENGINE_LOG_ERROR,
282358 THERMAL_ENGINE_THERMAL_ERROR,
359+ THERMAL_ENGINE_THRESHOLD_ERROR,
283360 THERMAL_ENGINE_MAINLOOP_ERROR,
284361 };
285362
@@ -318,6 +395,8 @@ int main(int argc, char *argv[]) · 32 unmodified lines
318395 return THERMAL_ENGINE_THERMAL_ERROR;
319396 }
320397
398+ for_each_thermal_zone(td.tz, set_threshold, td.th);
399+
321400 for_each_thermal_zone(td.tz, show_tz, td.th);
322401
323402 if (mainloop_init()) {