aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/Kconfig5
-rw-r--r--drivers/thermal/cpu_cooling.c107
-rw-r--r--include/linux/cpu_cooling.h4
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
81config THERMAL_EMULATION 82config 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 */
51struct cpufreq_cooling_device { 47struct 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};
59static LIST_HEAD(cooling_cpufreq_list);
60static DEFINE_IDR(cpufreq_idr); 54static DEFINE_IDR(cpufreq_idr);
61static DEFINE_MUTEX(cooling_cpufreq_lock); 55static 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 */
105static int is_cpufreq_valid(int cpu) 105static 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 */
128static int get_property(unsigned int cpu, unsigned long input, 136static 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 */
199unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) 218unsigned 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 226EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
208EXPORT_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 */
216static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) 240static 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 */
233static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, 263static 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 */
269static int cpufreq_thermal_notifier(struct notifier_block *nb, 305static 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 */
300static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, 341static 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 */
324static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, 370static 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 */
338static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, 389static 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 */
362struct thermal_cooling_device *cpufreq_cooling_register( 420struct 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}
421EXPORT_SYMBOL(cpufreq_cooling_register); 480EXPORT_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 */
427void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 488void 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}
445EXPORT_SYMBOL(cpufreq_cooling_unregister); 506EXPORT_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/**