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
6obj-$(CONFIG_THERMAL) += thermal_sys.o6obj-$(CONFIG_THERMAL) += thermal_sys.o
7thermal_sys-y += thermal_core.o thermal_sysfs.o7thermal_sys-y += thermal_core.o thermal_sysfs.o
8thermal_sys-y += thermal_trip.o thermal_helpers.o8thermal_sys-y += thermal_trip.o thermal_helpers.o
9thermal_sys-y += thermal_thresholds.o
9 10
10# netlink interface to manage the thermal framework11# netlink interface to manage the thermal framework
11thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o12thermal_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
30 30
31 dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);31 dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target);
32 32
33 mutex_lock(&instance->cdev->lock);33 thermal_cdev_update_nocheck(instance->cdev);
34 __thermal_cdev_update(instance->cdev);
35 mutex_unlock(&instance->cdev->lock);
36}34}
37 35
38/**36/**
@@ -67,6 +65,7 @@ static void bang_bang_control(struct thermal_zone_device *tz, · 28 unmodified lines
67 const struct thermal_trip *trip,65 const struct thermal_trip *trip,
68 bool crossed_up)66 bool crossed_up)
69{67{
68 const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
70 struct thermal_instance *instance;69 struct thermal_instance *instance;
71 70
72 lockdep_assert_held(&tz->lock);71 lockdep_assert_held(&tz->lock);
@@ -75,10 +74,8 @@ static void bang_bang_control(struct thermal_zone_device *tz, · 2 unmodified lines
75 thermal_zone_trip_id(tz, trip), trip->temperature,74 thermal_zone_trip_id(tz, trip), trip->temperature,
76 tz->temperature, trip->hysteresis);75 tz->temperature, trip->hysteresis);
77 76
78 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {77 list_for_each_entry(instance, &td->thermal_instances, trip_node)
79 if (instance->trip == trip)78 bang_bang_set_instance_target(instance, crossed_up);
80 bang_bang_set_instance_target(instance, crossed_up);
81 }
82}79}
83 80
84static void bang_bang_manage(struct thermal_zone_device *tz)81static 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
104 * to the thermal zone temperature and the trip point threshold.101 * to the thermal zone temperature and the trip point threshold.
105 */102 */
106 turn_on = tz->temperature >= td->threshold;103 turn_on = tz->temperature >= td->threshold;
107 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {104 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
108 if (!instance->initialized && instance->trip == trip)105 if (!instance->initialized)
109 bang_bang_set_instance_target(instance, turn_on);106 bang_bang_set_instance_target(instance, turn_on);
110 }107 }
111 }108 }
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
44/**44/**
45 * fair_share_throttle - throttles devices associated with the given zone45 * fair_share_throttle - throttles devices associated with the given zone
46 * @tz: thermal_zone_device46 * @tz: thermal_zone_device
47 * @trip: trip point47 * @td: trip point descriptor
48 * @trip_level: number of trips crossed by the zone temperature48 * @trip_level: number of trips crossed by the zone temperature
49 *49 *
50 * Throttling Logic: This uses three parameters to calculate the new50 * 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
61 * new_state of cooling device = P3 * P2 * P161 * new_state of cooling device = P3 * P2 * P1
62 */62 */
63static void fair_share_throttle(struct thermal_zone_device *tz,63static void fair_share_throttle(struct thermal_zone_device *tz,
64 const struct thermal_trip *trip,64 const struct thermal_trip_desc *td,
65 int trip_level)65 int trip_level)
66{66{
67 struct thermal_instance *instance;67 struct thermal_instance *instance;
68 int total_weight = 0;68 int total_weight = 0;
69 int nr_instances = 0;69 int nr_instances = 0;
70 70
71 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {71 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
72 if (instance->trip != trip)
73 continue;
74
75 total_weight += instance->weight;72 total_weight += instance->weight;
76 nr_instances++;73 nr_instances++;
77 }74 }
78 75
79 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {76 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
80 struct thermal_cooling_device *cdev = instance->cdev;77 struct thermal_cooling_device *cdev = instance->cdev;
81 u64 dividend;78 u64 dividend;
82 u32 divisor;79 u32 divisor;
83 80
84 if (instance->trip != trip)
85 continue;
86
87 dividend = trip_level;81 dividend = trip_level;
88 dividend *= cdev->max_state;82 dividend *= cdev->max_state;
89 divisor = tz->num_trips;83 divisor = tz->num_trips;
@@ -95,9 +89,7 @@ static void fair_share_throttle(struct thermal_zone_device *tz, · 5 unmodified lines
95 }89 }
96 instance->target = div_u64(dividend, divisor);90 instance->target = div_u64(dividend, divisor);
97 91
98 mutex_lock(&cdev->lock);92 thermal_cdev_update_nocheck(cdev);
99 __thermal_cdev_update(cdev);
100 mutex_unlock(&cdev->lock);
101 }93 }
102}94}
103 95
@@ -116,7 +108,7 @@ static void fair_share_manage(struct thermal_zone_device *tz) · 12 unmodified lines
116 trip->type == THERMAL_TRIP_HOT)108 trip->type == THERMAL_TRIP_HOT)
117 continue;109 continue;
118 110
119 fair_share_throttle(tz, trip, trip_level);111 fair_share_throttle(tz, td, trip_level);
120 }112 }
121}113}
122 114
drivers/thermal/gov_power_allocator.c+46−40
@@ -97,11 +97,9 @@ struct power_allocator_params { · 96 unmodified lines
97 struct power_actor *power;97 struct power_actor *power;
98};98};
99 99
100static bool power_actor_is_valid(struct power_allocator_params *params,100static bool power_actor_is_valid(struct thermal_instance *instance)
101 struct thermal_instance *instance)
102{101{
103 return (instance->trip == params->trip_max &&102 return cdev_is_power_actor(instance->cdev);
104 cdev_is_power_actor(instance->cdev));
105}103}
106 104
107/**105/**
@@ -118,13 +116,14 @@ static bool power_actor_is_valid(struct power_allocator_params *params, · 10 unmodified lines
118static u32 estimate_sustainable_power(struct thermal_zone_device *tz)116static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
119{117{
120 struct power_allocator_params *params = tz->governor_data;118 struct power_allocator_params *params = tz->governor_data;
119 const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
121 struct thermal_cooling_device *cdev;120 struct thermal_cooling_device *cdev;
122 struct thermal_instance *instance;121 struct thermal_instance *instance;
123 u32 sustainable_power = 0;122 u32 sustainable_power = 0;
124 u32 min_power;123 u32 min_power;
125 124
126 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {125 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
127 if (!power_actor_is_valid(params, instance))126 if (!power_actor_is_valid(instance))
128 continue;127 continue;
129 128
130 cdev = instance->cdev;129 cdev = instance->cdev;
@@ -323,9 +322,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev, · 192 unmodified lines
323 return ret;322 return ret;
324 323
325 instance->target = clamp_val(state, instance->lower, instance->upper);324 instance->target = clamp_val(state, instance->lower, instance->upper);
326 mutex_lock(&cdev->lock);325
327 __thermal_cdev_update(cdev);326 thermal_cdev_update_nocheck(cdev);
328 mutex_unlock(&cdev->lock);
329 327
330 return 0;328 return 0;
331}329}
@@ -356,11 +354,19 @@ static void divvy_up_power(struct power_actor *power, int num_actors, · 24 unmodified lines
356 u32 extra_power = 0;354 u32 extra_power = 0;
357 int i;355 int i;
358 356
359 /*357 if (!total_req_power) {
360 * Prevent division by 0 if none of the actors request power.358 /*
361 */359 * Nobody requested anything, just give everybody
362 if (!total_req_power)360 * the maximum power
363 total_req_power = 1;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 }
364 370
365 for (i = 0; i < num_actors; i++) {371 for (i = 0; i < num_actors; i++) {
366 struct power_actor *pa = &power[i];372 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
400static void allocate_power(struct thermal_zone_device *tz, int control_temp)406static void allocate_power(struct thermal_zone_device *tz, int control_temp)
401{407{
402 struct power_allocator_params *params = tz->governor_data;408 struct power_allocator_params *params = tz->governor_data;
409 const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
403 unsigned int num_actors = params->num_actors;410 unsigned int num_actors = params->num_actors;
404 struct power_actor *power = params->power;411 struct power_actor *power = params->power;
405 struct thermal_cooling_device *cdev;412 struct thermal_cooling_device *cdev;
@@ -417,10 +424,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) · 11 unmodified lines
417 /* Clean all buffers for new power estimations */424 /* Clean all buffers for new power estimations */
418 memset(power, 0, params->buffer_size);425 memset(power, 0, params->buffer_size);
419 426
420 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {427 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
421 struct power_actor *pa = &power[i];428 struct power_actor *pa = &power[i];
422 429
423 if (!power_actor_is_valid(params, instance))430 if (!power_actor_is_valid(instance))
424 continue;431 continue;
425 432
426 cdev = instance->cdev;433 cdev = instance->cdev;
@@ -454,10 +461,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) · 27 unmodified lines
454 power_range);461 power_range);
455 462
456 i = 0;463 i = 0;
457 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {464 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
458 struct power_actor *pa = &power[i];465 struct power_actor *pa = &power[i];
459 466
460 if (!power_actor_is_valid(params, instance))467 if (!power_actor_is_valid(instance))
461 continue;468 continue;
462 469
463 power_actor_set_power(instance->cdev, instance,470 power_actor_set_power(instance->cdev, instance,
@@ -538,29 +545,29 @@ static void reset_pid_controller(struct power_allocator_params *params) · 74 unmodified lines
538static void allow_maximum_power(struct thermal_zone_device *tz)545static void allow_maximum_power(struct thermal_zone_device *tz)
539{546{
540 struct power_allocator_params *params = tz->governor_data;547 struct power_allocator_params *params = tz->governor_data;
548 const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
541 struct thermal_cooling_device *cdev;549 struct thermal_cooling_device *cdev;
542 struct thermal_instance *instance;550 struct thermal_instance *instance;
543 u32 req_power;551 u32 req_power;
544 552
545 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {553 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
546 if (!power_actor_is_valid(params, instance))554 if (!power_actor_is_valid(instance))
547 continue;555 continue;
548 556
549 cdev = instance->cdev;557 cdev = instance->cdev;
550 558
551 instance->target = 0;559 instance->target = 0;
552 mutex_lock(&cdev->lock);560 scoped_guard(cooling_dev, cdev) {
553 /*561 /*
554 * Call for updating the cooling devices local stats and avoid562 * Call for updating the cooling devices local stats and
555 * periods of dozen of seconds when those have not been563 * avoid periods of dozen of seconds when those have not
556 * maintained.564 * been maintained.
557 */565 */
558 cdev->ops->get_requested_power(cdev, &req_power);566 cdev->ops->get_requested_power(cdev, &req_power);
559 567
560 if (params->update_cdevs)568 if (params->update_cdevs)
561 __thermal_cdev_update(cdev);569 __thermal_cdev_update(cdev);
562 570 }
563 mutex_unlock(&cdev->lock);
564 }571 }
565}572}
566 573
@@ -581,13 +588,11 @@ static void allow_maximum_power(struct thermal_zone_device *tz) · 14 unmodified lines
581static int check_power_actors(struct thermal_zone_device *tz,588static int check_power_actors(struct thermal_zone_device *tz,
582 struct power_allocator_params *params)589 struct power_allocator_params *params)
583{590{
591 const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
584 struct thermal_instance *instance;592 struct thermal_instance *instance;
585 int ret = 0;593 int ret = 0;
586 594
587 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {595 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
588 if (instance->trip != params->trip_max)
589 continue;
590
591 if (!cdev_is_power_actor(instance->cdev)) {596 if (!cdev_is_power_actor(instance->cdev)) {
592 dev_warn(&tz->device, "power_allocator: %s is not a power actor\n",597 dev_warn(&tz->device, "power_allocator: %s is not a power actor\n",
593 instance->cdev->type);598 instance->cdev->type);
@@ -635,14 +640,15 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, · 41 unmodified lines
635 enum thermal_notify_event reason)640 enum thermal_notify_event reason)
636{641{
637 struct power_allocator_params *params = tz->governor_data;642 struct power_allocator_params *params = tz->governor_data;
643 const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
638 struct thermal_instance *instance;644 struct thermal_instance *instance;
639 int num_actors = 0;645 int num_actors = 0;
640 646
641 switch (reason) {647 switch (reason) {
642 case THERMAL_TZ_BIND_CDEV:648 case THERMAL_TZ_BIND_CDEV:
643 case THERMAL_TZ_UNBIND_CDEV:649 case THERMAL_TZ_UNBIND_CDEV:
644 list_for_each_entry(instance, &tz->thermal_instances, tz_node)650 list_for_each_entry(instance, &td->thermal_instances, trip_node)
645 if (power_actor_is_valid(params, instance))651 if (power_actor_is_valid(instance))
646 num_actors++;652 num_actors++;
647 653
648 if (num_actors == params->num_actors)654 if (num_actors == params->num_actors)
@@ -652,8 +658,8 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, · 3 unmodified lines
652 break;658 break;
653 case THERMAL_INSTANCE_WEIGHT_CHANGED:659 case THERMAL_INSTANCE_WEIGHT_CHANGED:
654 params->total_weight = 0;660 params->total_weight = 0;
655 list_for_each_entry(instance, &tz->thermal_instances, tz_node)661 list_for_each_entry(instance, &td->thermal_instances, trip_node)
656 if (power_actor_is_valid(params, instance))662 if (power_actor_is_valid(instance))
657 params->total_weight += instance->weight;663 params->total_weight += instance->weight;
658 break;664 break;
659 default:665 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
66}66}
67 67
68static void thermal_zone_trip_update(struct thermal_zone_device *tz,68static void thermal_zone_trip_update(struct thermal_zone_device *tz,
69 const struct thermal_trip *trip,69 const struct thermal_trip_desc *td,
70 int trip_threshold)70 int trip_threshold)
71{71{
72 const struct thermal_trip *trip = &td->trip;
72 enum thermal_trend trend = get_tz_trend(tz, trip);73 enum thermal_trend trend = get_tz_trend(tz, trip);
73 int trip_id = thermal_zone_trip_id(tz, trip);74 int trip_id = thermal_zone_trip_id(tz, trip);
74 struct thermal_instance *instance;75 struct thermal_instance *instance;
@@ -82,12 +83,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, · 7 unmodified lines
82 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",83 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
83 trip_id, trip->type, trip_threshold, trend, throttle);84 trip_id, trip->type, trip_threshold, trend, throttle);
84 85
85 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {86 list_for_each_entry(instance, &td->thermal_instances, trip_node) {
86 int old_target;87 int old_target;
87 88
88 if (instance->trip != trip)
89 continue;
90
91 old_target = instance->target;89 old_target = instance->target;
92 instance->target = get_target_state(instance, trend, throttle);90 instance->target = get_target_state(instance, trend, throttle);
93 91
@@ -99,9 +97,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, · 5 unmodified lines
99 97
100 instance->initialized = true;98 instance->initialized = true;
101 99
102 mutex_lock(&instance->cdev->lock);100 scoped_guard(cooling_dev, instance->cdev) {
103 instance->cdev->updated = false; /* cdev needs update */101 instance->cdev->updated = false; /* cdev needs update */
104 mutex_unlock(&instance->cdev->lock);102 }
105 }103 }
106}104}
107 105
@@ -127,11 +125,13 @@ static void step_wise_manage(struct thermal_zone_device *tz) · 19 unmodified lines
127 trip->type == THERMAL_TRIP_HOT)125 trip->type == THERMAL_TRIP_HOT)
128 continue;126 continue;
129 127
130 thermal_zone_trip_update(tz, trip, td->threshold);128 thermal_zone_trip_update(tz, td, td->threshold);
131 }129 }
132 130
133 list_for_each_entry(instance, &tz->thermal_instances, tz_node)131 for_each_trip_desc(tz, td) {
134 thermal_cdev_update(instance->cdev);132 list_for_each_entry(instance, &td->thermal_instances, trip_node)
133 thermal_cdev_update(instance->cdev);
134 }
135}135}
136 136
137static struct thermal_governor thermal_gov_step_wise = {137static 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
185int tt_add_tz(void)185int tt_add_tz(void)
186{186{
187 struct tt_thermal_zone *tt_zone __free(kfree);187 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;
189 int ret;189 int ret;
190 190
191 tt_zone = kzalloc(sizeof(*tt_zone), GFP_KERNEL);191 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
237 237
238int tt_del_tz(const char *arg)238int tt_del_tz(const char *arg)
239{239{
240 struct tt_work *tt_work __free(kfree);240 struct tt_work *tt_work __free(kfree) = NULL;
241 struct tt_thermal_zone *tt_zone, *aux;241 struct tt_thermal_zone *tt_zone, *aux;
242 int ret;242 int ret;
243 int id;243 int id;
@@ -288,19 +288,14 @@ static struct tt_thermal_zone *tt_get_tt_zone(const char *arg) · 44 unmodified lines
288 288
289 guard(mutex)(&tt_thermal_zones_lock);289 guard(mutex)(&tt_thermal_zones_lock);
290 290
291 ret = -EINVAL;
292 list_for_each_entry(tt_zone, &tt_thermal_zones, list_node) {291 list_for_each_entry(tt_zone, &tt_thermal_zones, list_node) {
293 if (tt_zone->id == id) {292 if (tt_zone->id == id) {
294 tt_zone->refcount++;293 tt_zone->refcount++;
295 ret = 0;294 return tt_zone;
296 break;
297 }295 }
298 }296 }
299 297
300 if (ret)298 return ERR_PTR(-EINVAL);
301 return ERR_PTR(ret);
302
303 return tt_zone;
304}299}
305 300
306static void tt_put_tt_zone(struct tt_thermal_zone *tt_zone)301static 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
310 tt_zone->refcount--;305 tt_zone->refcount--;
311}306}
312 307
308DEFINE_FREE(put_tt_zone, struct tt_thermal_zone *,
309 if (!IS_ERR_OR_NULL(_T)) tt_put_tt_zone(_T))
310
313static void tt_zone_add_trip_work_fn(struct work_struct *work)311static void tt_zone_add_trip_work_fn(struct work_struct *work)
314{312{
315 struct tt_work *tt_work = tt_work_of_work(work);313 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
332 330
333int tt_zone_add_trip(const char *arg)331int tt_zone_add_trip(const char *arg)
334{332{
333 struct tt_thermal_zone *tt_zone __free(put_tt_zone) = NULL;
334 struct tt_trip *tt_trip __free(kfree) = NULL;
335 struct tt_work *tt_work __free(kfree);335 struct tt_work *tt_work __free(kfree);
336 struct tt_trip *tt_trip __free(kfree);
337 struct tt_thermal_zone *tt_zone;
338 int id;336 int id;
339 337
340 tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL);338 tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL);
@@ -350,10 +348,8 @@ int tt_zone_add_trip(const char *arg) · 9 unmodified lines
350 return PTR_ERR(tt_zone);348 return PTR_ERR(tt_zone);
351 349
352 id = ida_alloc(&tt_zone->ida, GFP_KERNEL);350 id = ida_alloc(&tt_zone->ida, GFP_KERNEL);
353 if (id < 0) {351 if (id < 0)
354 tt_put_tt_zone(tt_zone);
355 return id;352 return id;
356 }
357 353
358 tt_trip->trip.type = THERMAL_TRIP_ACTIVE;354 tt_trip->trip.type = THERMAL_TRIP_ACTIVE;
359 tt_trip->trip.temperature = THERMAL_TEMP_INVALID;355 tt_trip->trip.temperature = THERMAL_TEMP_INVALID;
@@ -366,7 +362,7 @@ int tt_zone_add_trip(const char *arg) · 6 unmodified lines
366 tt_zone->num_trips++;362 tt_zone->num_trips++;
367 363
368 INIT_WORK(&tt_work->work, tt_zone_add_trip_work_fn);364 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);
370 tt_work->tt_trip = no_free_ptr(tt_trip);366 tt_work->tt_trip = no_free_ptr(tt_trip);
371 schedule_work(&(no_free_ptr(tt_work)->work));367 schedule_work(&(no_free_ptr(tt_work)->work));
372 368
@@ -391,7 +387,7 @@ static struct thermal_zone_device_ops tt_zone_ops = { · 18 unmodified lines
391 387
392static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone)388static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone)
393{389{
394 struct thermal_trip *trips __free(kfree);390 struct thermal_trip *trips __free(kfree) = NULL;
395 struct thermal_zone_device *tz;391 struct thermal_zone_device *tz;
396 struct tt_trip *tt_trip;392 struct tt_trip *tt_trip;
397 int i;393 int i;
@@ -425,23 +421,18 @@ static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) · 27 unmodified lines
425 421
426int tt_zone_reg(const char *arg)422int tt_zone_reg(const char *arg)
427{423{
428 struct tt_thermal_zone *tt_zone;424 struct tt_thermal_zone *tt_zone __free(put_tt_zone);
429 int ret;
430 425
431 tt_zone = tt_get_tt_zone(arg);426 tt_zone = tt_get_tt_zone(arg);
432 if (IS_ERR(tt_zone))427 if (IS_ERR(tt_zone))
433 return PTR_ERR(tt_zone);428 return PTR_ERR(tt_zone);
434 429
435 ret = tt_zone_register_tz(tt_zone);430 return tt_zone_register_tz(tt_zone);
436
437 tt_put_tt_zone(tt_zone);
438
439 return ret;
440}431}
441 432
442int tt_zone_unreg(const char *arg)433int tt_zone_unreg(const char *arg)
443{434{
444 struct tt_thermal_zone *tt_zone;435 struct tt_thermal_zone *tt_zone __free(put_tt_zone);
445 436
446 tt_zone = tt_get_tt_zone(arg);437 tt_zone = tt_get_tt_zone(arg);
447 if (IS_ERR(tt_zone))438 if (IS_ERR(tt_zone))
@@ -449,8 +440,6 @@ int tt_zone_unreg(const char *arg) · 1 unmodified line
449 440
450 tt_zone_unregister_tz(tt_zone);441 tt_zone_unregister_tz(tt_zone);
451 442
452 tt_put_tt_zone(tt_zone);
453
454 return 0;443 return 0;
455}444}
456 445
drivers/thermal/thermal_core.c+503−380
@@ -15,7 +15,6 @@ · 14 unmodified lines
15#include <linux/slab.h>15#include <linux/slab.h>
16#include <linux/kdev_t.h>16#include <linux/kdev_t.h>
17#include <linux/idr.h>17#include <linux/idr.h>
18#include <linux/list_sort.h>
19#include <linux/thermal.h>18#include <linux/thermal.h>
20#include <linux/reboot.h>19#include <linux/reboot.h>
21#include <linux/string.h>20#include <linux/string.h>
@@ -40,6 +39,8 @@ static DEFINE_MUTEX(thermal_governor_lock); · 18 unmodified lines
40 39
41static struct thermal_governor *def_governor;40static struct thermal_governor *def_governor;
42 41
42static bool thermal_pm_suspended;
43
43/*44/*
44 * Governor section: set of functions to handle thermal governors45 * Governor section: set of functions to handle thermal governors
45 *46 *
@@ -122,7 +123,7 @@ int thermal_register_governor(struct thermal_governor *governor) · 76 unmodified lines
122 if (!governor)123 if (!governor)
123 return -EINVAL;124 return -EINVAL;
124 125
125 mutex_lock(&thermal_governor_lock);126 guard(mutex)(&thermal_governor_lock);
126 127
127 err = -EBUSY;128 err = -EBUSY;
128 if (!__find_governor(governor->name)) {129 if (!__find_governor(governor->name)) {
@@ -138,7 +139,7 @@ int thermal_register_governor(struct thermal_governor *governor) · 9 unmodified lines
138 def_governor = governor;139 def_governor = governor;
139 }140 }
140 141
141 mutex_lock(&thermal_list_lock);142 guard(mutex)(&thermal_list_lock);
142 143
143 list_for_each_entry(pos, &thermal_tz_list, node) {144 list_for_each_entry(pos, &thermal_tz_list, node) {
144 /*145 /*
@@ -161,9 +162,6 @@ int thermal_register_governor(struct thermal_governor *governor) · 16 unmodified lines
161 }162 }
162 }163 }
163 164
164 mutex_unlock(&thermal_list_lock);
165 mutex_unlock(&thermal_governor_lock);
166
167 return err;165 return err;
168}166}
169 167
@@ -174,23 +172,20 @@ void thermal_unregister_governor(struct thermal_governor *governor) · 4 unmodified lines
174 if (!governor)172 if (!governor)
175 return;173 return;
176 174
177 mutex_lock(&thermal_governor_lock);175 guard(mutex)(&thermal_governor_lock);
178 176
179 if (!__find_governor(governor->name))177 if (!__find_governor(governor->name))
180 goto exit;178 return;
181 179
182 mutex_lock(&thermal_list_lock);180 list_del(&governor->governor_list);
181
182 guard(mutex)(&thermal_list_lock);
183 183
184 list_for_each_entry(pos, &thermal_tz_list, node) {184 list_for_each_entry(pos, &thermal_tz_list, node) {
185 if (!strncasecmp(pos->governor->name, governor->name,185 if (!strncasecmp(pos->governor->name, governor->name,
186 THERMAL_NAME_LENGTH))186 THERMAL_NAME_LENGTH))
187 thermal_set_governor(pos, NULL);187 thermal_set_governor(pos, NULL);
188 }188 }
189
190 mutex_unlock(&thermal_list_lock);
191 list_del(&governor->governor_list);
192exit:
193 mutex_unlock(&thermal_governor_lock);
194}189}
195 190
196int thermal_zone_device_set_policy(struct thermal_zone_device *tz,191int 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
199 struct thermal_governor *gov;194 struct thermal_governor *gov;
200 int ret = -EINVAL;195 int ret = -EINVAL;
201 196
202 mutex_lock(&thermal_governor_lock);197 guard(mutex)(&thermal_governor_lock);
203 mutex_lock(&tz->lock);198 guard(thermal_zone)(tz);
204 199
205 gov = __find_governor(strim(policy));200 gov = __find_governor(strim(policy));
206 if (!gov)201 if (gov)
207 goto exit;202 ret = thermal_set_governor(tz, gov);
208
209 ret = thermal_set_governor(tz, gov);
210
211exit:
212 mutex_unlock(&tz->lock);
213 mutex_unlock(&thermal_governor_lock);
214 203
215 thermal_notify_tz_gov_change(tz, policy);204 thermal_notify_tz_gov_change(tz, policy);
216 205
@@ -222,15 +211,13 @@ int thermal_build_list_of_policies(char *buf) · 5 unmodified lines
222 struct thermal_governor *pos;211 struct thermal_governor *pos;
223 ssize_t count = 0;212 ssize_t count = 0;
224 213
225 mutex_lock(&thermal_governor_lock);214 guard(mutex)(&thermal_governor_lock);
226 215
227 list_for_each_entry(pos, &thermal_governor_list, governor_list) {216 list_for_each_entry(pos, &thermal_governor_list, governor_list) {
228 count += sysfs_emit_at(buf, count, "%s ", pos->name);217 count += sysfs_emit_at(buf, count, "%s ", pos->name);
229 }218 }
230 count += sysfs_emit_at(buf, count, "\n");219 count += sysfs_emit_at(buf, count, "\n");
231 220
232 mutex_unlock(&thermal_governor_lock);
233
234 return count;221 return count;
235}222}
236 223
@@ -421,83 +408,46 @@ static void handle_critical_trips(struct thermal_zone_device *tz, · 184 unmodified lines
421 tz->ops.hot(tz);408 tz->ops.hot(tz);
422}409}
423 410
424static void handle_thermal_trip(struct thermal_zone_device *tz,411static void move_trip_to_sorted_list(struct thermal_trip_desc *td,
425 struct thermal_trip_desc *td,412 struct list_head *list)
426 struct list_head *way_up_list,
427 struct list_head *way_down_list)
428{413{
429 const struct thermal_trip *trip = &td->trip;414 struct thermal_trip_desc *entry;
430 int old_threshold;
431
432 if (trip->temperature == THERMAL_TEMP_INVALID)
433 return;
434 415
435 /*416 /*
436 * If the trip temperature or hysteresis has been updated recently,417 * Delete upfront and then add to make relocation within the same list
437 * the threshold needs to be computed again using the new values.418 * work.
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.
441 */419 */
442 old_threshold = td->threshold;420 list_del(&td->list_node);
443 td->threshold = trip->temperature;
444 421
445 if (tz->last_temperature >= old_threshold &&422 /* Assume that the new entry is likely to be the last one. */
446 tz->last_temperature != THERMAL_TEMP_INIT) {423 list_for_each_entry_reverse(entry, list, list_node) {
447 /*424 if (entry->threshold <= td->threshold) {
448 * Mitigation is under way, so it needs to stop if the zone425 list_add(&td->list_node, &entry->list_node);
449 * temperature falls below the low temperature of the trip.426 return;
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;
462 }427 }
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);
478 }428 }
429 list_add(&td->list_node, list);
479}430}
480 431
481static void thermal_zone_device_check(struct work_struct *work)432static void move_to_trips_high(struct thermal_zone_device *tz,
433 struct thermal_trip_desc *td)
482{434{
483 struct thermal_zone_device *tz = container_of(work, struct435 td->threshold = td->trip.temperature;
484 thermal_zone_device,436 move_trip_to_sorted_list(td, &tz->trips_high);
485 poll_queue.work);
486 thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
487}437}
488 438
489static void thermal_zone_device_init(struct thermal_zone_device *tz)439static void move_to_trips_reached(struct thermal_zone_device *tz,
440 struct thermal_trip_desc *td)
490{441{
491 struct thermal_instance *pos;442 td->threshold = td->trip.temperature - td->trip.hysteresis;
492 443 move_trip_to_sorted_list(td, &tz->trips_reached);
493 INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);444}
494 445
495 tz->temperature = THERMAL_TEMP_INIT;446static void move_to_trips_invalid(struct thermal_zone_device *tz,
496 tz->passive = 0;447 struct thermal_trip_desc *td)
497 tz->prev_low_trip = -INT_MAX;448{
498 tz->prev_high_trip = INT_MAX;449 td->threshold = INT_MAX;
499 list_for_each_entry(pos, &tz->thermal_instances, tz_node)450 list_move(&td->list_node, &tz->trips_invalid);
500 pos->initialized = false;
501}451}
502 452
503static void thermal_governor_trip_crossed(struct thermal_governor *governor,453static 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
513}463}
514 464
515static void thermal_trip_crossed(struct thermal_zone_device *tz,465static void thermal_trip_crossed(struct thermal_zone_device *tz,
516 const struct thermal_trip *trip,466 struct thermal_trip_desc *td,
517 struct thermal_governor *governor,467 struct thermal_governor *governor,
518 bool crossed_up)468 bool crossed_up)
519{469{
470 const struct thermal_trip *trip = &td->trip;
471
520 if (crossed_up) {472 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
521 thermal_notify_tz_trip_up(tz, trip);479 thermal_notify_tz_trip_up(tz, trip);
522 thermal_debug_tz_trip_up(tz, trip);480 thermal_debug_tz_trip_up(tz, trip);
523 } else {481 } else {
482 if (trip->type == THERMAL_TRIP_PASSIVE) {
483 tz->passive--;
484 WARN_ON(tz->passive < 0);
485 }
524 thermal_notify_tz_trip_down(tz, trip);486 thermal_notify_tz_trip_down(tz, trip);
525 thermal_debug_tz_trip_down(tz, trip);487 thermal_debug_tz_trip_down(tz, trip);
526 }488 }
527 thermal_governor_trip_crossed(governor, tz, trip, crossed_up);489 thermal_governor_trip_crossed(governor, tz, trip, crossed_up);
528}490}
529 491
530static int thermal_trip_notify_cmp(void *not_used, const struct list_head *a,492void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
531 const struct list_head *b)493 struct thermal_trip *trip, int hyst)
532{494{
533 struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc,495 struct thermal_trip_desc *td = trip_to_trip_desc(trip);
534 notify_list_node);496
535 struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc,497 WRITE_ONCE(trip->hysteresis, hyst);
536 notify_list_node);498 thermal_notify_tz_trip_change(tz, trip);
537 return tda->notify_temp - tdb->notify_temp;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
509void 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}
556EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
557
558static 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 }
538}604}
539 605
540void __thermal_zone_device_update(struct thermal_zone_device *tz,606void __thermal_zone_device_update(struct thermal_zone_device *tz,
541 enum thermal_notify_event event)607 enum thermal_notify_event event)
542{608{
543 struct thermal_governor *governor = thermal_get_tz_governor(tz);609 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);
547 int low = -INT_MAX, high = INT_MAX;610 int low = -INT_MAX, high = INT_MAX;
548 int temp, ret;611 int temp, ret;
549 612
550 if (tz->suspended || tz->mode != THERMAL_DEVICE_ENABLED)613 if (tz->state != TZ_STATE_READY || tz->mode != THERMAL_DEVICE_ENABLED)
551 return;614 return;
552 615
553 ret = __thermal_zone_get_temp(tz, &temp);616 ret = __thermal_zone_get_temp(tz, &temp);
@@ -575,26 +638,12 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, · 21 unmodified lines
575 638
576 tz->notify_event = event;639 tz->notify_event = event;
577 640
578 for_each_trip_desc(tz, td) {641 thermal_zone_handle_trips(tz, governor, &low, &high);
579 handle_thermal_trip(tz, td, &way_up_list, &way_down_list);
580 642
581 if (td->threshold <= tz->temperature && td->threshold > low)643 thermal_thresholds_handle(tz, &low, &high);
582 low = td->threshold;
583
584 if (td->threshold >= tz->temperature && td->threshold < high)
585 high = td->threshold;
586 }
587 644
588 thermal_zone_set_trips(tz, low, high);645 thermal_zone_set_trips(tz, low, high);
589 646
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
598 if (governor->manage)647 if (governor->manage)
599 governor->manage(tz);648 governor->manage(tz);
600 649
@@ -609,26 +658,18 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, · 8 unmodified lines
609{658{
610 int ret;659 int ret;
611 660
612 mutex_lock(&tz->lock);661 guard(thermal_zone)(tz);
613 662
614 /* do nothing if mode isn't changing */663 /* do nothing if mode isn't changing */
615 if (mode == tz->mode) {664 if (mode == tz->mode)
616 mutex_unlock(&tz->lock);
617
618 return 0;665 return 0;
619 }
620 666
621 ret = __thermal_zone_device_set_mode(tz, mode);667 ret = __thermal_zone_device_set_mode(tz, mode);
622 if (ret) {668 if (ret)
623 mutex_unlock(&tz->lock);
624
625 return ret;669 return ret;
626 }
627 670
628 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);671 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
629 672
630 mutex_unlock(&tz->lock);
631
632 if (mode == THERMAL_DEVICE_ENABLED)673 if (mode == THERMAL_DEVICE_ENABLED)
633 thermal_notify_tz_enable(tz);674 thermal_notify_tz_enable(tz);
634 else675 else
@@ -657,85 +698,81 @@ static bool thermal_zone_is_present(struct thermal_zone_device *tz) · 22 unmodified lines
657void thermal_zone_device_update(struct thermal_zone_device *tz,698void thermal_zone_device_update(struct thermal_zone_device *tz,
658 enum thermal_notify_event event)699 enum thermal_notify_event event)
659{700{
660 mutex_lock(&tz->lock);701 guard(thermal_zone)(tz);
702
661 if (thermal_zone_is_present(tz))703 if (thermal_zone_is_present(tz))
662 __thermal_zone_device_update(tz, event);704 __thermal_zone_device_update(tz, event);
663 mutex_unlock(&tz->lock);
664}705}
665EXPORT_SYMBOL_GPL(thermal_zone_device_update);706EXPORT_SYMBOL_GPL(thermal_zone_device_update);
666 707
667void 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
673int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),708int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
674 void *data)709 void *data)
675{710{
676 struct thermal_governor *gov;711 struct thermal_governor *gov;
677 int ret = 0;
678 712
679 mutex_lock(&thermal_governor_lock);713 guard(mutex)(&thermal_governor_lock);
714
680 list_for_each_entry(gov, &thermal_governor_list, governor_list) {715 list_for_each_entry(gov, &thermal_governor_list, governor_list) {
716 int ret;
717
681 ret = cb(gov, data);718 ret = cb(gov, data);
682 if (ret)719 if (ret)
683 break;720 return ret;
684 }721 }
685 mutex_unlock(&thermal_governor_lock);
686 722
687 return ret;723 return 0;
688}724}
689 725
690int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,726int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
691 void *), void *data)727 void *), void *data)
692{728{
693 struct thermal_cooling_device *cdev;729 struct thermal_cooling_device *cdev;
694 int ret = 0;
695 730
696 mutex_lock(&thermal_list_lock);731 guard(mutex)(&thermal_list_lock);
732
697 list_for_each_entry(cdev, &thermal_cdev_list, node) {733 list_for_each_entry(cdev, &thermal_cdev_list, node) {
734 int ret;
735
698 ret = cb(cdev, data);736 ret = cb(cdev, data);
699 if (ret)737 if (ret)
700 break;738 return ret;
701 }739 }
702 mutex_unlock(&thermal_list_lock);
703 740
704 return ret;741 return 0;
705}742}
706 743
707int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *),744int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *),
708 void *data)745 void *data)
709{746{
710 struct thermal_zone_device *tz;747 struct thermal_zone_device *tz;
711 int ret = 0;
712 748
713 mutex_lock(&thermal_list_lock);749 guard(mutex)(&thermal_list_lock);
750
714 list_for_each_entry(tz, &thermal_tz_list, node) {751 list_for_each_entry(tz, &thermal_tz_list, node) {
752 int ret;
753
715 ret = cb(tz, data);754 ret = cb(tz, data);
716 if (ret)755 if (ret)
717 break;756 return ret;
718 }757 }
719 mutex_unlock(&thermal_list_lock);
720 758
721 return ret;759 return 0;
722}760}
723 761
724struct thermal_zone_device *thermal_zone_get_by_id(int id)762struct thermal_zone_device *thermal_zone_get_by_id(int id)
725{763{
726 struct thermal_zone_device *tz, *match = NULL;764 struct thermal_zone_device *tz;
765
766 guard(mutex)(&thermal_list_lock);
727 767
728 mutex_lock(&thermal_list_lock);
729 list_for_each_entry(tz, &thermal_tz_list, node) {768 list_for_each_entry(tz, &thermal_tz_list, node) {
730 if (tz->id == id) {769 if (tz->id == id) {
731 get_device(&tz->device);770 get_device(&tz->device);
732 match = tz;771 return tz;
733 break;
734 }772 }
735 }773 }
736 mutex_unlock(&thermal_list_lock);
737 774
738 return match;775 return NULL;
739}776}
740 777
741/*778/*
@@ -748,12 +785,32 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) · 6 unmodified lines
748 * binding, and unbinding.785 * binding, and unbinding.
749 */786 */
750 787
788static 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
751/**808/**
752 * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone809 * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone
753 * @tz: pointer to struct thermal_zone_device810 * @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
755 * @cdev: pointer to struct thermal_cooling_device812 * @cdev: pointer to struct thermal_cooling_device
756 * @cool_spec: cooling specification for @trip and @cdev813 * @cool_spec: cooling specification for the trip point and @cdev
757 *814 *
758 * This interface function bind a thermal cooling device to the certain trip815 * This interface function bind a thermal cooling device to the certain trip
759 * point of a thermal zone device.816 * point of a thermal zone device.
@@ -762,12 +819,11 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) · 2 unmodified lines
762 * Return: 0 on success, the proper error value otherwise.819 * Return: 0 on success, the proper error value otherwise.
763 */820 */
764static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,821static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
765 const struct thermal_trip *trip,822 struct thermal_trip_desc *td,
766 struct thermal_cooling_device *cdev,823 struct thermal_cooling_device *cdev,
767 struct cooling_spec *cool_spec)824 struct cooling_spec *cool_spec)
768{825{
769 struct thermal_instance *dev;826 struct thermal_instance *dev;
770 struct thermal_instance *pos;
771 bool upper_no_limit;827 bool upper_no_limit;
772 int result;828 int result;
773 829
@@ -790,7 +846,7 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, · 16 unmodified lines
790 return -ENOMEM;846 return -ENOMEM;
791 847
792 dev->cdev = cdev;848 dev->cdev = cdev;
793 dev->trip = trip;849 dev->trip = &td->trip;
794 dev->upper = cool_spec->upper;850 dev->upper = cool_spec->upper;
795 dev->upper_no_limit = upper_no_limit;851 dev->upper_no_limit = upper_no_limit;
796 dev->lower = cool_spec->lower;852 dev->lower = cool_spec->lower;
@@ -829,24 +885,15 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, · 32 unmodified lines
829 if (result)885 if (result)
830 goto remove_trip_file;886 goto remove_trip_file;
831 887
832 mutex_lock(&cdev->lock);888 result = thermal_instance_add(dev, cdev, td);
833 list_for_each_entry(pos, &tz->thermal_instances, tz_node)889 if (result)
834 if (pos->trip == trip && pos->cdev == cdev) {890 goto remove_weight_file;
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);
842 891
843 thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV);892 thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV);
844 }
845 mutex_unlock(&cdev->lock);
846 893
847 if (!result)894 return 0;
848 return 0;
849 895
896remove_weight_file:
850 device_remove_file(&tz->device, &dev->weight_attr);897 device_remove_file(&tz->device, &dev->weight_attr);
851remove_trip_file:898remove_trip_file:
852 device_remove_file(&tz->device, &dev->attr);899 device_remove_file(&tz->device, &dev->attr);
@@ -859,10 +906,19 @@ free_mem: · 6 unmodified lines
859 return result;906 return result;
860}907}
861 908
909static 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
862/**918/**
863 * thermal_unbind_cdev_from_trip - unbind a cooling device from a thermal zone.919 * thermal_unbind_cdev_from_trip - unbind a cooling device from a thermal zone.
864 * @tz: pointer to a struct thermal_zone_device.920 * @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
866 * @cdev: pointer to a struct thermal_cooling_device.922 * @cdev: pointer to a struct thermal_cooling_device.
867 *923 *
868 * This interface function unbind a thermal cooling device from the certain924 * This interface function unbind a thermal cooling device from the certain
@@ -870,28 +926,23 @@ free_mem: · 1 unmodified line
870 * This function is usually called in the thermal zone device .unbind callback.926 * This function is usually called in the thermal zone device .unbind callback.
871 */927 */
872static void thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,928static void thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
873 const struct thermal_trip *trip,929 struct thermal_trip_desc *td,
874 struct thermal_cooling_device *cdev)930 struct thermal_cooling_device *cdev)
875{931{
876 struct thermal_instance *pos, *next;932 struct thermal_instance *pos, *next;
877 933
878 mutex_lock(&cdev->lock);934 list_for_each_entry_safe(pos, next, &td->thermal_instances, trip_node) {
879 list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {935 if (pos->cdev == cdev) {
880 if (pos->trip == trip && pos->cdev == cdev) {936 thermal_instance_delete(pos);
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);
887 goto unbind;937 goto unbind;
888 }938 }
889 }939 }
890 mutex_unlock(&cdev->lock);
891 940
892 return;941 return;
893 942
894unbind:943unbind:
944 thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV);
945
895 device_remove_file(&tz->device, &pos->weight_attr);946 device_remove_file(&tz->device, &pos->weight_attr);
896 device_remove_file(&tz->device, &pos->attr);947 device_remove_file(&tz->device, &pos->attr);
897 sysfs_remove_link(&tz->device.kobj, pos->name);948 sysfs_remove_link(&tz->device.kobj, pos->name);
@@ -924,25 +975,23 @@ static struct class *thermal_class; · 26 unmodified lines
924 975
925static inline976static inline
926void print_bind_err_msg(struct thermal_zone_device *tz,977void print_bind_err_msg(struct thermal_zone_device *tz,
927 const struct thermal_trip *trip,978 const struct thermal_trip_desc *td,
928 struct thermal_cooling_device *cdev, int ret)979 struct thermal_cooling_device *cdev, int ret)
929{980{
930 dev_err(&tz->device, "binding cdev %s to trip %d failed: %d\n",981 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);
932}983}
933 984
934static void thermal_zone_cdev_bind(struct thermal_zone_device *tz,985static bool __thermal_zone_cdev_bind(struct thermal_zone_device *tz,
935 struct thermal_cooling_device *cdev)986 struct thermal_cooling_device *cdev)
936{987{
937 struct thermal_trip_desc *td;988 struct thermal_trip_desc *td;
989 bool update_tz = false;
938 990
939 if (!tz->ops.should_bind)991 if (!tz->ops.should_bind)
940 return;992 return false;
941
942 mutex_lock(&tz->lock);
943 993
944 for_each_trip_desc(tz, td) {994 for_each_trip_desc(tz, td) {
945 struct thermal_trip *trip = &td->trip;
946 struct cooling_spec c = {995 struct cooling_spec c = {
947 .upper = THERMAL_NO_LIMIT,996 .upper = THERMAL_NO_LIMIT,
948 .lower = THERMAL_NO_LIMIT,997 .lower = THERMAL_NO_LIMIT,
@@ -950,15 +999,40 @@ static void thermal_zone_cdev_bind(struct thermal_zone_device *tz, · 1 unmodified line
950 };999 };
951 int ret;1000 int ret;
952 1001
953 if (!tz->ops.should_bind(tz, trip, cdev, &c))1002 if (!tz->ops.should_bind(tz, &td->trip, cdev, &c))
954 continue;1003 continue;
955 1004
956 ret = thermal_bind_cdev_to_trip(tz, trip, cdev, &c);1005 ret = thermal_bind_cdev_to_trip(tz, td, cdev, &c);
957 if (ret)1006 if (ret) {
958 print_bind_err_msg(tz, trip, cdev, ret);1007 print_bind_err_msg(tz, td, cdev, ret);
1008 continue;
1009 }
1010
1011 update_tz = true;
959 }1012 }
960 1013
961 mutex_unlock(&tz->lock);1014 return update_tz;
1015}
1016
1017static 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
1026static 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);
962}1036}
963 1037
964/**1038/**
@@ -983,7 +1057,6 @@ __thermal_cooling_device_register(struct device_node *np, · 18 unmodified lines
983 const struct thermal_cooling_device_ops *ops)1057 const struct thermal_cooling_device_ops *ops)
984{1058{
985 struct thermal_cooling_device *cdev;1059 struct thermal_cooling_device *cdev;
986 struct thermal_zone_device *pos = NULL;
987 unsigned long current_state;1060 unsigned long current_state;
988 int id, ret;1061 int id, ret;
989 1062
@@ -1050,21 +1123,7 @@ __thermal_cooling_device_register(struct device_node *np, · 60 unmodified lines
1050 if (current_state <= cdev->max_state)1123 if (current_state <= cdev->max_state)
1051 thermal_debug_cdev_add(cdev, current_state);1124 thermal_debug_cdev_add(cdev, current_state);
1052 1125
1053 /* Add 'this' new cdev to the global cdev list */1126 thermal_cooling_device_init_complete(cdev);
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);
1068 1127
1069 return cdev;1128 return cdev;
1070 1129
@@ -1207,19 +1266,19 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) · 136 unmodified lines
1207 * Hold thermal_list_lock throughout the update to prevent the device1266 * Hold thermal_list_lock throughout the update to prevent the device
1208 * from going away while being updated.1267 * from going away while being updated.
1209 */1268 */
1210 mutex_lock(&thermal_list_lock);1269 guard(mutex)(&thermal_list_lock);
1211 1270
1212 if (!thermal_cooling_device_present(cdev))1271 if (!thermal_cooling_device_present(cdev))
1213 goto unlock_list;1272 return;
1214 1273
1215 /*1274 /*
1216 * Update under the cdev lock to prevent the state from being set beyond1275 * Update under the cdev lock to prevent the state from being set beyond
1217 * the new limit concurrently.1276 * the new limit concurrently.
1218 */1277 */
1219 mutex_lock(&cdev->lock);1278 guard(cooling_dev)(cdev);
1220 1279
1221 if (cdev->ops->get_max_state(cdev, &cdev->max_state))1280 if (cdev->ops->get_max_state(cdev, &cdev->max_state))
1222 goto unlock;1281 return;
1223 1282
1224 thermal_cooling_device_stats_reinit(cdev);1283 thermal_cooling_device_stats_reinit(cdev);
1225 1284
@@ -1246,63 +1305,59 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) · 20 unmodified lines
1246 }1305 }
1247 1306
1248 if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state)1307 if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state)
1249 goto unlock;1308 return;
1250 1309
1251 thermal_cooling_device_stats_update(cdev, state);1310 thermal_cooling_device_stats_update(cdev, state);
1252
1253unlock:
1254 mutex_unlock(&cdev->lock);
1255
1256unlock_list:
1257 mutex_unlock(&thermal_list_lock);
1258}1311}
1259EXPORT_SYMBOL_GPL(thermal_cooling_device_update);1312EXPORT_SYMBOL_GPL(thermal_cooling_device_update);
1260 1313
1261static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz,1314static void __thermal_zone_cdev_unbind(struct thermal_zone_device *tz,
1262 struct thermal_cooling_device *cdev)1315 struct thermal_cooling_device *cdev)
1263{1316{
1264 struct thermal_trip_desc *td;1317 struct thermal_trip_desc *td;
1265 1318
1266 mutex_lock(&tz->lock);
1267
1268 for_each_trip_desc(tz, td)1319 for_each_trip_desc(tz, td)
1269 thermal_unbind_cdev_from_trip(tz, &td->trip, cdev);1320 thermal_unbind_cdev_from_trip(tz, td, cdev);
1270
1271 mutex_unlock(&tz->lock);
1272}1321}
1273 1322
1274/**1323static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz,
1275 * thermal_cooling_device_unregister - removes a thermal cooling device1324 struct thermal_cooling_device *cdev)
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 */
1281void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
1282{1325{
1283 struct thermal_zone_device *tz;1326 guard(thermal_zone)(tz);
1284 1327
1285 if (!cdev)1328 __thermal_zone_cdev_unbind(tz, cdev);
1286 return;1329}
1287 1330
1288 thermal_debug_cdev_remove(cdev);1331static bool thermal_cooling_device_exit(struct thermal_cooling_device *cdev)
1332{
1333 struct thermal_zone_device *tz;
1289 1334
1290 mutex_lock(&thermal_list_lock);1335 guard(mutex)(&thermal_list_lock);
1291 1336
1292 if (!thermal_cooling_device_present(cdev)) {1337 if (!thermal_cooling_device_present(cdev))
1293 mutex_unlock(&thermal_list_lock);1338 return false;
1294 return;
1295 }
1296 1339
1297 list_del(&cdev->node);1340 list_del(&cdev->node);
1298 1341
1299 /* Unbind all thermal zones associated with 'this' cdev */
1300 list_for_each_entry(tz, &thermal_tz_list, node)1342 list_for_each_entry(tz, &thermal_tz_list, node)
1301 thermal_zone_cdev_unbind(tz, cdev);1343 thermal_zone_cdev_unbind(tz, cdev);
1302 1344
1303 mutex_unlock(&thermal_list_lock);1345 return true;
1346}
1304 1347
1305 device_unregister(&cdev->device);1348/**
1349 * thermal_cooling_device_unregister() - removes a thermal cooling device
1350 * @cdev: Thermal cooling device to remove.
1351 */
1352void 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);
1306}1361}
1307EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);1362EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
1308 1363
@@ -1314,7 +1369,7 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) · 5 unmodified lines
1314 if (tz->ops.get_crit_temp)1369 if (tz->ops.get_crit_temp)
1315 return tz->ops.get_crit_temp(tz, temp);1370 return tz->ops.get_crit_temp(tz, temp);
1316 1371
1317 mutex_lock(&tz->lock);1372 guard(thermal_zone)(tz);
1318 1373
1319 for_each_trip_desc(tz, td) {1374 for_each_trip_desc(tz, td) {
1320 const struct thermal_trip *trip = &td->trip;1375 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
1326 }1381 }
1327 }1382 }
1328 1383
1329 mutex_unlock(&tz->lock);
1330
1331 return ret;1384 return ret;
1332}1385}
1333EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp);1386EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp);
1334 1387
1388static 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
1396static 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
1429static 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
1443static 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
1335/**1469/**
1336 * thermal_zone_device_register_with_trips() - register a new thermal zone device1470 * thermal_zone_device_register_with_trips() - register a new thermal zone device
1337 * @type: the thermal zone device type1471 * @type: the thermal zone device type
@@ -1366,12 +1500,10 @@ thermal_zone_device_register_with_trips(const char *type, · 28 unmodified lines
1366 unsigned int polling_delay)1500 unsigned int polling_delay)
1367{1501{
1368 const struct thermal_trip *trip = trips;1502 const struct thermal_trip *trip = trips;
1369 struct thermal_cooling_device *cdev;
1370 struct thermal_zone_device *tz;1503 struct thermal_zone_device *tz;
1371 struct thermal_trip_desc *td;1504 struct thermal_trip_desc *td;
1372 int id;1505 int id;
1373 int result;1506 int result;
1374 struct thermal_governor *governor;
1375 1507
1376 if (!type || strlen(type) == 0) {1508 if (!type || strlen(type) == 0) {
1377 pr_err("No thermal zone type defined\n");1509 pr_err("No thermal zone type defined\n");
@@ -1415,8 +1547,10 @@ thermal_zone_device_register_with_trips(const char *type, · 37 unmodified lines
1415 }1547 }
1416 }1548 }
1417 1549
1418 INIT_LIST_HEAD(&tz->thermal_instances);
1419 INIT_LIST_HEAD(&tz->node);1550 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);
1420 ida_init(&tz->ida);1554 ida_init(&tz->ida);
1421 mutex_init(&tz->lock);1555 mutex_init(&tz->lock);
1422 init_completion(&tz->removal);1556 init_completion(&tz->removal);
@@ -1439,51 +1573,41 @@ thermal_zone_device_register_with_trips(const char *type, · 16 unmodified lines
1439 tz->num_trips = num_trips;1573 tz->num_trips = num_trips;
1440 for_each_trip_desc(tz, td) {1574 for_each_trip_desc(tz, td) {
1441 td->trip = *trip++;1575 td->trip = *trip++;
1576 INIT_LIST_HEAD(&td->thermal_instances);
1577 INIT_LIST_HEAD(&td->list_node);
1442 /*1578 /*
1443 * Mark all thresholds as invalid to start with even though1579 * Mark all thresholds as invalid to start with even though
1444 * this only matters for the trips that start as invalid and1580 * this only matters for the trips that start as invalid and
1445 * become valid later.1581 * become valid later.
1446 */1582 */
1447 td->threshold = INT_MAX;1583 move_to_trips_invalid(tz, td);
1448 }1584 }
1449 1585
1450 tz->polling_delay_jiffies = msecs_to_jiffies(polling_delay);1586 tz->polling_delay_jiffies = msecs_to_jiffies(polling_delay);
1451 tz->passive_delay_jiffies = msecs_to_jiffies(passive_delay);1587 tz->passive_delay_jiffies = msecs_to_jiffies(passive_delay);
1452 tz->recheck_delay_jiffies = THERMAL_RECHECK_DELAY;1588 tz->recheck_delay_jiffies = THERMAL_RECHECK_DELAY;
1453 1589
1590 tz->state = TZ_STATE_FLAG_INIT;
1591
1454 /* sys I/F */1592 /* sys I/F */
1455 /* Add nodes that are always present via .groups */1593 /* Add nodes that are always present via .groups */
1456 result = thermal_zone_create_device_groups(tz);1594 result = thermal_zone_create_device_groups(tz);
1457 if (result)1595 if (result)
1458 goto remove_id;1596 goto remove_id;
1459 1597
1460 /* A new thermal zone needs to be updated anyway. */
1461 atomic_set(&tz->need_update, 1);
1462
1463 result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);1598 result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
1464 if (result) {1599 if (result) {
1465 thermal_zone_destroy_device_groups(tz);1600 thermal_zone_destroy_device_groups(tz);
1466 goto remove_id;1601 goto remove_id;
1467 }1602 }
1603 thermal_zone_device_init(tz);
1468 result = device_register(&tz->device);1604 result = device_register(&tz->device);
1469 if (result)1605 if (result)
1470 goto release_device;1606 goto release_device;
1471 1607
1472 /* Update 'this' zone's governor information */1608 result = thermal_zone_init_governor(tz);
1473 mutex_lock(&thermal_governor_lock);1609 if (result)
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);
1483 goto unregister;1610 goto unregister;
1484 }
1485
1486 mutex_unlock(&thermal_governor_lock);
1487 1611
1488 if (!tz->tzp || !tz->tzp->no_hwmon) {1612 if (!tz->tzp || !tz->tzp->no_hwmon) {
1489 result = thermal_add_hwmon_sysfs(tz);1613 result = thermal_add_hwmon_sysfs(tz);
@@ -1491,22 +1615,11 @@ thermal_zone_device_register_with_trips(const char *type, · 1 unmodified line
1491 goto unregister;1615 goto unregister;
1492 }1616 }
1493 1617
1494 mutex_lock(&thermal_list_lock);1618 result = thermal_thresholds_init(tz);
1495 1619 if (result)
1496 mutex_lock(&tz->lock);1620 goto remove_hwmon;
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);
1505 1621
1506 thermal_zone_device_init(tz);1622 thermal_zone_init_complete(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);
1510 1623
1511 thermal_notify_tz_create(tz);1624 thermal_notify_tz_create(tz);
1512 1625
@@ -1514,6 +1627,8 @@ thermal_zone_device_register_with_trips(const char *type, · 1 unmodified line
1514 1627
1515 return tz;1628 return tz;
1516 1629
1630remove_hwmon:
1631 thermal_remove_hwmon_sysfs(tz);
1517unregister:1632unregister:
1518 device_del(&tz->device);1633 device_del(&tz->device);
1519release_device:1634release_device:
@@ -1563,44 +1678,46 @@ struct device *thermal_zone_device(struct thermal_zone_device *tzd) · 43 unmodified lines
1563}1678}
1564EXPORT_SYMBOL_GPL(thermal_zone_device);1679EXPORT_SYMBOL_GPL(thermal_zone_device);
1565 1680
1681static 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
1566/**1702/**
1567 * thermal_zone_device_unregister - removes the registered thermal zone device1703 * thermal_zone_device_unregister - removes the registered thermal zone device
1568 * @tz: the thermal zone device to remove1704 * @tz: the thermal zone device to remove
1569 */1705 */
1570void thermal_zone_device_unregister(struct thermal_zone_device *tz)1706void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1571{1707{
1572 struct thermal_cooling_device *cdev;
1573 struct thermal_zone_device *pos = NULL;
1574
1575 if (!tz)1708 if (!tz)
1576 return;1709 return;
1577 1710
1578 thermal_debug_tz_remove(tz);1711 thermal_debug_tz_remove(tz);
1579 1712
1580 mutex_lock(&thermal_list_lock);1713 if (!thermal_zone_exit(tz))
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);
1587 return;1714 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);
1599 1715
1600 cancel_delayed_work_sync(&tz->poll_queue);1716 cancel_delayed_work_sync(&tz->poll_queue);
1601 1717
1602 thermal_set_governor(tz, NULL);1718 thermal_set_governor(tz, NULL);
1603 1719
1720 thermal_thresholds_exit(tz);
1604 thermal_remove_hwmon_sysfs(tz);1721 thermal_remove_hwmon_sysfs(tz);
1605 ida_free(&thermal_tz_ida, tz->id);1722 ida_free(&thermal_tz_ida, tz->id);
1606 ida_destroy(&tz->ida);1723 ida_destroy(&tz->ida);
@@ -1632,24 +1749,23 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name) · 25 unmodified lines
1632 unsigned int found = 0;1749 unsigned int found = 0;
1633 1750
1634 if (!name)1751 if (!name)
1635 goto exit;1752 return ERR_PTR(-EINVAL);
1753
1754 guard(mutex)(&thermal_list_lock);
1636 1755
1637 mutex_lock(&thermal_list_lock);
1638 list_for_each_entry(pos, &thermal_tz_list, node)1756 list_for_each_entry(pos, &thermal_tz_list, node)
1639 if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) {1757 if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) {
1640 found++;1758 found++;
1641 ref = pos;1759 ref = pos;
1642 }1760 }
1643 mutex_unlock(&thermal_list_lock);
1644 1761
1645 /* nothing has been found, thus an error code for it */1762 if (!found)
1646 if (found == 0)1763 return ERR_PTR(-ENODEV);
1647 ref = ERR_PTR(-ENODEV);1764
1648 else if (found > 1)1765 /* Success only when one zone is found. */
1649 /* Success only when an unique zone is found */1766 if (found > 1)
1650 ref = ERR_PTR(-EEXIST);1767 return ERR_PTR(-EEXIST);
1651 1768
1652exit:
1653 return ref;1769 return ref;
1654}1770}
1655EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);1771EXPORT_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
1660 1776
1661 tz = container_of(work, struct thermal_zone_device, poll_queue.work);1777 tz = container_of(work, struct thermal_zone_device, poll_queue.work);
1662 1778
1663 mutex_lock(&tz->lock);1779 guard(thermal_zone)(tz);
1664 1780
1665 tz->suspended = false;1781 tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING);
1666 1782
1667 thermal_debug_tz_resume(tz);1783 thermal_debug_tz_resume(tz);
1668 thermal_zone_device_init(tz);1784 thermal_zone_device_init(tz);
@@ -1670,74 +1786,81 @@ static void thermal_zone_device_resume(struct work_struct *work) · 1 unmodified line
1670 __thermal_zone_device_update(tz, THERMAL_TZ_RESUME);1786 __thermal_zone_device_update(tz, THERMAL_TZ_RESUME);
1671 1787
1672 complete(&tz->resume);1788 complete(&tz->resume);
1673 tz->resuming = false;
1674
1675 mutex_unlock(&tz->lock);
1676}1789}
1677 1790
1678static int thermal_pm_notify(struct notifier_block *nb,1791static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
1679 unsigned long mode, void *_unused)
1680{1792{
1681 struct thermal_zone_device *tz;1793 guard(thermal_zone)(tz);
1682 1794
1683 switch (mode) {1795 if (tz->state & TZ_STATE_FLAG_RESUMING) {
1684 case PM_HIBERNATION_PREPARE:1796 /*
1685 case PM_RESTORE_PREPARE:1797 * thermal_zone_device_resume() queued up for this zone has not
1686 case PM_SUSPEND_PREPARE:1798 * acquired the lock yet, so release it to let the function run
1687 mutex_lock(&thermal_list_lock);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 }
1688 1805
1689 list_for_each_entry(tz, &thermal_tz_list, node) {1806 tz->state |= TZ_STATE_FLAG_SUSPENDED;
1690 mutex_lock(&tz->lock);1807}
1691 1808
1692 if (tz->resuming) {1809static void thermal_pm_notify_prepare(void)
1693 /*1810{
1694 * thermal_zone_device_resume() queued up for1811 struct thermal_zone_device *tz;
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);
1700 1812
1701 wait_for_completion(&tz->resume);1813 guard(mutex)(&thermal_list_lock);
1702 1814
1703 mutex_lock(&tz->lock);1815 thermal_pm_suspended = true;
1704 }
1705 1816
1706 tz->suspended = true;1817 list_for_each_entry(tz, &thermal_tz_list, node)
1818 thermal_zone_pm_prepare(tz);
1819}
1707 1820
1708 mutex_unlock(&tz->lock);1821static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
1709 }1822{
1823 guard(thermal_zone)(tz);
1710 1824
1711 mutex_unlock(&thermal_list_lock);1825 cancel_delayed_work(&tz->poll_queue);
1712 break;
1713 case PM_POST_HIBERNATION:
1714 case PM_POST_RESTORE:
1715 case PM_POST_SUSPEND:
1716 mutex_lock(&thermal_list_lock);
1717 1826
1718 list_for_each_entry(tz, &thermal_tz_list, node) {1827 reinit_completion(&tz->resume);
1719 mutex_lock(&tz->lock);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}
1720 1838
1721 cancel_delayed_work(&tz->poll_queue);1839static void thermal_pm_notify_complete(void)
1840{
1841 struct thermal_zone_device *tz;
1722 1842
1723 reinit_completion(&tz->resume);1843 guard(mutex)(&thermal_list_lock);
1724 tz->resuming = true;
1725 1844
1726 /*1845 thermal_pm_suspended = false;
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);
1736 1846
1737 mutex_unlock(&tz->lock);1847 list_for_each_entry(tz, &thermal_tz_list, node)
1738 }1848 thermal_zone_pm_complete(tz);
1849}
1739 1850
1740 mutex_unlock(&thermal_list_lock);1851static 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();
1741 break;1864 break;
1742 default:1865 default:
1743 break;1866 break;
drivers/thermal/thermal_core.h+28−13
@@ -9,10 +9,12 @@ · 8 unmodified lines
9#ifndef __THERMAL_CORE_H__9#ifndef __THERMAL_CORE_H__
10#define __THERMAL_CORE_H__10#define __THERMAL_CORE_H__
11 11
12#include <linux/cleanup.h>
12#include <linux/device.h>13#include <linux/device.h>
13#include <linux/thermal.h>14#include <linux/thermal.h>
14 15
15#include "thermal_netlink.h"16#include "thermal_netlink.h"
17#include "thermal_thresholds.h"
16#include "thermal_debugfs.h"18#include "thermal_debugfs.h"
17 19
18struct thermal_attr {20struct thermal_attr {
@@ -29,8 +31,8 @@ struct thermal_trip_attrs { · 10 unmodified lines
29struct thermal_trip_desc {31struct thermal_trip_desc {
30 struct thermal_trip trip;32 struct thermal_trip trip;
31 struct thermal_trip_attrs trip_attrs;33 struct thermal_trip_attrs trip_attrs;
32 struct list_head notify_list_node;34 struct list_head list_node;
33 int notify_temp;35 struct list_head thermal_instances;
34 int threshold;36 int threshold;
35};37};
36 38
@@ -61,6 +63,13 @@ struct thermal_governor { · 24 unmodified lines
61 struct list_head governor_list;63 struct list_head governor_list;
62};64};
63 65
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
64/**73/**
65 * struct thermal_zone_device - structure for a thermal zone74 * struct thermal_zone_device - structure for a thermal zone
66 * @id: unique id number for each thermal zone75 * @id: unique id number for each thermal zone
@@ -68,6 +77,9 @@ struct thermal_governor { · 1 unmodified line
68 * @device: &struct device for this thermal zone77 * @device: &struct device for this thermal zone
69 * @removal: removal completion78 * @removal: removal completion
70 * @resume: resume completion79 * @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
71 * @mode: current mode of this thermal zone83 * @mode: current mode of this thermal zone
72 * @devdata: private pointer for device private data84 * @devdata: private pointer for device private data
73 * @num_trips: number of trip points the thermal zone supports85 * @num_trips: number of trip points the thermal zone supports
@@ -88,20 +100,17 @@ struct thermal_governor { · 14 unmodified lines
88 trip point.100 trip point.
89 * @prev_high_trip: the above current temperature if you've crossed a101 * @prev_high_trip: the above current temperature if you've crossed a
90 passive trip point.102 passive trip point.
91 * @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
92 * @ops: operations this &thermal_zone_device supports103 * @ops: operations this &thermal_zone_device supports
93 * @tzp: thermal zone parameters104 * @tzp: thermal zone parameters
94 * @governor: pointer to the governor for this thermal zone105 * @governor: pointer to the governor for this thermal zone
95 * @governor_data: private pointer for governor data106 * @governor_data: private pointer for governor data
96 * @thermal_instances: list of &struct thermal_instance of this thermal zone
97 * @ida: &struct ida to generate unique id for this zone's cooling107 * @ida: &struct ida to generate unique id for this zone's cooling
98 * devices108 * devices
99 * @lock: lock to protect thermal_instances list109 * @lock: lock to protect thermal_instances list
100 * @node: node in thermal_tz_list (in thermal_core.c)110 * @node: node in thermal_tz_list (in thermal_core.c)
101 * @poll_queue: delayed work for polling111 * @poll_queue: delayed work for polling
102 * @notify_event: Last notification event112 * @notify_event: Last notification event
103 * @suspended: thermal zone suspend indicator113 * @state: current state of the thermal zone
104 * @resuming: indicates whether or not thermal zone resume is in progress
105 * @trips: array of struct thermal_trip objects114 * @trips: array of struct thermal_trip objects
106 */115 */
107struct thermal_zone_device {116struct thermal_zone_device {
@@ -111,6 +120,9 @@ struct thermal_zone_device { · 3 unmodified lines
111 struct completion removal;120 struct completion removal;
112 struct completion resume;121 struct completion resume;
113 struct attribute_group trips_attribute_group;122 struct attribute_group trips_attribute_group;
123 struct list_head trips_high;
124 struct list_head trips_reached;
125 struct list_head trips_invalid;
114 enum thermal_device_mode mode;126 enum thermal_device_mode mode;
115 void *devdata;127 void *devdata;
116 int num_trips;128 int num_trips;
@@ -123,25 +135,29 @@ struct thermal_zone_device { · 6 unmodified lines
123 int passive;135 int passive;
124 int prev_low_trip;136 int prev_low_trip;
125 int prev_high_trip;137 int prev_high_trip;
126 atomic_t need_update;
127 struct thermal_zone_device_ops ops;138 struct thermal_zone_device_ops ops;
128 struct thermal_zone_params *tzp;139 struct thermal_zone_params *tzp;
129 struct thermal_governor *governor;140 struct thermal_governor *governor;
130 void *governor_data;141 void *governor_data;
131 struct list_head thermal_instances;
132 struct ida ida;142 struct ida ida;
133 struct mutex lock;143 struct mutex lock;
134 struct list_head node;144 struct list_head node;
135 struct delayed_work poll_queue;145 struct delayed_work poll_queue;
136 enum thermal_notify_event notify_event;146 enum thermal_notify_event notify_event;
137 bool suspended;147 u8 state;
138 bool resuming;
139#ifdef CONFIG_THERMAL_DEBUGFS148#ifdef CONFIG_THERMAL_DEBUGFS
140 struct thermal_debugfs *debugfs;149 struct thermal_debugfs *debugfs;
141#endif150#endif
151 struct list_head user_thresholds;
142 struct thermal_trip_desc trips[] __counted_by(num_trips);152 struct thermal_trip_desc trips[] __counted_by(num_trips);
143};153};
144 154
155DEFINE_GUARD(thermal_zone, struct thermal_zone_device *, mutex_lock(&_T->lock),
156 mutex_unlock(&_T->lock))
157
158DEFINE_GUARD(thermal_zone_reverse, struct thermal_zone_device *,
159 mutex_unlock(&_T->lock), mutex_lock(&_T->lock))
160
145/* Initial thermal zone temperature. */161/* Initial thermal zone temperature. */
146#define THERMAL_TEMP_INIT INT_MIN162#define THERMAL_TEMP_INIT INT_MIN
147 163
@@ -204,6 +220,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) · 56 unmodified lines
204}220}
205 221
206void thermal_cdev_update(struct thermal_cooling_device *);222void thermal_cdev_update(struct thermal_cooling_device *);
223void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev);
207void __thermal_cdev_update(struct thermal_cooling_device *cdev);224void __thermal_cdev_update(struct thermal_cooling_device *cdev);
208 225
209int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip);226int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip);
@@ -226,7 +243,7 @@ struct thermal_instance { · 16 unmodified lines
226 struct device_attribute attr;243 struct device_attribute attr;
227 char weight_attr_name[THERMAL_NAME_LENGTH];244 char weight_attr_name[THERMAL_NAME_LENGTH];
228 struct device_attribute weight_attr;245 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 */
230 struct list_head cdev_node; /* node in cdev->thermal_instances */247 struct list_head cdev_node; /* node in cdev->thermal_instances */
231 unsigned int weight; /* The weight of the cooling device */248 unsigned int weight; /* The weight of the cooling device */
232 bool upper_no_limit;249 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
261int thermal_zone_trip_id(const struct thermal_zone_device *tz,278int thermal_zone_trip_id(const struct thermal_zone_device *tz,
262 const struct thermal_trip *trip);279 const struct thermal_trip *trip);
263int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);280int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
264void thermal_zone_trip_down(struct thermal_zone_device *tz,
265 const struct thermal_trip *trip);
266void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,281void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
267 struct thermal_trip *trip, int hyst);282 struct thermal_trip *trip, int hyst);
268 283
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
516 cdev->debugfs = thermal_dbg;516 cdev->debugfs = thermal_dbg;
517}517}
518 518
519static 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
519/**532/**
520 * thermal_debug_cdev_remove - Remove a cooling device debugfs entry533 * thermal_debug_cdev_remove - Remove a cooling device debugfs entry
521 *534 *
@@ -527,17 +540,9 @@ void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) · 5 unmodified lines
527{540{
528 struct thermal_debugfs *thermal_dbg;541 struct thermal_debugfs *thermal_dbg;
529 542
530 mutex_lock(&cdev->lock);543 thermal_dbg = thermal_debug_cdev_clear(cdev);
531 544 if (!thermal_dbg)
532 thermal_dbg = cdev->debugfs;
533 if (!thermal_dbg) {
534 mutex_unlock(&cdev->lock);
535 return;545 return;
536 }
537
538 cdev->debugfs = NULL;
539
540 mutex_unlock(&cdev->lock);
541 546
542 mutex_lock(&thermal_dbg->lock);547 mutex_lock(&thermal_dbg->lock);
543 548
@@ -885,6 +890,19 @@ void thermal_debug_tz_add(struct thermal_zone_device *tz) · 341 unmodified lines
885 tz->debugfs = thermal_dbg;890 tz->debugfs = thermal_dbg;
886}891}
887 892
893static 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
888void thermal_debug_tz_remove(struct thermal_zone_device *tz)906void thermal_debug_tz_remove(struct thermal_zone_device *tz)
889{907{
890 struct thermal_debugfs *thermal_dbg;908 struct thermal_debugfs *thermal_dbg;
@@ -892,17 +910,9 @@ void thermal_debug_tz_remove(struct thermal_zone_device *tz) · 1 unmodified line
892 struct tz_debugfs *tz_dbg;910 struct tz_debugfs *tz_dbg;
893 int *trips_crossed;911 int *trips_crossed;
894 912
895 mutex_lock(&tz->lock);913 thermal_dbg = thermal_debug_tz_clear(tz);
896 914 if (!thermal_dbg)
897 thermal_dbg = tz->debugfs;
898 if (!thermal_dbg) {
899 mutex_unlock(&tz->lock);
900 return;915 return;
901 }
902
903 tz->debugfs = NULL;
904
905 mutex_unlock(&tz->lock);
906 916
907 tz_dbg = &thermal_dbg->tz_dbg;917 tz_dbg = &thermal_dbg->tz_dbg;
908 918
drivers/thermal/thermal_helpers.c+23−23
@@ -43,10 +43,11 @@ static bool thermal_instance_present(struct thermal_zone_device *tz, · 42 unmodified lines
43 struct thermal_cooling_device *cdev,43 struct thermal_cooling_device *cdev,
44 const struct thermal_trip *trip)44 const struct thermal_trip *trip)
45{45{
46 const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
46 struct thermal_instance *ti;47 struct thermal_instance *ti;
47 48
48 list_for_each_entry(ti, &tz->thermal_instances, tz_node) {49 list_for_each_entry(ti, &td->thermal_instances, trip_node) {
49 if (ti->trip == trip && ti->cdev == cdev)50 if (ti->cdev == cdev)
50 return true;51 return true;
51 }52 }
52 53
@@ -57,17 +58,10 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz, · 4 unmodified lines
57 const struct thermal_trip *trip,58 const struct thermal_trip *trip,
58 struct thermal_cooling_device *cdev)59 struct thermal_cooling_device *cdev)
59{60{
60 bool ret;61 guard(thermal_zone)(tz);
62 guard(cooling_dev)(cdev);
61 63
62 mutex_lock(&tz->lock);64 return thermal_instance_present(tz, cdev, trip);
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;
71}65}
72EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev);66EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev);
73 67
@@ -137,19 +131,14 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) · 63 unmodified lines
137 if (IS_ERR_OR_NULL(tz))131 if (IS_ERR_OR_NULL(tz))
138 return -EINVAL;132 return -EINVAL;
139 133
140 mutex_lock(&tz->lock);134 guard(thermal_zone)(tz);
141 135
142 if (!tz->ops.get_temp) {136 if (!tz->ops.get_temp)
143 ret = -EINVAL;137 return -EINVAL;
144 goto unlock;
145 }
146 138
147 ret = __thermal_zone_get_temp(tz, temp);139 ret = __thermal_zone_get_temp(tz, temp);
148 if (!ret && *temp <= THERMAL_TEMP_INVALID)140 if (!ret && *temp <= THERMAL_TEMP_INVALID)
149 ret = -ENODATA;141 return -ENODATA;
150
151unlock:
152 mutex_unlock(&tz->lock);
153 142
154 return ret;143 return ret;
155}144}
@@ -201,12 +190,23 @@ void __thermal_cdev_update(struct thermal_cooling_device *cdev) · 45 unmodified lines
201 */190 */
202void thermal_cdev_update(struct thermal_cooling_device *cdev)191void thermal_cdev_update(struct thermal_cooling_device *cdev)
203{192{
204 mutex_lock(&cdev->lock);193 guard(cooling_dev)(cdev);
194
205 if (!cdev->updated) {195 if (!cdev->updated) {
206 __thermal_cdev_update(cdev);196 __thermal_cdev_update(cdev);
207 cdev->updated = true;197 cdev->updated = true;
208 }198 }
209 mutex_unlock(&cdev->lock);199}
200
201/**
202 * thermal_cdev_update_nocheck() - Unconditionally update cooling device state
203 * @cdev: Target cooling device.
204 */
205void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev)
206{
207 guard(cooling_dev)(cdev);
208
209 __thermal_cdev_update(cdev);
210}210}
211 211
212/**212/**
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
78 int temperature;78 int temperature;
79 int ret;79 int ret;
80 80
81 mutex_lock(&tz->lock);81 guard(thermal_zone)(tz);
82 82
83 ret = tz->ops.get_crit_temp(tz, &temperature);83 ret = tz->ops.get_crit_temp(tz, &temperature);
84
85 mutex_unlock(&tz->lock);
86
87 if (ret)84 if (ret)
88 return ret;85 return ret;
89 86
drivers/thermal/thermal_netlink.c+232−21
@@ -9,6 +9,7 @@ · 8 unmodified lines
9#include <linux/module.h>9#include <linux/module.h>
10#include <linux/notifier.h>10#include <linux/notifier.h>
11#include <linux/kernel.h>11#include <linux/kernel.h>
12#include <net/sock.h>
12#include <net/genetlink.h>13#include <net/genetlink.h>
13#include <uapi/linux/thermal.h>14#include <uapi/linux/thermal.h>
14 15
@@ -49,6 +50,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = · 34 unmodified lines
49 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 },50 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 },
50 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 },51 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 },
51 [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 },52 [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 },
52};58};
53 59
54struct param {60struct param {
@@ -62,6 +68,8 @@ struct param { · 7 unmodified lines
62 int trip_type;68 int trip_type;
63 int trip_hyst;69 int trip_hyst;
64 int temp;70 int temp;
71 int prev_temp;
72 int direction;
65 int cdev_state;73 int cdev_state;
66 int cdev_max_state;74 int cdev_max_state;
67 struct thermal_genl_cpu_caps *cpu_capabilities;75 struct thermal_genl_cpu_caps *cpu_capabilities;
@@ -234,6 +242,34 @@ out_cancel_nest: · 166 unmodified lines
234 return -EMSGSIZE;242 return -EMSGSIZE;
235}243}
236 244
245static 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
255static 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
263static 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
237int thermal_genl_event_tz_delete(struct param *p)273int thermal_genl_event_tz_delete(struct param *p)
238 __attribute__((alias("thermal_genl_event_tz")));274 __attribute__((alias("thermal_genl_event_tz")));
239 275
@@ -246,6 +282,12 @@ int thermal_genl_event_tz_disable(struct param *p) · 6 unmodified lines
246int thermal_genl_event_tz_trip_down(struct param *p)282int thermal_genl_event_tz_trip_down(struct param *p)
247 __attribute__((alias("thermal_genl_event_tz_trip_up")));283 __attribute__((alias("thermal_genl_event_tz_trip_up")));
248 284
285int thermal_genl_event_threshold_delete(struct param *p)
286 __attribute__((alias("thermal_genl_event_threshold_add")));
287
288int thermal_genl_event_threshold_down(struct param *p)
289 __attribute__((alias("thermal_genl_event_threshold_up")));
290
249static cb_t event_cb[] = {291static cb_t event_cb[] = {
250 [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,292 [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,
251 [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,293 [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,
@@ -259,6 +301,11 @@ static cb_t event_cb[] = { · 7 unmodified lines
259 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,301 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
260 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,302 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,
261 [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,303 [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,
262};309};
263 310
264/*311/*
@@ -401,6 +448,43 @@ int thermal_genl_cpu_capability_event(int count, · 136 unmodified lines
401}448}
402EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);449EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
403 450
451int 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
459int 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
467int 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
474int 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
481int 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
404/*************************** Command encoding ********************************/488/*************************** Command encoding ********************************/
405 489
406static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,490static 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
459 if (!start_trip)543 if (!start_trip)
460 return -EMSGSIZE;544 return -EMSGSIZE;
461 545
462 mutex_lock(&tz->lock);546 guard(thermal_zone)(tz);
463 547
464 for_each_trip_desc(tz, td) {548 for_each_trip_desc(tz, td) {
465 const struct thermal_trip *trip = &td->trip;549 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
469 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||553 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||
470 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) ||554 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) ||
471 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis))555 nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis))
472 goto out_cancel_nest;556 return -EMSGSIZE;
473 }557 }
474 558
475 mutex_unlock(&tz->lock);
476
477 nla_nest_end(msg, start_trip);559 nla_nest_end(msg, start_trip);
478 560
479 return 0;561 return 0;
480
481out_cancel_nest:
482 mutex_unlock(&tz->lock);
483
484 return -EMSGSIZE;
485}562}
486 563
487static int thermal_genl_cmd_tz_get_temp(struct param *p)564static 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
512static int thermal_genl_cmd_tz_get_gov(struct param *p)589static int thermal_genl_cmd_tz_get_gov(struct param *p)
513{590{
514 struct sk_buff *msg = p->msg;591 struct sk_buff *msg = p->msg;
515 int id, ret = 0;592 int id;
516 593
517 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])594 if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
518 return -EINVAL;595 return -EINVAL;
@@ -523,16 +600,14 @@ static int thermal_genl_cmd_tz_get_gov(struct param *p) · 4 unmodified lines
523 if (!tz)600 if (!tz)
524 return -EINVAL;601 return -EINVAL;
525 602
526 mutex_lock(&tz->lock);603 guard(thermal_zone)(tz);
527 604
528 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||605 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
529 nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,606 nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
530 tz->governor->name))607 tz->governor->name))
531 ret = -EMSGSIZE;608 return -EMSGSIZE;
532
533 mutex_unlock(&tz->lock);
534 609
535 return ret;610 return 0;
536}611}
537 612
538static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,613static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
@@ -572,12 +647,128 @@ out_cancel_nest: · 33 unmodified lines
572 return ret;647 return ret;
573}648}
574 649
650static 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
661static 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
689static 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
714static 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
739static 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
575static cb_t cmd_cb[] = {762static cb_t cmd_cb[] = {
576 [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id,763 [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,764 [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,765 [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,766 [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov,
580 [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get,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,
581};772};
582 773
583static int thermal_genl_cmd_dumpit(struct sk_buff *skb,774static 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
688 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,879 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
689 .dumpit = thermal_genl_cmd_dumpit,880 .dumpit = thermal_genl_cmd_dumpit,
690 },881 },
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 },
691};902};
692 903
693static struct genl_family thermal_genl_family __ro_after_init = {904static 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
700 .unbind = thermal_genl_unbind,911 .unbind = thermal_genl_unbind,
701 .small_ops = thermal_genl_ops,912 .small_ops = thermal_genl_ops,
702 .n_small_ops = ARRAY_SIZE(thermal_genl_ops),913 .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,
704 .mcgrps = thermal_genl_mcgrps,915 .mcgrps = thermal_genl_mcgrps,
705 .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),916 .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
706};917};
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
53int thermal_genl_sampling_temp(int id, int temp);53int thermal_genl_sampling_temp(int id, int temp);
54int thermal_genl_cpu_capability_event(int count,54int thermal_genl_cpu_capability_event(int count,
55 struct thermal_genl_cpu_caps *caps);55 struct thermal_genl_cpu_caps *caps);
56int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
57 int temperature, int direction);
58int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
59 int temperature, int direction);
60int thermal_notify_threshold_flush(const struct thermal_zone_device *tz);
61int thermal_notify_threshold_down(const struct thermal_zone_device *tz);
62int thermal_notify_threshold_up(const struct thermal_zone_device *tz);
56#else63#else
57static inline int thermal_netlink_init(void)64static inline int thermal_netlink_init(void)
58{65{
@@ -139,6 +146,33 @@ static inline int thermal_genl_cpu_capability_event(int count, struct thermal_ge · 80 unmodified lines
139 return 0;146 return 0;
140}147}
141 148
149static inline int thermal_notify_threshold_add(const struct thermal_zone_device *tz,
150 int temperature, int direction)
151{
152 return 0;
153}
154
155static inline int thermal_notify_threshold_delete(const struct thermal_zone_device *tz,
156 int temperature, int direction)
157{
158 return 0;
159}
160
161static inline int thermal_notify_threshold_flush(const struct thermal_zone_device *tz)
162{
163 return 0;
164}
165
166static inline int thermal_notify_threshold_down(const struct thermal_zone_device *tz)
167{
168 return 0;
169}
170
171static inline int thermal_notify_threshold_up(const struct thermal_zone_device *tz)
172{
173 return 0;
174}
175
142static inline void __init thermal_netlink_exit(void) {}176static inline void __init thermal_netlink_exit(void) {}
143 177
144#endif /* CONFIG_THERMAL_NETLINK */178#endif /* CONFIG_THERMAL_NETLINK */
drivers/thermal/thermal_sysfs.c+53−79
@@ -50,13 +50,13 @@ static ssize_t · 49 unmodified lines
50mode_show(struct device *dev, struct device_attribute *attr, char *buf)50mode_show(struct device *dev, struct device_attribute *attr, char *buf)
51{51{
52 struct thermal_zone_device *tz = to_thermal_zone(dev);52 struct thermal_zone_device *tz = to_thermal_zone(dev);
53 int enabled;
54 53
55 mutex_lock(&tz->lock);54 guard(thermal_zone)(tz);
56 enabled = tz->mode == THERMAL_DEVICE_ENABLED;
57 mutex_unlock(&tz->lock);
58 55
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");
60}60}
61 61
62static ssize_t62static ssize_t
@@ -103,38 +103,34 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, · 40 unmodified lines
103{103{
104 struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);104 struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);
105 struct thermal_zone_device *tz = to_thermal_zone(dev);105 struct thermal_zone_device *tz = to_thermal_zone(dev);
106 int ret, temp;106 int temp;
107 107
108 ret = kstrtoint(buf, 10, &temp);108 if (kstrtoint(buf, 10, &temp))
109 if (ret)
110 return -EINVAL;109 return -EINVAL;
111 110
112 mutex_lock(&tz->lock);111 guard(thermal_zone)(tz);
113 112
114 if (temp == trip->temperature)113 if (temp == trip->temperature)
115 goto unlock;114 return count;
116 115
117 /* Arrange the condition to avoid integer overflows. */116 /* Arrange the condition to avoid integer overflows. */
118 if (temp != THERMAL_TEMP_INVALID &&117 if (temp != THERMAL_TEMP_INVALID &&
119 temp <= trip->hysteresis + THERMAL_TEMP_INVALID) {118 temp <= trip->hysteresis + THERMAL_TEMP_INVALID)
120 ret = -EINVAL;119 return -EINVAL;
121 goto unlock;
122 }
123 120
124 if (tz->ops.set_trip_temp) {121 if (tz->ops.set_trip_temp) {
122 int ret;
123
125 ret = tz->ops.set_trip_temp(tz, trip, temp);124 ret = tz->ops.set_trip_temp(tz, trip, temp);
126 if (ret)125 if (ret)
127 goto unlock;126 return ret;
128 }127 }
129 128
130 thermal_zone_set_trip_temp(tz, trip, temp);129 thermal_zone_set_trip_temp(tz, trip, temp);
131 130
132 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);131 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
133 132
134unlock:133 return count;
135 mutex_unlock(&tz->lock);
136
137 return ret ? ret : count;
138}134}
139 135
140static ssize_t136static ssize_t
@@ -152,16 +148,15 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, · 11 unmodified lines
152{148{
153 struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);149 struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);
154 struct thermal_zone_device *tz = to_thermal_zone(dev);150 struct thermal_zone_device *tz = to_thermal_zone(dev);
155 int ret, hyst;151 int hyst;
156 152
157 ret = kstrtoint(buf, 10, &hyst);153 if (kstrtoint(buf, 10, &hyst) || hyst < 0)
158 if (ret || hyst < 0)
159 return -EINVAL;154 return -EINVAL;
160 155
161 mutex_lock(&tz->lock);156 guard(thermal_zone)(tz);
162 157
163 if (hyst == trip->hysteresis)158 if (hyst == trip->hysteresis)
164 goto unlock;159 return count;
165 160
166 /*161 /*
167 * Allow the hysteresis to be updated when the temperature is invalid162 * 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
171 */166 */
172 if (trip->temperature == THERMAL_TEMP_INVALID) {167 if (trip->temperature == THERMAL_TEMP_INVALID) {
173 WRITE_ONCE(trip->hysteresis, hyst);168 WRITE_ONCE(trip->hysteresis, hyst);
174 goto unlock;169 return count;
175 }170 }
176 171
177 if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) {172 if (trip->temperature - hyst <= THERMAL_TEMP_INVALID)
178 ret = -EINVAL;173 return -EINVAL;
179 goto unlock;
180 }
181 174
182 thermal_zone_set_trip_hyst(tz, trip, hyst);175 thermal_zone_set_trip_hyst(tz, trip, hyst);
183 176
184 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);177 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
185 178
186unlock:179 return count;
187 mutex_unlock(&tz->lock);
188
189 return ret ? ret : count;
190}180}
191 181
192static ssize_t182static ssize_t
@@ -236,25 +226,26 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, · 43 unmodified lines
236 const char *buf, size_t count)226 const char *buf, size_t count)
237{227{
238 struct thermal_zone_device *tz = to_thermal_zone(dev);228 struct thermal_zone_device *tz = to_thermal_zone(dev);
239 int ret = 0;
240 int temperature;229 int temperature;
241 230
242 if (kstrtoint(buf, 10, &temperature))231 if (kstrtoint(buf, 10, &temperature))
243 return -EINVAL;232 return -EINVAL;
244 233
245 mutex_lock(&tz->lock);234 guard(thermal_zone)(tz);
246 235
247 if (!tz->ops.set_emul_temp)236 if (tz->ops.set_emul_temp) {
248 tz->emul_temperature = temperature;237 int ret;
249 else
250 ret = tz->ops.set_emul_temp(tz, temperature);
251 238
252 if (!ret)239 ret = tz->ops.set_emul_temp(tz, temperature);
253 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);240 if (ret)
241 return ret;
242 } else {
243 tz->emul_temperature = temperature;
244 }
254 245
255 mutex_unlock(&tz->lock);246 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
256 247
257 return ret ? ret : count;248 return count;
258}249}
259static DEVICE_ATTR_WO(emul_temp);250static DEVICE_ATTR_WO(emul_temp);
260#endif251#endif
@@ -553,14 +544,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, · 292 unmodified lines
553 if (state > cdev->max_state)544 if (state > cdev->max_state)
554 return -EINVAL;545 return -EINVAL;
555 546
556 mutex_lock(&cdev->lock);547 guard(cooling_dev)(cdev);
557 548
558 result = cdev->ops->set_cur_state(cdev, state);549 result = cdev->ops->set_cur_state(cdev, state);
559 if (!result)550 if (result)
560 thermal_cooling_device_stats_update(cdev, state);551 return result;
561 552
562 mutex_unlock(&cdev->lock);553 thermal_cooling_device_stats_update(cdev, state);
563 return result ? result : count;554
555 return count;
564}556}
565 557
566static struct device_attribute558static struct device_attribute
@@ -634,21 +626,18 @@ static ssize_t total_trans_show(struct device *dev, · 67 unmodified lines
634{626{
635 struct thermal_cooling_device *cdev = to_cooling_device(dev);627 struct thermal_cooling_device *cdev = to_cooling_device(dev);
636 struct cooling_dev_stats *stats;628 struct cooling_dev_stats *stats;
637 int ret = 0;629 int ret;
638 630
639 mutex_lock(&cdev->lock);631 guard(cooling_dev)(cdev);
640 632
641 stats = cdev->stats;633 stats = cdev->stats;
642 if (!stats)634 if (!stats)
643 goto unlock;635 return 0;
644 636
645 spin_lock(&stats->lock);637 spin_lock(&stats->lock);
646 ret = sprintf(buf, "%u\n", stats->total_trans);638 ret = sprintf(buf, "%u\n", stats->total_trans);
647 spin_unlock(&stats->lock);639 spin_unlock(&stats->lock);
648 640
649unlock:
650 mutex_unlock(&cdev->lock);
651
652 return ret;641 return ret;
653}642}
654 643
@@ -661,11 +650,11 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 6 unmodified lines
661 ssize_t len = 0;650 ssize_t len = 0;
662 int i;651 int i;
663 652
664 mutex_lock(&cdev->lock);653 guard(cooling_dev)(cdev);
665 654
666 stats = cdev->stats;655 stats = cdev->stats;
667 if (!stats)656 if (!stats)
668 goto unlock;657 return 0;
669 658
670 spin_lock(&stats->lock);659 spin_lock(&stats->lock);
671 660
@@ -677,9 +666,6 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 5 unmodified lines
677 }666 }
678 spin_unlock(&stats->lock);667 spin_unlock(&stats->lock);
679 668
680unlock:
681 mutex_unlock(&cdev->lock);
682
683 return len;669 return len;
684}670}
685 671
@@ -691,11 +677,11 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 5 unmodified lines
691 struct cooling_dev_stats *stats;677 struct cooling_dev_stats *stats;
692 int i, states;678 int i, states;
693 679
694 mutex_lock(&cdev->lock);680 guard(cooling_dev)(cdev);
695 681
696 stats = cdev->stats;682 stats = cdev->stats;
697 if (!stats)683 if (!stats)
698 goto unlock;684 return count;
699 685
700 states = cdev->max_state + 1;686 states = cdev->max_state + 1;
701 687
@@ -711,9 +697,6 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 9 unmodified lines
711 697
712 spin_unlock(&stats->lock);698 spin_unlock(&stats->lock);
713 699
714unlock:
715 mutex_unlock(&cdev->lock);
716
717 return count;700 return count;
718}701}
719 702
@@ -725,13 +708,11 @@ static ssize_t trans_table_show(struct device *dev, · 5 unmodified lines
725 ssize_t len = 0;708 ssize_t len = 0;
726 int i, j;709 int i, j;
727 710
728 mutex_lock(&cdev->lock);711 guard(cooling_dev)(cdev);
729 712
730 stats = cdev->stats;713 stats = cdev->stats;
731 if (!stats) {714 if (!stats)
732 len = -ENODATA;715 return -ENODATA;
733 goto unlock;
734 }
735 716
736 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");717 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
737 len += snprintf(buf + len, PAGE_SIZE - len, " : ");718 len += snprintf(buf + len, PAGE_SIZE - len, " : ");
@@ -740,10 +721,8 @@ static ssize_t trans_table_show(struct device *dev, · 2 unmodified lines
740 break;721 break;
741 len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);722 len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i);
742 }723 }
743 if (len >= PAGE_SIZE) {724 if (len >= PAGE_SIZE)
744 len = PAGE_SIZE;725 return PAGE_SIZE;
745 goto unlock;
746 }
747 726
748 len += snprintf(buf + len, PAGE_SIZE - len, "\n");727 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
749 728
@@ -769,9 +748,6 @@ static ssize_t trans_table_show(struct device *dev, · 19 unmodified lines
769 len = -EFBIG;748 len = -EFBIG;
770 }749 }
771 750
772unlock:
773 mutex_unlock(&cdev->lock);
774
775 return len;751 return len;
776}752}
777 753
@@ -894,13 +870,11 @@ ssize_t weight_store(struct device *dev, struct device_attribute *attr, · 116 unmodified lines
894 instance = container_of(attr, struct thermal_instance, weight_attr);870 instance = container_of(attr, struct thermal_instance, weight_attr);
895 871
896 /* Don't race with governors using the 'weight' value */872 /* Don't race with governors using the 'weight' value */
897 mutex_lock(&tz->lock);873 guard(thermal_zone)(tz);
898 874
899 instance->weight = weight;875 instance->weight = weight;
900 876
901 thermal_governor_update_tz(tz, THERMAL_INSTANCE_WEIGHT_CHANGED);877 thermal_governor_update_tz(tz, THERMAL_INSTANCE_WEIGHT_CHANGED);
902 878
903 mutex_unlock(&tz->lock);
904
905 return count;879 return count;
906}880}
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
16int thermal_thresholds_init(struct thermal_zone_device *tz)
17{
18 INIT_LIST_HEAD(&tz->user_thresholds);
19
20 return 0;
21}
22
23static 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
34void 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
45void thermal_thresholds_exit(struct thermal_zone_device *tz)
46{
47 __thermal_thresholds_flush(tz);
48}
49
50static 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
60static 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
72static 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
98static 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
112static 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
126void 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
164int 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
198int 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
224int 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
5struct user_threshold {
6 struct list_head list_node;
7 int temperature;
8 int direction;
9};
10
11int thermal_thresholds_init(struct thermal_zone_device *tz);
12void thermal_thresholds_exit(struct thermal_zone_device *tz);
13void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high);
14void thermal_thresholds_flush(struct thermal_zone_device *tz);
15int thermal_thresholds_add(struct thermal_zone_device *tz, int temperature, int direction);
16int thermal_thresholds_delete(struct thermal_zone_device *tz, int temperature, int direction);
17int 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
45 int (*cb)(struct thermal_trip *, void *),45 int (*cb)(struct thermal_trip *, void *),
46 void *data)46 void *data)
47{47{
48 int ret;48 guard(thermal_zone)(tz);
49
50 mutex_lock(&tz->lock);
51 ret = for_each_thermal_trip(tz, cb, data);
52 mutex_unlock(&tz->lock);
53 49
54 return ret;50 return for_each_thermal_trip(tz, cb, data);
55}51}
56EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);52EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);
57 53
@@ -92,43 +88,3 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz, · 34 unmodified lines
92 */88 */
93 return trip_to_trip_desc(trip) - tz->trips;89 return trip_to_trip_desc(trip) - tz->trips;
94}90}
95
96void 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
103void 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}
134EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
include/linux/thermal.h+6−0
@@ -56,6 +56,9 @@ enum thermal_notify_event { · 55 unmodified lines
56 THERMAL_TZ_UNBIND_CDEV, /* Cooling dev is unbind from the thermal zone */56 THERMAL_TZ_UNBIND_CDEV, /* Cooling dev is unbind from the thermal zone */
57 THERMAL_INSTANCE_WEIGHT_CHANGED, /* Thermal instance weight changed */57 THERMAL_INSTANCE_WEIGHT_CHANGED, /* Thermal instance weight changed */
58 THERMAL_TZ_RESUME, /* Thermal zone is resuming after system sleep */58 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 */
59};62};
60 63
61/**64/**
@@ -137,6 +140,9 @@ struct thermal_cooling_device { · 75 unmodified lines
137#endif140#endif
138};141};
139 142
143DEFINE_GUARD(cooling_dev, struct thermal_cooling_device *, mutex_lock(&_T->lock),
144 mutex_unlock(&_T->lock))
145
140/* Structure to define Thermal Zone parameters */146/* Structure to define Thermal Zone parameters */
141struct thermal_zone_params {147struct thermal_zone_params {
142 const char *governor_name;148 const char *governor_name;
include/uapi/linux/thermal.h+22−7
@@ -3,6 +3,8 @@ · 2 unmodified lines
3#define _UAPI_LINUX_THERMAL_H3#define _UAPI_LINUX_THERMAL_H
4 4
5#define THERMAL_NAME_LENGTH 205#define THERMAL_NAME_LENGTH 20
6#define THERMAL_THRESHOLD_WAY_UP BIT(0)
7#define THERMAL_THRESHOLD_WAY_DOWN BIT(1)
6 8
7enum thermal_device_mode {9enum thermal_device_mode {
8 THERMAL_DEVICE_DISABLED = 0,10 THERMAL_DEVICE_DISABLED = 0,
@@ -18,7 +20,7 @@ enum thermal_trip_type { · 9 unmodified lines
18 20
19/* Adding event notification support elements */21/* Adding event notification support elements */
20#define THERMAL_GENL_FAMILY_NAME "thermal"22#define THERMAL_GENL_FAMILY_NAME "thermal"
21#define THERMAL_GENL_VERSION 0x0123#define THERMAL_GENL_VERSION 0x02
22#define THERMAL_GENL_SAMPLING_GROUP_NAME "sampling"24#define THERMAL_GENL_SAMPLING_GROUP_NAME "sampling"
23#define THERMAL_GENL_EVENT_GROUP_NAME "event"25#define THERMAL_GENL_EVENT_GROUP_NAME "event"
24 26
@@ -28,6 +30,7 @@ enum thermal_genl_attr { · 3 unmodified lines
28 THERMAL_GENL_ATTR_TZ,30 THERMAL_GENL_ATTR_TZ,
29 THERMAL_GENL_ATTR_TZ_ID,31 THERMAL_GENL_ATTR_TZ_ID,
30 THERMAL_GENL_ATTR_TZ_TEMP,32 THERMAL_GENL_ATTR_TZ_TEMP,
33 THERMAL_GENL_ATTR_TZ_PREV_TEMP,
31 THERMAL_GENL_ATTR_TZ_TRIP,34 THERMAL_GENL_ATTR_TZ_TRIP,
32 THERMAL_GENL_ATTR_TZ_TRIP_ID,35 THERMAL_GENL_ATTR_TZ_TRIP_ID,
33 THERMAL_GENL_ATTR_TZ_TRIP_TYPE,36 THERMAL_GENL_ATTR_TZ_TRIP_TYPE,
@@ -48,6 +51,9 @@ enum thermal_genl_attr { · 14 unmodified lines
48 THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,51 THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
49 THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,52 THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
50 THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,53 THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
54 THERMAL_GENL_ATTR_THRESHOLD,
55 THERMAL_GENL_ATTR_THRESHOLD_TEMP,
56 THERMAL_GENL_ATTR_THRESHOLD_DIRECTION,
51 __THERMAL_GENL_ATTR_MAX,57 __THERMAL_GENL_ATTR_MAX,
52};58};
53#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)59#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
@@ -75,6 +81,11 @@ enum thermal_genl_event { · 21 unmodified lines
75 THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */81 THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */
76 THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */82 THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */
77 THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, /* CPU capability changed */83 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 */
78 __THERMAL_GENL_EVENT_MAX,89 __THERMAL_GENL_EVENT_MAX,
79};90};
80#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)91#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)
@@ -82,12 +93,16 @@ enum thermal_genl_event { · 1 unmodified line
82/* Commands supported by the thermal_genl_family */93/* Commands supported by the thermal_genl_family */
83enum thermal_genl_cmd {94enum thermal_genl_cmd {
84 THERMAL_GENL_CMD_UNSPEC,95 THERMAL_GENL_CMD_UNSPEC,
85 THERMAL_GENL_CMD_TZ_GET_ID, /* List of thermal zones id */96 THERMAL_GENL_CMD_TZ_GET_ID, /* List of thermal zones id */
86 THERMAL_GENL_CMD_TZ_GET_TRIP, /* List of thermal trips */97 THERMAL_GENL_CMD_TZ_GET_TRIP, /* List of thermal trips */
87 THERMAL_GENL_CMD_TZ_GET_TEMP, /* Get the thermal zone temperature */98 THERMAL_GENL_CMD_TZ_GET_TEMP, /* Get the thermal zone temperature */
88 THERMAL_GENL_CMD_TZ_GET_GOV, /* Get the thermal zone governor */99 THERMAL_GENL_CMD_TZ_GET_GOV, /* Get the thermal zone governor */
89 THERMAL_GENL_CMD_TZ_GET_MODE, /* Get the thermal zone mode */100 THERMAL_GENL_CMD_TZ_GET_MODE, /* Get the thermal zone mode */
90 THERMAL_GENL_CMD_CDEV_GET, /* List of cdev id */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 */
91 __THERMAL_GENL_CMD_MAX,106 __THERMAL_GENL_CMD_MAX,
92};107};
93#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)108#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
tools/lib/thermal/commands.c+175−13
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#include <stdio.h>5#include <stdio.h>
6#include <stdlib.h>6#include <stdlib.h>
7#include <unistd.h>7#include <unistd.h>
8#include <limits.h>
8 9
9#include <thermal.h>10#include <thermal.h>
10#include "thermal_nl.h"11#include "thermal_nl.h"
@@ -33,6 +34,11 @@ static struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { · 22 unmodified lines
33 [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 },34 [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 },
34 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },35 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },
35 [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING },36 [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 },
36};42};
37 43
38static int parse_tz_get(struct genl_info *info, struct thermal_zone **tz)44static 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
182 return THERMAL_SUCCESS;188 return THERMAL_SUCCESS;
183}189}
184 190
191static 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
185static int handle_netlink(struct nl_cache_ops *unused,233static int handle_netlink(struct nl_cache_ops *unused,
186 struct genl_cmd *cmd,234 struct genl_cmd *cmd,
187 struct genl_info *info, void *arg)235 struct genl_info *info, void *arg)
@@ -210,6 +258,10 @@ static int handle_netlink(struct nl_cache_ops *unused, · 22 unmodified lines
210 ret = parse_tz_get_gov(info, arg);258 ret = parse_tz_get_gov(info, arg);
211 break;259 break;
212 260
261 case THERMAL_GENL_CMD_THRESHOLD_GET:
262 ret = parse_threshold_get(info, arg);
263 break;
264
213 default:265 default:
214 return THERMAL_ERROR;266 return THERMAL_ERROR;
215 }267 }
@@ -253,6 +305,34 @@ static struct genl_cmd thermal_cmds[] = { · 37 unmodified lines
253 .c_maxattr = THERMAL_GENL_ATTR_MAX,305 .c_maxattr = THERMAL_GENL_ATTR_MAX,
254 .c_attr_policy = thermal_genl_policy,306 .c_attr_policy = thermal_genl_policy,
255 },307 },
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 },
256};336};
257 337
258static struct genl_ops thermal_cmd_ops = {338static struct genl_ops thermal_cmd_ops = {
@@ -261,9 +341,41 @@ static struct genl_ops thermal_cmd_ops = { · 2 unmodified lines
261 .o_ncmds = ARRAY_SIZE(thermal_cmds),341 .o_ncmds = ARRAY_SIZE(thermal_cmds),
262};342};
263 343
264static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int cmd,344struct cmd_param {
265 int flags, void *arg)345 int tz_id;
346 int temp;
347 int direction;
348};
349
350typedef int (*cmd_cb_t)(struct nl_msg *, struct cmd_param *);
351
352static int thermal_genl_tz_id_encode(struct nl_msg *msg, struct cmd_param *p)
266{353{
354 if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
355 return -1;
356
357 return 0;
358}
359
360static 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
374static 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;
267 struct nl_msg *msg;379 struct nl_msg *msg;
268 void *hdr;380 void *hdr;
269 381
@@ -274,45 +386,95 @@ static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int · 4 unmodified lines
274 hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id,386 hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id,
275 0, flags, cmd, THERMAL_GENL_VERSION);387 0, flags, cmd, THERMAL_GENL_VERSION);
276 if (!hdr)388 if (!hdr)
277 return THERMAL_ERROR;389 goto out;
278 390
279 if (id >= 0 && nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id))391 if (cmd_cb && cmd_cb(msg, param))
280 return THERMAL_ERROR;392 goto out;
281 393
282 if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg))394 if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg))
283 return THERMAL_ERROR;395 goto out;
284 396
397 ret = THERMAL_SUCCESS;
398out:
285 nlmsg_free(msg);399 nlmsg_free(msg);
286 400
287 return THERMAL_SUCCESS;401 return ret;
288}402}
289 403
290thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz)404thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz)
291{405{
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,
293 NLM_F_DUMP | NLM_F_ACK, tz);407 NLM_F_DUMP | NLM_F_ACK, tz);
294}408}
295 409
296thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc)410thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc)
297{411{
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,
299 NLM_F_DUMP | NLM_F_ACK, tc);413 NLM_F_DUMP | NLM_F_ACK, tc);
300}414}
301 415
302thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz)416thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz)
303{417{
304 return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TRIP,418 struct cmd_param p = { .tz_id = tz->id };
305 0, tz);419
420 return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p,
421 THERMAL_GENL_CMD_TZ_GET_TRIP, 0, tz);
306}422}
307 423
308thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz)424thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz)
309{425{
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);
311}430}
312 431
313thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz)432thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz)
314{433{
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
440thermal_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
449thermal_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
460thermal_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
471thermal_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);
316}478}
317 479
318thermal_error_t thermal_cmd_exit(struct thermal_handler *th)480thermal_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
94 case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:94 case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:
95 return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),95 return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]),
96 nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg);96 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
97 default:121 default:
98 return -1;122 return -1;
99 }123 }
@@ -101,19 +125,24 @@ static int handle_thermal_event(struct nl_msg *n, void *arg) · 1 unmodified line
101 125
102static void thermal_events_ops_init(struct thermal_events_ops *ops)126static void thermal_events_ops_init(struct thermal_events_ops *ops)
103{127{
104 enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create;128 enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create;
105 enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete;129 enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete;
106 enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable;130 enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable;
107 enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable;131 enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable;
108 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high;132 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high;
109 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low;133 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low;
110 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change;134 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change;
111 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add;135 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add;
112 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete;136 enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete;
113 enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add;137 enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add;
114 enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete;138 enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete;
115 enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;139 enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update;
116 enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change;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;
117}146}
118 147
119thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg)148thermal_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
4#define __LIBTHERMAL_H4#define __LIBTHERMAL_H
5 5
6#include <linux/thermal.h>6#include <linux/thermal.h>
7#include <sys/types.h>
7 8
8#ifndef LIBTHERMAL_API9#ifndef LIBTHERMAL_API
9#define LIBTHERMAL_API __attribute__((visibility("default")))10#define LIBTHERMAL_API __attribute__((visibility("default")))
10#endif11#endif
11 12
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
12#ifdef __cplusplus21#ifdef __cplusplus
13extern "C" {22extern "C" {
14#endif23#endif
@@ -31,6 +40,11 @@ struct thermal_events_ops { · 16 unmodified lines
31 int (*cdev_delete)(int cdev_id, void *arg);40 int (*cdev_delete)(int cdev_id, void *arg);
32 int (*cdev_update)(int cdev_id, int cur_state, void *arg);41 int (*cdev_update)(int cdev_id, int cur_state, void *arg);
33 int (*gov_change)(int tz_id, const char *gov_name, void *arg);42 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);
34};48};
35 49
36struct thermal_ops {50struct thermal_ops {
@@ -45,12 +59,18 @@ struct thermal_trip { · 8 unmodified lines
45 int hyst;59 int hyst;
46};60};
47 61
62struct thermal_threshold {
63 int temperature;
64 int direction;
65};
66
48struct thermal_zone {67struct thermal_zone {
49 int id;68 int id;
50 int temp;69 int temp;
51 char name[THERMAL_NAME_LENGTH];70 char name[THERMAL_NAME_LENGTH];
52 char governor[THERMAL_NAME_LENGTH];71 char governor[THERMAL_NAME_LENGTH];
53 struct thermal_trip *trip;72 struct thermal_trip *trip;
73 struct thermal_threshold *thresholds;
54};74};
55 75
56struct thermal_cdev {76struct thermal_cdev {
@@ -74,12 +94,16 @@ typedef int (*cb_tt_t)(struct thermal_trip *, void *); · 17 unmodified lines
74 94
75typedef int (*cb_tc_t)(struct thermal_cdev *, void *);95typedef int (*cb_tc_t)(struct thermal_cdev *, void *);
76 96
97typedef int (*cb_th_t)(struct thermal_threshold *, void *);
98
77LIBTHERMAL_API int for_each_thermal_zone(struct thermal_zone *tz, cb_tz_t cb, void *arg);99LIBTHERMAL_API int for_each_thermal_zone(struct thermal_zone *tz, cb_tz_t cb, void *arg);
78 100
79LIBTHERMAL_API int for_each_thermal_trip(struct thermal_trip *tt, cb_tt_t cb, void *arg);101LIBTHERMAL_API int for_each_thermal_trip(struct thermal_trip *tt, cb_tt_t cb, void *arg);
80 102
81LIBTHERMAL_API int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg);103LIBTHERMAL_API int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg);
82 104
105LIBTHERMAL_API int for_each_thermal_threshold(struct thermal_threshold *th, cb_th_t cb, void *arg);
106
83LIBTHERMAL_API struct thermal_zone *thermal_zone_find_by_name(struct thermal_zone *tz,107LIBTHERMAL_API struct thermal_zone *thermal_zone_find_by_name(struct thermal_zone *tz,
84 const char *name);108 const char *name);
85 109
@@ -124,6 +148,22 @@ LIBTHERMAL_API thermal_error_t thermal_cmd_get_governor(struct thermal_handler * · 38 unmodified lines
124LIBTHERMAL_API thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th,148LIBTHERMAL_API thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th,
125 struct thermal_zone *tz);149 struct thermal_zone *tz);
126 150
151LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_get(struct thermal_handler *th,
152 struct thermal_zone *tz);
153
154LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_add(struct thermal_handler *th,
155 struct thermal_zone *tz,
156 int temperature,
157 int direction);
158
159LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_delete(struct thermal_handler *th,
160 struct thermal_zone *tz,
161 int temperature,
162 int direction);
163
164LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_flush(struct thermal_handler *th,
165 struct thermal_zone *tz);
166
127/*167/*
128 * Netlink thermal samples168 * Netlink thermal samples
129 */169 */
tools/lib/thermal/libthermal.map+5−0
@@ -4,6 +4,7 @@ LIBTHERMAL_0.0.1 { · 3 unmodified lines
4 for_each_thermal_zone;4 for_each_thermal_zone;
5 for_each_thermal_trip;5 for_each_thermal_trip;
6 for_each_thermal_cdev;6 for_each_thermal_cdev;
7 for_each_thermal_threshold;
7 thermal_zone_find_by_name;8 thermal_zone_find_by_name;
8 thermal_zone_find_by_id;9 thermal_zone_find_by_id;
9 thermal_zone_discover;10 thermal_zone_discover;
@@ -17,6 +18,10 @@ LIBTHERMAL_0.0.1 { · 7 unmodified lines
17 thermal_cmd_get_trip;18 thermal_cmd_get_trip;
18 thermal_cmd_get_governor;19 thermal_cmd_get_governor;
19 thermal_cmd_get_temp;20 thermal_cmd_get_temp;
21 thermal_cmd_threshold_get;
22 thermal_cmd_threshold_add;
23 thermal_cmd_threshold_delete;
24 thermal_cmd_threshold_flush;
20 thermal_sampling_init;25 thermal_sampling_init;
21 thermal_sampling_handle;26 thermal_sampling_handle;
22 thermal_sampling_fd;27 thermal_sampling_fd;
tools/lib/thermal/thermal.c+17−0
@@ -1,10 +1,24 @@
1// SPDX-License-Identifier: LGPL-2.1+1// SPDX-License-Identifier: LGPL-2.1+
2// Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>2// Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
3#include <stdio.h>3#include <stdio.h>
4#include <limits.h>
4#include <thermal.h>5#include <thermal.h>
5 6
6#include "thermal_nl.h"7#include "thermal_nl.h"
7 8
9int 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
8int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg)22int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg)
9{23{
10 int i, ret = 0;24 int i, ret = 0;
@@ -80,6 +94,9 @@ static int __thermal_zone_discover(struct thermal_zone *tz, void *th) · 69 unmodified lines
80 if (thermal_cmd_get_trip(th, tz) < 0)94 if (thermal_cmd_get_trip(th, tz) < 0)
81 return -1;95 return -1;
82 96
97 if (thermal_cmd_threshold_get(th, tz))
98 return -1;
99
83 if (thermal_cmd_get_governor(th, tz))100 if (thermal_cmd_get_governor(th, tz))
84 return -1;101 return -1;
85 102
tools/thermal/lib/Makefile+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4LIBTHERMAL_TOOLS_VERSION = 04LIBTHERMAL_TOOLS_VERSION = 0
5LIBTHERMAL_TOOLS_PATCHLEVEL = 05LIBTHERMAL_TOOLS_PATCHLEVEL = 0
6LIBTHERMAL_TOOLS_EXTRAVERSION = 16LIBTHERMAL_TOOLS_EXTRAVERSION = 2
7 7
8MAKEFLAGS += --no-print-directory8MAKEFLAGS += --no-print-directory
9 9
tools/thermal/thermal-engine/thermal-engine.c+92−13
@@ -38,6 +38,14 @@ struct thermal_data { · 37 unmodified lines
38 struct thermal_handler *th;38 struct thermal_handler *th;
39};39};
40 40
41static 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
41static int show_trip(struct thermal_trip *tt, __maybe_unused void *arg)49static int show_trip(struct thermal_trip *tt, __maybe_unused void *arg)
42{50{
43 INFO("trip id=%d, type=%d, temp=%d, hyst=%d\n",51 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
70 78
71 for_each_thermal_trip(tz->trip, show_trip, NULL);79 for_each_thermal_trip(tz->trip, show_trip, NULL);
72 80
81 for_each_thermal_threshold(tz->thresholds, show_threshold, NULL);
82
73 show_temp(tz, arg);83 show_temp(tz, arg);
74 84
75 show_governor(tz, arg);85 show_governor(tz, arg);
@@ -77,6 +87,30 @@ static int show_tz(struct thermal_zone *tz, __maybe_unused void *arg) · 1 unmodified line
77 return 0;87 return 0;
78}88}
79 89
90static 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
80static int tz_create(const char *name, int tz_id, __maybe_unused void *arg)114static int tz_create(const char *name, int tz_id, __maybe_unused void *arg)
81{115{
82 INFO("Thermal zone '%s'/%d created\n", name, tz_id);116 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
197 return 0;231 return 0;
198}232}
199 233
234static 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
241static 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
248static 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
255static 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
263static 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
200static struct thermal_ops ops = {271static struct thermal_ops ops = {
201 .events.tz_create = tz_create,272 .events.tz_create = tz_create,
202 .events.tz_delete = tz_delete,273 .events.tz_delete = tz_delete,
203 .events.tz_disable = tz_disable,274 .events.tz_disable = tz_disable,
204 .events.tz_enable = tz_enable,275 .events.tz_enable = tz_enable,
205 .events.trip_high = trip_high,276 .events.trip_high = trip_high,
206 .events.trip_low = trip_low,277 .events.trip_low = trip_low,
207 .events.trip_add = trip_add,278 .events.trip_add = trip_add,
208 .events.trip_delete = trip_delete,279 .events.trip_delete = trip_delete,
209 .events.trip_change = trip_change,280 .events.trip_change = trip_change,
210 .events.cdev_add = cdev_add,281 .events.cdev_add = cdev_add,
211 .events.cdev_delete = cdev_delete,282 .events.cdev_delete = cdev_delete,
212 .events.cdev_update = cdev_update,283 .events.cdev_update = cdev_update,
213 .events.gov_change = gov_change284 .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,
214};290};
215 291
216static int thermal_event(__maybe_unused int fd, __maybe_unused void *arg)292static int thermal_event(__maybe_unused int fd, __maybe_unused void *arg)
@@ -280,6 +356,7 @@ enum { · 63 unmodified lines
280 THERMAL_ENGINE_DAEMON_ERROR,356 THERMAL_ENGINE_DAEMON_ERROR,
281 THERMAL_ENGINE_LOG_ERROR,357 THERMAL_ENGINE_LOG_ERROR,
282 THERMAL_ENGINE_THERMAL_ERROR,358 THERMAL_ENGINE_THERMAL_ERROR,
359 THERMAL_ENGINE_THRESHOLD_ERROR,
283 THERMAL_ENGINE_MAINLOOP_ERROR,360 THERMAL_ENGINE_MAINLOOP_ERROR,
284};361};
285 362
@@ -318,6 +395,8 @@ int main(int argc, char *argv[]) · 32 unmodified lines
318 return THERMAL_ENGINE_THERMAL_ERROR;395 return THERMAL_ENGINE_THERMAL_ERROR;
319 }396 }
320 397
398 for_each_thermal_zone(td.tz, set_threshold, td.th);
399
321 for_each_thermal_zone(td.tz, show_tz, td.th);400 for_each_thermal_zone(td.tz, show_tz, td.th);
322 401
323 if (mainloop_init()) {402 if (mainloop_init()) {