aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2008-01-17 02:51:23 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 23:18:19 -0500
commitd9460fd227ed2ce52941b6a12ad4de05c195f6aa (patch)
tree1fb877cf41c8599e0fc9c1fbf902b88baba60708
parent05a83d972293f39a66bc2aa409a5e7996bba585d (diff)
ACPI: register ACPI Processor as generic thermal cooling device
Register ACPI processor as thermal cooling devices. A combination of processor T-state and P-state are used for thermal throttling. the processor will reduce the frequency first and then set the T-state. we use cpufreq_thermal_reduction_pctg to calculate the cpufreq limit, and call cpufreq_verify_with_limit to set the cpufreq limit. if cpufreq driver is loaded, then we have four cooling state for cpufreq control. cooling state 0: cpufreq limit == max_freq cooling state 1: cpufreq limit == max_freq * 80% cooling state 2: cpufreq limit == max_freq * 60% cooling state 3: cpufreq limit == max_freq * 40% after the cpufreq limit is set to 40 percentage of the max_freq, we use T-state for cooling. eg. a processor has P-state support, and it has 8 T-state (T0-T7), the max_state of the proceesor is 10: state cpufreq-limit T-state 0: max_freq T0 1: max_freq * 80% T0 2: max_freq * 60% T0 3: max_freq * 40% T0 4: max_freq * 40% T1 5: max_freq * 40% T2 6: max_freq * 40% T3 7: max_freq * 40% T4 8: max_freq * 40% T5 9: max_freq * 40% T6 10: max_freq * 40% T7 Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Thomas Sujith <sujith.thomas@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/processor_core.c23
-rw-r--r--drivers/acpi/processor_thermal.c134
-rw-r--r--include/acpi/processor.h6
3 files changed, 155 insertions, 8 deletions
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e48ee4f8749f..5668c5e8ae19 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
668 668
669 acpi_processor_power_init(pr, device); 669 acpi_processor_power_init(pr, device);
670 670
671 pr->cdev = thermal_cooling_device_register("Processor", device,
672 &processor_cooling_ops);
673 if (pr->cdev)
674 printk(KERN_INFO PREFIX
675 "%s is registered as cooling_device%d\n",
676 device->dev.bus_id, pr->cdev->id);
677 else
678 goto end;
679
680 result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
681 "thermal_cooling");
682 if (result)
683 return result;
684 result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
685 "device");
686 if (result)
687 return result;
688
671 if (pr->flags.throttling) { 689 if (pr->flags.throttling) {
672 printk(KERN_INFO PREFIX "%s [%s] (supports", 690 printk(KERN_INFO PREFIX "%s [%s] (supports",
673 acpi_device_name(device), acpi_device_bid(device)); 691 acpi_device_name(device), acpi_device_bid(device));
@@ -791,6 +809,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
791 809
792 acpi_processor_remove_fs(device); 810 acpi_processor_remove_fs(device);
793 811
812 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
813 sysfs_remove_link(&pr->cdev->device.kobj, "device");
814 thermal_cooling_device_unregister(pr->cdev);
815 pr->cdev = NULL;
816
794 processors[pr->id] = NULL; 817 processors[pr->id] = NULL;
795 818
796 kfree(pr); 819 kfree(pr);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 06e6f3fb8825..9cb43f52f7b6 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -32,6 +32,7 @@
32#include <linux/cpufreq.h> 32#include <linux/cpufreq.h>
33#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/sysdev.h>
35 36
36#include <asm/uaccess.h> 37#include <asm/uaccess.h>
37 38
@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
93 * _any_ cpufreq driver and not only the acpi-cpufreq driver. 94 * _any_ cpufreq driver and not only the acpi-cpufreq driver.
94 */ 95 */
95 96
97#define CPUFREQ_THERMAL_MIN_STEP 0
98#define CPUFREQ_THERMAL_MAX_STEP 3
99
96static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; 100static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
97static unsigned int acpi_thermal_cpufreq_is_init = 0; 101static unsigned int acpi_thermal_cpufreq_is_init = 0;
98 102
@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
109 if (!cpu_has_cpufreq(cpu)) 113 if (!cpu_has_cpufreq(cpu))
110 return -ENODEV; 114 return -ENODEV;
111 115
112 if (cpufreq_thermal_reduction_pctg[cpu] < 60) { 116 if (cpufreq_thermal_reduction_pctg[cpu] <
113 cpufreq_thermal_reduction_pctg[cpu] += 20; 117 CPUFREQ_THERMAL_MAX_STEP) {
118 cpufreq_thermal_reduction_pctg[cpu]++;
114 cpufreq_update_policy(cpu); 119 cpufreq_update_policy(cpu);
115 return 0; 120 return 0;
116 } 121 }
@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
123 if (!cpu_has_cpufreq(cpu)) 128 if (!cpu_has_cpufreq(cpu))
124 return -ENODEV; 129 return -ENODEV;
125 130
126 if (cpufreq_thermal_reduction_pctg[cpu] > 20) 131 if (cpufreq_thermal_reduction_pctg[cpu] >
127 cpufreq_thermal_reduction_pctg[cpu] -= 20; 132 (CPUFREQ_THERMAL_MIN_STEP + 1))
133 cpufreq_thermal_reduction_pctg[cpu]--;
128 else 134 else
129 cpufreq_thermal_reduction_pctg[cpu] = 0; 135 cpufreq_thermal_reduction_pctg[cpu] = 0;
130 cpufreq_update_policy(cpu); 136 cpufreq_update_policy(cpu);
@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
143 149
144 max_freq = 150 max_freq =
145 (policy->cpuinfo.max_freq * 151 (policy->cpuinfo.max_freq *
146 (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; 152 (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
147 153
148 cpufreq_verify_within_limits(policy, 0, max_freq); 154 cpufreq_verify_within_limits(policy, 0, max_freq);
149 155
@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
155 .notifier_call = acpi_thermal_cpufreq_notifier, 161 .notifier_call = acpi_thermal_cpufreq_notifier,
156}; 162};
157 163
164static int cpufreq_get_max_state(unsigned int cpu)
165{
166 if (!cpu_has_cpufreq(cpu))
167 return 0;
168
169 return CPUFREQ_THERMAL_MAX_STEP;
170}
171
172static int cpufreq_get_cur_state(unsigned int cpu)
173{
174 if (!cpu_has_cpufreq(cpu))
175 return 0;
176
177 return cpufreq_thermal_reduction_pctg[cpu];
178}
179
180static int cpufreq_set_cur_state(unsigned int cpu, int state)
181{
182 if (!cpu_has_cpufreq(cpu))
183 return 0;
184
185 cpufreq_thermal_reduction_pctg[cpu] = state;
186 cpufreq_update_policy(cpu);
187 return 0;
188}
189
158void acpi_thermal_cpufreq_init(void) 190void acpi_thermal_cpufreq_init(void)
159{ 191{
160 int i; 192 int i;
@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
179} 211}
180 212
181#else /* ! CONFIG_CPU_FREQ */ 213#else /* ! CONFIG_CPU_FREQ */
214static int cpufreq_get_max_state(unsigned int cpu)
215{
216 return 0;
217}
218
219static int cpufreq_get_cur_state(unsigned int cpu)
220{
221 return 0;
222}
223
224static int cpufreq_set_cur_state(unsigned int cpu, int state)
225{
226 return 0;
227}
182 228
183static int acpi_thermal_cpufreq_increase(unsigned int cpu) 229static int acpi_thermal_cpufreq_increase(unsigned int cpu)
184{ 230{
@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
310 return 0; 356 return 0;
311} 357}
312 358
359/* thermal coolign device callbacks */
360static int acpi_processor_max_state(struct acpi_processor *pr)
361{
362 int max_state = 0;
363
364 /*
365 * There exists four states according to
366 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
367 */
368 max_state += cpufreq_get_max_state(pr->id);
369 if (pr->flags.throttling)
370 max_state += (pr->throttling.state_count -1);
371
372 return max_state;
373}
374static int
375processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
376{
377 struct acpi_device *device = cdev->devdata;
378 struct acpi_processor *pr = acpi_driver_data(device);
379
380 if (!device || !pr)
381 return -EINVAL;
382
383 return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
384}
385
386static int
387processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
388{
389 struct acpi_device *device = cdev->devdata;
390 struct acpi_processor *pr = acpi_driver_data(device);
391 int cur_state;
392
393 if (!device || !pr)
394 return -EINVAL;
395
396 cur_state = cpufreq_get_cur_state(pr->id);
397 if (pr->flags.throttling)
398 cur_state += pr->throttling.state;
399
400 return sprintf(buf, "%d\n", cur_state);
401}
402
403static int
404processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
405{
406 struct acpi_device *device = cdev->devdata;
407 struct acpi_processor *pr = acpi_driver_data(device);
408 int result = 0;
409 int max_pstate;
410
411 if (!device || !pr)
412 return -EINVAL;
413
414 max_pstate = cpufreq_get_max_state(pr->id);
415
416 if (state > acpi_processor_max_state(pr))
417 return -EINVAL;
418
419 if (state <= max_pstate) {
420 if (pr->flags.throttling && pr->throttling.state)
421 result = acpi_processor_set_throttling(pr, 0);
422 cpufreq_set_cur_state(pr->id, state);
423 } else {
424 cpufreq_set_cur_state(pr->id, max_pstate);
425 result = acpi_processor_set_throttling(pr,
426 state - max_pstate);
427 }
428 return result;
429}
430
431struct thermal_cooling_device_ops processor_cooling_ops = {
432 .get_max_state = processor_get_max_state,
433 .get_cur_state = processor_get_cur_state,
434 .set_cur_state = processor_set_cur_state,
435};
436
313/* /proc interface */ 437/* /proc interface */
314 438
315static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) 439static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 76411b1fc4fd..0787635a11aa 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -4,7 +4,7 @@
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/cpu.h> 5#include <linux/cpu.h>
6#include <linux/cpuidle.h> 6#include <linux/cpuidle.h>
7 7#include <linux/thermal.h>
8#include <asm/acpi.h> 8#include <asm/acpi.h>
9 9
10#define ACPI_PROCESSOR_BUSY_METRIC 10 10#define ACPI_PROCESSOR_BUSY_METRIC 10
@@ -218,7 +218,7 @@ struct acpi_processor {
218 struct acpi_processor_performance *performance; 218 struct acpi_processor_performance *performance;
219 struct acpi_processor_throttling throttling; 219 struct acpi_processor_throttling throttling;
220 struct acpi_processor_limit limit; 220 struct acpi_processor_limit limit;
221 221 struct thermal_cooling_device *cdev;
222 /* the _PDC objects for this processor, if any */ 222 /* the _PDC objects for this processor, if any */
223 struct acpi_object_list *pdc; 223 struct acpi_object_list *pdc;
224}; 224};
@@ -330,7 +330,7 @@ extern struct cpuidle_driver acpi_idle_driver;
330/* in processor_thermal.c */ 330/* in processor_thermal.c */
331int acpi_processor_get_limit_info(struct acpi_processor *pr); 331int acpi_processor_get_limit_info(struct acpi_processor *pr);
332extern struct file_operations acpi_processor_limit_fops; 332extern struct file_operations acpi_processor_limit_fops;
333 333extern struct thermal_cooling_device_ops processor_cooling_ops;
334#ifdef CONFIG_CPU_FREQ 334#ifdef CONFIG_CPU_FREQ
335void acpi_thermal_cpufreq_init(void); 335void acpi_thermal_cpufreq_init(void);
336void acpi_thermal_cpufreq_exit(void); 336void acpi_thermal_cpufreq_exit(void);