diff options
author | Rafał Bilski <rafalbilski@interia.pl> | 2011-07-21 17:11:29 -0400 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2011-10-26 17:19:46 -0400 |
commit | 27e954c241673d2437448bd8bf0eaa7cd81a4b15 (patch) | |
tree | 457008d9d5b8fa9dacb3a0c00ce81248e26c0cb6 /drivers/cpufreq/e_powersaver.c | |
parent | ed361bf08033f165e0a004f254919e13f07df0ae (diff) |
[CPUFREQ] e_powersaver: Check BIOS limit for CPU frequency
Call ACPI function to get BIOS limit for CPU frequency.
Fail if processor would like to run at higher frequency.
Allow user to ignore BIOS limit.
eps: Detected VIA Model D C7-M
eps: Current voltage = 1084mV
eps: Current multiplier = 16
eps: Highest voltage = 1084mV
eps: Highest multiplier = 16
eps: Lowest voltage = 844mV
eps: Lowest multiplier = 4
eps: ACPI limit 1.60GHz
Signed-off-by: Rafał Bilski <rafalbilski@interia.pl>
Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'drivers/cpufreq/e_powersaver.c')
-rw-r--r-- | drivers/cpufreq/e_powersaver.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index 84661c54a74c..2882d40a3084 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c | |||
@@ -19,6 +19,11 @@ | |||
19 | #include <asm/msr.h> | 19 | #include <asm/msr.h> |
20 | #include <asm/tsc.h> | 20 | #include <asm/tsc.h> |
21 | 21 | ||
22 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
23 | #include <linux/acpi.h> | ||
24 | #include <acpi/processor.h> | ||
25 | #endif | ||
26 | |||
22 | #define EPS_BRAND_C7M 0 | 27 | #define EPS_BRAND_C7M 0 |
23 | #define EPS_BRAND_C7 1 | 28 | #define EPS_BRAND_C7 1 |
24 | #define EPS_BRAND_EDEN 2 | 29 | #define EPS_BRAND_EDEN 2 |
@@ -27,6 +32,9 @@ | |||
27 | 32 | ||
28 | struct eps_cpu_data { | 33 | struct eps_cpu_data { |
29 | u32 fsb; | 34 | u32 fsb; |
35 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
36 | u32 bios_limit; | ||
37 | #endif | ||
30 | struct cpufreq_frequency_table freq_table[]; | 38 | struct cpufreq_frequency_table freq_table[]; |
31 | }; | 39 | }; |
32 | 40 | ||
@@ -36,6 +44,46 @@ static struct eps_cpu_data *eps_cpu[NR_CPUS]; | |||
36 | static int freq_failsafe_off; | 44 | static int freq_failsafe_off; |
37 | static int voltage_failsafe_off; | 45 | static int voltage_failsafe_off; |
38 | 46 | ||
47 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
48 | static int ignore_acpi_limit; | ||
49 | |||
50 | static struct acpi_processor_performance *eps_acpi_cpu_perf; | ||
51 | |||
52 | /* Minimum necessary to get acpi_processor_get_bios_limit() working */ | ||
53 | static int eps_acpi_init(void) | ||
54 | { | ||
55 | eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance), | ||
56 | GFP_KERNEL); | ||
57 | if (!eps_acpi_cpu_perf) | ||
58 | return -ENOMEM; | ||
59 | |||
60 | if (!zalloc_cpumask_var(&eps_acpi_cpu_perf->shared_cpu_map, | ||
61 | GFP_KERNEL)) { | ||
62 | kfree(eps_acpi_cpu_perf); | ||
63 | eps_acpi_cpu_perf = NULL; | ||
64 | return -ENOMEM; | ||
65 | } | ||
66 | |||
67 | if (acpi_processor_register_performance(eps_acpi_cpu_perf, 0)) { | ||
68 | free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map); | ||
69 | kfree(eps_acpi_cpu_perf); | ||
70 | eps_acpi_cpu_perf = NULL; | ||
71 | return -EIO; | ||
72 | } | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int eps_acpi_exit(struct cpufreq_policy *policy) | ||
77 | { | ||
78 | if (eps_acpi_cpu_perf) { | ||
79 | acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0); | ||
80 | free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map); | ||
81 | kfree(eps_acpi_cpu_perf); | ||
82 | eps_acpi_cpu_perf = NULL; | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | #endif | ||
39 | 87 | ||
40 | static unsigned int eps_get(unsigned int cpu) | 88 | static unsigned int eps_get(unsigned int cpu) |
41 | { | 89 | { |
@@ -168,6 +216,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy) | |||
168 | int k, step, voltage; | 216 | int k, step, voltage; |
169 | int ret; | 217 | int ret; |
170 | int states; | 218 | int states; |
219 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
220 | unsigned int limit; | ||
221 | #endif | ||
171 | 222 | ||
172 | if (policy->cpu != 0) | 223 | if (policy->cpu != 0) |
173 | return -ENODEV; | 224 | return -ENODEV; |
@@ -271,6 +322,24 @@ static int eps_cpu_init(struct cpufreq_policy *policy) | |||
271 | 322 | ||
272 | /* Calc FSB speed */ | 323 | /* Calc FSB speed */ |
273 | fsb = cpu_khz / current_multiplier; | 324 | fsb = cpu_khz / current_multiplier; |
325 | |||
326 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
327 | /* Check for ACPI processor speed limit */ | ||
328 | if (!ignore_acpi_limit && !eps_acpi_init()) { | ||
329 | if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) { | ||
330 | printk(KERN_INFO "eps: ACPI limit %u.%uGHz\n", | ||
331 | limit/1000000, | ||
332 | (limit%1000000)/10000); | ||
333 | eps_acpi_exit(policy); | ||
334 | /* Check if max_multiplier is in BIOS limits */ | ||
335 | if (limit && max_multiplier * fsb > limit) { | ||
336 | printk(KERN_INFO "eps: Aborting.\n"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | #endif | ||
342 | |||
274 | /* Calc number of p-states supported */ | 343 | /* Calc number of p-states supported */ |
275 | if (brand == EPS_BRAND_C7M) | 344 | if (brand == EPS_BRAND_C7M) |
276 | states = max_multiplier - min_multiplier + 1; | 345 | states = max_multiplier - min_multiplier + 1; |
@@ -287,6 +356,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy) | |||
287 | 356 | ||
288 | /* Copy basic values */ | 357 | /* Copy basic values */ |
289 | centaur->fsb = fsb; | 358 | centaur->fsb = fsb; |
359 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
360 | centaur->bios_limit = limit; | ||
361 | #endif | ||
290 | 362 | ||
291 | /* Fill frequency and MSR value table */ | 363 | /* Fill frequency and MSR value table */ |
292 | f_table = ¢aur->freq_table[0]; | 364 | f_table = ¢aur->freq_table[0]; |
@@ -377,6 +449,10 @@ module_param(freq_failsafe_off, int, 0644); | |||
377 | MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check"); | 449 | MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check"); |
378 | module_param(voltage_failsafe_off, int, 0644); | 450 | module_param(voltage_failsafe_off, int, 0644); |
379 | MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check"); | 451 | MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check"); |
452 | #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE | ||
453 | module_param(ignore_acpi_limit, int, 0644); | ||
454 | MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit"); | ||
455 | #endif | ||
380 | 456 | ||
381 | MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>"); | 457 | MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>"); |
382 | MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); | 458 | MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); |