Commit | Line | Data |
---|---|---|
873e65bc | 1 | // SPDX-License-Identifier: GPL-2.0-only |
e151a202 D |
2 | /* |
3 | * step_wise.c - A step-by-step Thermal throttling governor | |
4 | * | |
5 | * Copyright (C) 2012 Intel Corp | |
6 | * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> | |
7 | * | |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
9 | * | |
e151a202 D |
10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
11 | */ | |
12 | ||
e151a202 | 13 | #include <linux/thermal.h> |
25bff3ed | 14 | #include <linux/minmax.h> |
32a7a021 | 15 | #include "thermal_trace.h" |
e151a202 D |
16 | |
17 | #include "thermal_core.h" | |
18 | ||
19 | /* | |
20 | * If the temperature is higher than a trip point, | |
21 | * a. if the trend is THERMAL_TREND_RAISING, use higher cooling | |
22 | * state for this trip point | |
07209fcf | 23 | * b. if the trend is THERMAL_TREND_DROPPING, do nothing |
3dbfff3d ZR |
24 | * If the temperature is lower than a trip point, |
25 | * a. if the trend is THERMAL_TREND_RAISING, do nothing | |
26 | * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling | |
27 | * state for this trip point, if the cooling state already | |
28 | * equals lower limit, deactivate the thermal instance | |
e151a202 D |
29 | */ |
30 | static unsigned long get_target_state(struct thermal_instance *instance, | |
3dbfff3d | 31 | enum thermal_trend trend, bool throttle) |
e151a202 D |
32 | { |
33 | struct thermal_cooling_device *cdev = instance->cdev; | |
34 | unsigned long cur_state; | |
ca56caa0 | 35 | unsigned long next_target; |
e151a202 | 36 | |
ca56caa0 EV |
37 | /* |
38 | * We keep this instance the way it is by default. | |
39 | * Otherwise, we use the current state of the | |
40 | * cdev in use to determine the next_target. | |
41 | */ | |
e151a202 | 42 | cdev->ops->get_cur_state(cdev, &cur_state); |
ca56caa0 | 43 | next_target = instance->target; |
06475b55 | 44 | dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state); |
e151a202 | 45 | |
bb431ba2 ZR |
46 | if (!instance->initialized) { |
47 | if (throttle) { | |
25bff3ed | 48 | next_target = clamp((cur_state + 1), instance->lower, instance->upper); |
bb431ba2 ZR |
49 | } else { |
50 | next_target = THERMAL_NO_TARGET; | |
51 | } | |
52 | ||
53 | return next_target; | |
54 | } | |
55 | ||
e4006bfe ZR |
56 | if (throttle) { |
57 | if (trend == THERMAL_TREND_RAISING) | |
25bff3ed | 58 | next_target = clamp((cur_state + 1), instance->lower, instance->upper); |
e4006bfe ZR |
59 | } else { |
60 | if (trend == THERMAL_TREND_DROPPING) { | |
61 | if (cur_state <= instance->lower) | |
ca56caa0 | 62 | next_target = THERMAL_NO_TARGET; |
e4006bfe | 63 | else |
25bff3ed | 64 | next_target = clamp((cur_state - 1), instance->lower, instance->upper); |
e79fe642 | 65 | } |
e151a202 D |
66 | } |
67 | ||
ca56caa0 | 68 | return next_target; |
e151a202 D |
69 | } |
70 | ||
71 | static void update_passive_instance(struct thermal_zone_device *tz, | |
72 | enum thermal_trip_type type, int value) | |
73 | { | |
74 | /* | |
75 | * If value is +1, activate a passive instance. | |
76 | * If value is -1, deactivate a passive instance. | |
77 | */ | |
a7d6ba14 | 78 | if (type == THERMAL_TRIP_PASSIVE) |
e151a202 D |
79 | tz->passive += value; |
80 | } | |
81 | ||
7f725a23 | 82 | static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id) |
e151a202 | 83 | { |
e151a202 | 84 | enum thermal_trend trend; |
b8bb6cb9 | 85 | struct thermal_instance *instance; |
7f725a23 | 86 | struct thermal_trip trip; |
b8bb6cb9 ZR |
87 | bool throttle = false; |
88 | int old_target; | |
e151a202 | 89 | |
7f725a23 | 90 | __thermal_zone_get_trip(tz, trip_id, &trip); |
e151a202 | 91 | |
7f725a23 | 92 | trend = get_tz_trend(tz, trip_id); |
e151a202 | 93 | |
7f725a23 | 94 | if (tz->temperature >= trip.temperature) { |
b8bb6cb9 | 95 | throttle = true; |
7f725a23 | 96 | trace_thermal_zone_trip(tz, trip_id, trip.type); |
208cd822 | 97 | } |
b8bb6cb9 | 98 | |
17e8351a | 99 | dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", |
7f725a23 | 100 | trip_id, trip.type, trip.temperature, trend, throttle); |
06475b55 | 101 | |
b8bb6cb9 | 102 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
7f725a23 | 103 | if (instance->trip != trip_id) |
b8bb6cb9 ZR |
104 | continue; |
105 | ||
106 | old_target = instance->target; | |
107 | instance->target = get_target_state(instance, trend, throttle); | |
06475b55 AL |
108 | dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", |
109 | old_target, (int)instance->target); | |
b8bb6cb9 | 110 | |
bb431ba2 | 111 | if (instance->initialized && old_target == instance->target) |
178c2490 SG |
112 | continue; |
113 | ||
b8bb6cb9 ZR |
114 | /* Activate a passive thermal instance */ |
115 | if (old_target == THERMAL_NO_TARGET && | |
116 | instance->target != THERMAL_NO_TARGET) | |
7f725a23 | 117 | update_passive_instance(tz, trip.type, 1); |
b8bb6cb9 ZR |
118 | /* Deactivate a passive thermal instance */ |
119 | else if (old_target != THERMAL_NO_TARGET && | |
120 | instance->target == THERMAL_NO_TARGET) | |
7f725a23 | 121 | update_passive_instance(tz, trip.type, -1); |
b8bb6cb9 | 122 | |
bb431ba2 | 123 | instance->initialized = true; |
d0b7306d | 124 | mutex_lock(&instance->cdev->lock); |
b8bb6cb9 | 125 | instance->cdev->updated = false; /* cdev needs update */ |
d0b7306d | 126 | mutex_unlock(&instance->cdev->lock); |
b8bb6cb9 | 127 | } |
e151a202 D |
128 | } |
129 | ||
130 | /** | |
56b613ea | 131 | * step_wise_throttle - throttles devices associated with the given zone |
53d256e7 AK |
132 | * @tz: thermal_zone_device |
133 | * @trip: trip point index | |
e151a202 D |
134 | * |
135 | * Throttling Logic: This uses the trend of the thermal zone to throttle. | |
136 | * If the thermal zone is 'heating up' this throttles all the cooling | |
137 | * devices associated with the zone and its particular trip point, by one | |
138 | * step. If the zone is 'cooling down' it brings back the performance of | |
139 | * the devices by one step. | |
140 | */ | |
b88a4977 | 141 | static int step_wise_throttle(struct thermal_zone_device *tz, int trip) |
e151a202 D |
142 | { |
143 | struct thermal_instance *instance; | |
144 | ||
670a5e35 | 145 | lockdep_assert_held(&tz->lock); |
e151a202 | 146 | |
63561fe3 DL |
147 | thermal_zone_trip_update(tz, trip); |
148 | ||
e151a202 D |
149 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) |
150 | thermal_cdev_update(instance->cdev); | |
151 | ||
e151a202 D |
152 | return 0; |
153 | } | |
154 | ||
b88a4977 | 155 | static struct thermal_governor thermal_gov_step_wise = { |
1f53ef17 | 156 | .name = "step_wise", |
e151a202 | 157 | .throttle = step_wise_throttle, |
e151a202 | 158 | }; |
57c5b2ec | 159 | THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise); |