diff options
-rw-r--r-- | drivers/thermal/Kconfig | 5 | ||||
-rw-r--r-- | drivers/thermal/cpu_cooling.c | 107 | ||||
-rw-r--r-- | include/linux/cpu_cooling.h | 4 |
3 files changed, 88 insertions, 28 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index d1c2160492aa..5e3c02554d99 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -72,10 +72,11 @@ config CPU_THERMAL | |||
72 | select CPU_FREQ_TABLE | 72 | select CPU_FREQ_TABLE |
73 | help | 73 | help |
74 | This implements the generic cpu cooling mechanism through frequency | 74 | This implements the generic cpu cooling mechanism through frequency |
75 | reduction, cpu hotplug and any other ways of reducing temperature. An | 75 | reduction. An ACPI version of this already exists |
76 | ACPI version of this already exists(drivers/acpi/processor_thermal.c). | 76 | (drivers/acpi/processor_thermal.c). |
77 | This will be useful for platforms using the generic thermal interface | 77 | This will be useful for platforms using the generic thermal interface |
78 | and not the ACPI interface. | 78 | and not the ACPI interface. |
79 | |||
79 | If you want this support, you should say Y here. | 80 | If you want this support, you should say Y here. |
80 | 81 | ||
81 | config THERMAL_EMULATION | 82 | config THERMAL_EMULATION |
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 768b508f0d69..a294921be650 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c | |||
@@ -20,10 +20,8 @@ | |||
20 | * | 20 | * |
21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
22 | */ | 22 | */ |
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | 23 | #include <linux/module.h> |
25 | #include <linux/thermal.h> | 24 | #include <linux/thermal.h> |
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/cpufreq.h> | 25 | #include <linux/cpufreq.h> |
28 | #include <linux/err.h> | 26 | #include <linux/err.h> |
29 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
@@ -31,21 +29,19 @@ | |||
31 | #include <linux/cpu_cooling.h> | 29 | #include <linux/cpu_cooling.h> |
32 | 30 | ||
33 | /** | 31 | /** |
34 | * struct cpufreq_cooling_device | 32 | * struct cpufreq_cooling_device - data for cooling device with cpufreq |
35 | * @id: unique integer value corresponding to each cpufreq_cooling_device | 33 | * @id: unique integer value corresponding to each cpufreq_cooling_device |
36 | * registered. | 34 | * registered. |
37 | * @cool_dev: thermal_cooling_device pointer to keep track of the the | 35 | * @cool_dev: thermal_cooling_device pointer to keep track of the |
38 | * egistered cooling device. | 36 | * registered cooling device. |
39 | * @cpufreq_state: integer value representing the current state of cpufreq | 37 | * @cpufreq_state: integer value representing the current state of cpufreq |
40 | * cooling devices. | 38 | * cooling devices. |
41 | * @cpufreq_val: integer value representing the absolute value of the clipped | 39 | * @cpufreq_val: integer value representing the absolute value of the clipped |
42 | * frequency. | 40 | * frequency. |
43 | * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. | 41 | * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. |
44 | * @node: list_head to link all cpufreq_cooling_device together. | ||
45 | * | 42 | * |
46 | * This structure is required for keeping information of each | 43 | * This structure is required for keeping information of each |
47 | * cpufreq_cooling_device registered as a list whose head is represented by | 44 | * cpufreq_cooling_device registered. In order to prevent corruption of this a |
48 | * cooling_cpufreq_list. In order to prevent corruption of this list a | ||
49 | * mutex lock cooling_cpufreq_lock is used. | 45 | * mutex lock cooling_cpufreq_lock is used. |
50 | */ | 46 | */ |
51 | struct cpufreq_cooling_device { | 47 | struct cpufreq_cooling_device { |
@@ -54,9 +50,7 @@ struct cpufreq_cooling_device { | |||
54 | unsigned int cpufreq_state; | 50 | unsigned int cpufreq_state; |
55 | unsigned int cpufreq_val; | 51 | unsigned int cpufreq_val; |
56 | struct cpumask allowed_cpus; | 52 | struct cpumask allowed_cpus; |
57 | struct list_head node; | ||
58 | }; | 53 | }; |
59 | static LIST_HEAD(cooling_cpufreq_list); | ||
60 | static DEFINE_IDR(cpufreq_idr); | 54 | static DEFINE_IDR(cpufreq_idr); |
61 | static DEFINE_MUTEX(cooling_cpufreq_lock); | 55 | static DEFINE_MUTEX(cooling_cpufreq_lock); |
62 | 56 | ||
@@ -99,8 +93,14 @@ static void release_idr(struct idr *idr, int id) | |||
99 | /* Below code defines functions to be used for cpufreq as cooling device */ | 93 | /* Below code defines functions to be used for cpufreq as cooling device */ |
100 | 94 | ||
101 | /** | 95 | /** |
102 | * is_cpufreq_valid - function to check if a cpu has frequency transition policy. | 96 | * is_cpufreq_valid - function to check frequency transitioning capability. |
103 | * @cpu: cpu for which check is needed. | 97 | * @cpu: cpu for which check is needed. |
98 | * | ||
99 | * This function will check the current state of the system if | ||
100 | * it is capable of changing the frequency for a given @cpu. | ||
101 | * | ||
102 | * Return: 0 if the system is not currently capable of changing | ||
103 | * the frequency of given cpu. !0 in case the frequency is changeable. | ||
104 | */ | 104 | */ |
105 | static int is_cpufreq_valid(int cpu) | 105 | static int is_cpufreq_valid(int cpu) |
106 | { | 106 | { |
@@ -114,8 +114,14 @@ enum cpufreq_cooling_property { | |||
114 | GET_MAXL, | 114 | GET_MAXL, |
115 | }; | 115 | }; |
116 | 116 | ||
117 | /* | 117 | /** |
118 | * this is the common function to | 118 | * get_property - fetch a property of interest for a give cpu. |
119 | * @cpu: cpu for which the property is required | ||
120 | * @input: query parameter | ||
121 | * @output: query return | ||
122 | * @property: type of query (frequency, level, max level) | ||
123 | * | ||
124 | * This is the common function to | ||
119 | * 1. get maximum cpu cooling states | 125 | * 1. get maximum cpu cooling states |
120 | * 2. translate frequency to cooling state | 126 | * 2. translate frequency to cooling state |
121 | * 3. translate cooling state to frequency | 127 | * 3. translate cooling state to frequency |
@@ -124,12 +130,14 @@ enum cpufreq_cooling_property { | |||
124 | * a) reduce duplicate code as most of the code can be shared. | 130 | * a) reduce duplicate code as most of the code can be shared. |
125 | * b) make sure the logic is consistent when translating between | 131 | * b) make sure the logic is consistent when translating between |
126 | * cooling states and frequencies. | 132 | * cooling states and frequencies. |
127 | */ | 133 | * |
134 | * Return: 0 on success, -EINVAL when invalid parameters are passed. | ||
135 | */ | ||
128 | static int get_property(unsigned int cpu, unsigned long input, | 136 | static int get_property(unsigned int cpu, unsigned long input, |
129 | unsigned int* output, enum cpufreq_cooling_property property) | 137 | unsigned int* output, enum cpufreq_cooling_property property) |
130 | { | 138 | { |
131 | int i, j; | 139 | int i, j; |
132 | unsigned long max_level = 0, level; | 140 | unsigned long max_level = 0, level = 0; |
133 | unsigned int freq = CPUFREQ_ENTRY_INVALID; | 141 | unsigned int freq = CPUFREQ_ENTRY_INVALID; |
134 | int descend = -1; | 142 | int descend = -1; |
135 | struct cpufreq_frequency_table *table = | 143 | struct cpufreq_frequency_table *table = |
@@ -196,6 +204,17 @@ static int get_property(unsigned int cpu, unsigned long input, | |||
196 | return -EINVAL; | 204 | return -EINVAL; |
197 | } | 205 | } |
198 | 206 | ||
207 | /** | ||
208 | * cpufreq_cooling_get_level - for a give cpu, return the cooling level. | ||
209 | * @cpu: cpu for which the level is required | ||
210 | * @freq: the frequency of interest | ||
211 | * | ||
212 | * This function will match the cooling level corresponding to the | ||
213 | * requested @freq and return it. | ||
214 | * | ||
215 | * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID | ||
216 | * otherwise. | ||
217 | */ | ||
199 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) | 218 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) |
200 | { | 219 | { |
201 | unsigned int val; | 220 | unsigned int val; |
@@ -204,14 +223,19 @@ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) | |||
204 | return THERMAL_CSTATE_INVALID; | 223 | return THERMAL_CSTATE_INVALID; |
205 | return (unsigned long)val; | 224 | return (unsigned long)val; |
206 | } | 225 | } |
207 | 226 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); | |
208 | EXPORT_SYMBOL(cpufreq_cooling_get_level); | ||
209 | 227 | ||
210 | /** | 228 | /** |
211 | * get_cpu_frequency - get the absolute value of frequency from level. | 229 | * get_cpu_frequency - get the absolute value of frequency from level. |
212 | * @cpu: cpu for which frequency is fetched. | 230 | * @cpu: cpu for which frequency is fetched. |
213 | * @level: level of frequency, equals cooling state of cpu cooling device | 231 | * @level: cooling level |
232 | * | ||
233 | * This function matches cooling level with frequency. Based on a cooling level | ||
234 | * of frequency, equals cooling state of cpu cooling device, it will return | ||
235 | * the corresponding frequency. | ||
214 | * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc | 236 | * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc |
237 | * | ||
238 | * Return: 0 on error, the corresponding frequency otherwise. | ||
215 | */ | 239 | */ |
216 | static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) | 240 | static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) |
217 | { | 241 | { |
@@ -229,6 +253,12 @@ static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) | |||
229 | * @cpufreq_device: cpufreq_cooling_device pointer containing frequency | 253 | * @cpufreq_device: cpufreq_cooling_device pointer containing frequency |
230 | * clipping data. | 254 | * clipping data. |
231 | * @cooling_state: value of the cooling state. | 255 | * @cooling_state: value of the cooling state. |
256 | * | ||
257 | * Function used to make sure the cpufreq layer is aware of current thermal | ||
258 | * limits. The limits are applied by updating the cpufreq policy. | ||
259 | * | ||
260 | * Return: 0 on success, an error code otherwise (-EINVAL in case wrong | ||
261 | * cooling state). | ||
232 | */ | 262 | */ |
233 | static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, | 263 | static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, |
234 | unsigned long cooling_state) | 264 | unsigned long cooling_state) |
@@ -265,6 +295,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, | |||
265 | * @nb: struct notifier_block * with callback info. | 295 | * @nb: struct notifier_block * with callback info. |
266 | * @event: value showing cpufreq event for which this function invoked. | 296 | * @event: value showing cpufreq event for which this function invoked. |
267 | * @data: callback-specific data | 297 | * @data: callback-specific data |
298 | * | ||
299 | * Callback to highjack the notification on cpufreq policy transition. | ||
300 | * Every time there is a change in policy, we will intercept and | ||
301 | * update the cpufreq policy with thermal constraints. | ||
302 | * | ||
303 | * Return: 0 (success) | ||
268 | */ | 304 | */ |
269 | static int cpufreq_thermal_notifier(struct notifier_block *nb, | 305 | static int cpufreq_thermal_notifier(struct notifier_block *nb, |
270 | unsigned long event, void *data) | 306 | unsigned long event, void *data) |
@@ -296,6 +332,11 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, | |||
296 | * cpufreq_get_max_state - callback function to get the max cooling state. | 332 | * cpufreq_get_max_state - callback function to get the max cooling state. |
297 | * @cdev: thermal cooling device pointer. | 333 | * @cdev: thermal cooling device pointer. |
298 | * @state: fill this variable with the max cooling state. | 334 | * @state: fill this variable with the max cooling state. |
335 | * | ||
336 | * Callback for the thermal cooling device to return the cpufreq | ||
337 | * max cooling state. | ||
338 | * | ||
339 | * Return: 0 on success, an error code otherwise. | ||
299 | */ | 340 | */ |
300 | static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, | 341 | static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, |
301 | unsigned long *state) | 342 | unsigned long *state) |
@@ -320,6 +361,11 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, | |||
320 | * cpufreq_get_cur_state - callback function to get the current cooling state. | 361 | * cpufreq_get_cur_state - callback function to get the current cooling state. |
321 | * @cdev: thermal cooling device pointer. | 362 | * @cdev: thermal cooling device pointer. |
322 | * @state: fill this variable with the current cooling state. | 363 | * @state: fill this variable with the current cooling state. |
364 | * | ||
365 | * Callback for the thermal cooling device to return the cpufreq | ||
366 | * current cooling state. | ||
367 | * | ||
368 | * Return: 0 on success, an error code otherwise. | ||
323 | */ | 369 | */ |
324 | static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, | 370 | static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, |
325 | unsigned long *state) | 371 | unsigned long *state) |
@@ -334,6 +380,11 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, | |||
334 | * cpufreq_set_cur_state - callback function to set the current cooling state. | 380 | * cpufreq_set_cur_state - callback function to set the current cooling state. |
335 | * @cdev: thermal cooling device pointer. | 381 | * @cdev: thermal cooling device pointer. |
336 | * @state: set this variable to the current cooling state. | 382 | * @state: set this variable to the current cooling state. |
383 | * | ||
384 | * Callback for the thermal cooling device to change the cpufreq | ||
385 | * current cooling state. | ||
386 | * | ||
387 | * Return: 0 on success, an error code otherwise. | ||
337 | */ | 388 | */ |
338 | static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, | 389 | static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, |
339 | unsigned long state) | 390 | unsigned long state) |
@@ -358,6 +409,13 @@ static struct notifier_block thermal_cpufreq_notifier_block = { | |||
358 | /** | 409 | /** |
359 | * cpufreq_cooling_register - function to create cpufreq cooling device. | 410 | * cpufreq_cooling_register - function to create cpufreq cooling device. |
360 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. | 411 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. |
412 | * | ||
413 | * This interface function registers the cpufreq cooling device with the name | ||
414 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | ||
415 | * cooling devices. | ||
416 | * | ||
417 | * Return: a valid struct thermal_cooling_device pointer on success, | ||
418 | * on failure, it returns a corresponding ERR_PTR(). | ||
361 | */ | 419 | */ |
362 | struct thermal_cooling_device *cpufreq_cooling_register( | 420 | struct thermal_cooling_device *cpufreq_cooling_register( |
363 | const struct cpumask *clip_cpus) | 421 | const struct cpumask *clip_cpus) |
@@ -396,7 +454,8 @@ struct thermal_cooling_device *cpufreq_cooling_register( | |||
396 | return ERR_PTR(-EINVAL); | 454 | return ERR_PTR(-EINVAL); |
397 | } | 455 | } |
398 | 456 | ||
399 | sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id); | 457 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", |
458 | cpufreq_dev->id); | ||
400 | 459 | ||
401 | cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev, | 460 | cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev, |
402 | &cpufreq_cooling_ops); | 461 | &cpufreq_cooling_ops); |
@@ -418,11 +477,13 @@ struct thermal_cooling_device *cpufreq_cooling_register( | |||
418 | mutex_unlock(&cooling_cpufreq_lock); | 477 | mutex_unlock(&cooling_cpufreq_lock); |
419 | return cool_dev; | 478 | return cool_dev; |
420 | } | 479 | } |
421 | EXPORT_SYMBOL(cpufreq_cooling_register); | 480 | EXPORT_SYMBOL_GPL(cpufreq_cooling_register); |
422 | 481 | ||
423 | /** | 482 | /** |
424 | * cpufreq_cooling_unregister - function to remove cpufreq cooling device. | 483 | * cpufreq_cooling_unregister - function to remove cpufreq cooling device. |
425 | * @cdev: thermal cooling device pointer. | 484 | * @cdev: thermal cooling device pointer. |
485 | * | ||
486 | * This interface function unregisters the "thermal-cpufreq-%x" cooling device. | ||
426 | */ | 487 | */ |
427 | void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | 488 | void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) |
428 | { | 489 | { |
@@ -432,14 +493,14 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |||
432 | cpufreq_dev_count--; | 493 | cpufreq_dev_count--; |
433 | 494 | ||
434 | /* Unregister the notifier for the last cpufreq cooling device */ | 495 | /* Unregister the notifier for the last cpufreq cooling device */ |
435 | if (cpufreq_dev_count == 0) { | 496 | if (cpufreq_dev_count == 0) |
436 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, | 497 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, |
437 | CPUFREQ_POLICY_NOTIFIER); | 498 | CPUFREQ_POLICY_NOTIFIER); |
438 | } | 499 | |
439 | mutex_unlock(&cooling_cpufreq_lock); | 500 | mutex_unlock(&cooling_cpufreq_lock); |
440 | 501 | ||
441 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); | 502 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); |
442 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 503 | release_idr(&cpufreq_idr, cpufreq_dev->id); |
443 | kfree(cpufreq_dev); | 504 | kfree(cpufreq_dev); |
444 | } | 505 | } |
445 | EXPORT_SYMBOL(cpufreq_cooling_unregister); | 506 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); |
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index 77c87c9d0193..f48f6fbcd3be 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h | |||
@@ -25,9 +25,7 @@ | |||
25 | #define __CPU_COOLING_H__ | 25 | #define __CPU_COOLING_H__ |
26 | 26 | ||
27 | #include <linux/thermal.h> | 27 | #include <linux/thermal.h> |
28 | 28 | #include <linux/cpumask.h> | |
29 | #define CPUFREQ_COOLING_START 0 | ||
30 | #define CPUFREQ_COOLING_STOP 1 | ||
31 | 29 | ||
32 | #ifdef CONFIG_CPU_THERMAL | 30 | #ifdef CONFIG_CPU_THERMAL |
33 | /** | 31 | /** |