diff options
author | Durgadoss R <durgadoss.r@intel.com> | 2012-09-21 02:36:04 -0400 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2012-11-05 01:00:07 -0500 |
commit | e151a202a084f9f4310d1aa4398325c56ca95fda (patch) | |
tree | 200f8dcd62f7702e5bda755253d99ec98f5d0fa4 /drivers | |
parent | 4ccc5743ae70530f758c7d7ec9a0ca58878e584b (diff) |
Thermal: Introduce a step_wise thermal governor
This patch adds a simple step_wise governor to the
generic thermal layer. This algorithm throttles the
cooling devices in a linear fashion. If the 'trend'
is heating, it throttles by one step. And if the
thermal trend is cooling it de-throttles by one step.
This actually moves the throttling logic from thermal_sys.c
and puts inside step_wise.c, without any change.
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/thermal/Kconfig | 6 | ||||
-rw-r--r-- | drivers/thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/step_wise.c | 194 |
3 files changed, 201 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 84b0f0382e5d..7e1b6de68566 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -61,3 +61,9 @@ config FAIR_SHARE | |||
61 | depends on THERMAL | 61 | depends on THERMAL |
62 | help | 62 | help |
63 | Enable this to manage platform thermals using fair-share governor. | 63 | Enable this to manage platform thermals using fair-share governor. |
64 | |||
65 | config STEP_WISE | ||
66 | bool "Step_wise thermal governor" | ||
67 | depends on THERMAL | ||
68 | help | ||
69 | Enable this to manage platform thermals using a simple linear | ||
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 30540dde4080..4e53c00fe89d 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o | |||
8 | obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o | 8 | obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o |
9 | obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o | 9 | obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o |
10 | obj-$(CONFIG_FAIR_SHARE) += fair_share.o | 10 | obj-$(CONFIG_FAIR_SHARE) += fair_share.o |
11 | obj-$(CONFIG_STEP_WISE) += step_wise.o | ||
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c new file mode 100644 index 000000000000..3f9cfcf66ccd --- /dev/null +++ b/drivers/thermal/step_wise.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * step_wise.c - A step-by-step Thermal throttling governor | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corp | ||
5 | * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> | ||
6 | * | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | */ | ||
24 | |||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/thermal.h> | ||
29 | |||
30 | #include "thermal_core.h" | ||
31 | |||
32 | /* | ||
33 | * If the temperature is higher than a trip point, | ||
34 | * a. if the trend is THERMAL_TREND_RAISING, use higher cooling | ||
35 | * state for this trip point | ||
36 | * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling | ||
37 | * state for this trip point | ||
38 | */ | ||
39 | static unsigned long get_target_state(struct thermal_instance *instance, | ||
40 | enum thermal_trend trend) | ||
41 | { | ||
42 | struct thermal_cooling_device *cdev = instance->cdev; | ||
43 | unsigned long cur_state; | ||
44 | |||
45 | cdev->ops->get_cur_state(cdev, &cur_state); | ||
46 | |||
47 | if (trend == THERMAL_TREND_RAISING) { | ||
48 | cur_state = cur_state < instance->upper ? | ||
49 | (cur_state + 1) : instance->upper; | ||
50 | } else if (trend == THERMAL_TREND_DROPPING) { | ||
51 | cur_state = cur_state > instance->lower ? | ||
52 | (cur_state - 1) : instance->lower; | ||
53 | } | ||
54 | |||
55 | return cur_state; | ||
56 | } | ||
57 | |||
58 | static void update_passive_instance(struct thermal_zone_device *tz, | ||
59 | enum thermal_trip_type type, int value) | ||
60 | { | ||
61 | /* | ||
62 | * If value is +1, activate a passive instance. | ||
63 | * If value is -1, deactivate a passive instance. | ||
64 | */ | ||
65 | if (type == THERMAL_TRIP_PASSIVE || type == THERMAL_TRIPS_NONE) | ||
66 | tz->passive += value; | ||
67 | } | ||
68 | |||
69 | static void update_instance_for_throttle(struct thermal_zone_device *tz, | ||
70 | int trip, enum thermal_trip_type trip_type, | ||
71 | enum thermal_trend trend) | ||
72 | { | ||
73 | struct thermal_instance *instance; | ||
74 | |||
75 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { | ||
76 | if (instance->trip != trip) | ||
77 | continue; | ||
78 | |||
79 | instance->target = get_target_state(instance, trend); | ||
80 | |||
81 | /* Activate a passive thermal instance */ | ||
82 | if (instance->target == THERMAL_NO_TARGET) | ||
83 | update_passive_instance(tz, trip_type, 1); | ||
84 | |||
85 | instance->cdev->updated = false; /* cdev needs update */ | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void update_instance_for_dethrottle(struct thermal_zone_device *tz, | ||
90 | int trip, enum thermal_trip_type trip_type) | ||
91 | { | ||
92 | struct thermal_instance *instance; | ||
93 | struct thermal_cooling_device *cdev; | ||
94 | unsigned long cur_state; | ||
95 | |||
96 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { | ||
97 | if (instance->trip != trip || | ||
98 | instance->target == THERMAL_NO_TARGET) | ||
99 | continue; | ||
100 | |||
101 | cdev = instance->cdev; | ||
102 | cdev->ops->get_cur_state(cdev, &cur_state); | ||
103 | |||
104 | instance->target = cur_state > instance->lower ? | ||
105 | (cur_state - 1) : THERMAL_NO_TARGET; | ||
106 | |||
107 | /* Deactivate a passive thermal instance */ | ||
108 | if (instance->target == THERMAL_NO_TARGET) | ||
109 | update_passive_instance(tz, trip_type, -1); | ||
110 | |||
111 | cdev->updated = false; /* cdev needs update */ | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) | ||
116 | { | ||
117 | long trip_temp; | ||
118 | enum thermal_trip_type trip_type; | ||
119 | enum thermal_trend trend; | ||
120 | |||
121 | if (trip == THERMAL_TRIPS_NONE) { | ||
122 | trip_temp = tz->forced_passive; | ||
123 | trip_type = THERMAL_TRIPS_NONE; | ||
124 | } else { | ||
125 | tz->ops->get_trip_temp(tz, trip, &trip_temp); | ||
126 | tz->ops->get_trip_type(tz, trip, &trip_type); | ||
127 | } | ||
128 | |||
129 | trend = get_tz_trend(tz, trip); | ||
130 | |||
131 | mutex_lock(&tz->lock); | ||
132 | |||
133 | if (tz->temperature >= trip_temp) | ||
134 | update_instance_for_throttle(tz, trip, trip_type, trend); | ||
135 | else | ||
136 | update_instance_for_dethrottle(tz, trip, trip_type); | ||
137 | |||
138 | mutex_unlock(&tz->lock); | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * step_wise_throttle - throttles devices asscciated with the given zone | ||
143 | * @tz - thermal_zone_device | ||
144 | * @trip - the trip point | ||
145 | * @trip_type - type of the trip point | ||
146 | * | ||
147 | * Throttling Logic: This uses the trend of the thermal zone to throttle. | ||
148 | * If the thermal zone is 'heating up' this throttles all the cooling | ||
149 | * devices associated with the zone and its particular trip point, by one | ||
150 | * step. If the zone is 'cooling down' it brings back the performance of | ||
151 | * the devices by one step. | ||
152 | */ | ||
153 | int step_wise_throttle(struct thermal_zone_device *tz, int trip) | ||
154 | { | ||
155 | struct thermal_instance *instance; | ||
156 | |||
157 | thermal_zone_trip_update(tz, trip); | ||
158 | |||
159 | if (tz->forced_passive) | ||
160 | thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE); | ||
161 | |||
162 | mutex_lock(&tz->lock); | ||
163 | |||
164 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) | ||
165 | thermal_cdev_update(instance->cdev); | ||
166 | |||
167 | mutex_unlock(&tz->lock); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | struct thermal_governor thermal_gov_step_wise = { | ||
173 | .name = DEFAULT_THERMAL_GOVERNOR, | ||
174 | .throttle = step_wise_throttle, | ||
175 | .owner = THIS_MODULE, | ||
176 | }; | ||
177 | |||
178 | static int __init thermal_gov_step_wise_init(void) | ||
179 | { | ||
180 | return thermal_register_governor(&thermal_gov_step_wise); | ||
181 | } | ||
182 | |||
183 | static void __exit thermal_gov_step_wise_exit(void) | ||
184 | { | ||
185 | thermal_unregister_governor(&thermal_gov_step_wise); | ||
186 | } | ||
187 | |||
188 | /* This should load after thermal framework */ | ||
189 | fs_initcall(thermal_gov_step_wise_init); | ||
190 | module_exit(thermal_gov_step_wise_exit); | ||
191 | |||
192 | MODULE_AUTHOR("Durgadoss R"); | ||
193 | MODULE_DESCRIPTION("A step-by-step thermal throttling governor"); | ||
194 | MODULE_LICENSE("GPL"); | ||