diff options
Diffstat (limited to 'drivers/acpi/processor_perflib.c')
-rw-r--r-- | drivers/acpi/processor_perflib.c | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60e543d3234e..3a73a93596e8 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/cpufreq.h> | 32 | #include <linux/cpufreq.h> |
33 | #include <linux/slab.h> | ||
33 | 34 | ||
34 | #ifdef CONFIG_X86 | 35 | #ifdef CONFIG_X86 |
35 | #include <asm/cpufeature.h> | 36 | #include <asm/cpufeature.h> |
@@ -39,6 +40,8 @@ | |||
39 | #include <acpi/acpi_drivers.h> | 40 | #include <acpi/acpi_drivers.h> |
40 | #include <acpi/processor.h> | 41 | #include <acpi/processor.h> |
41 | 42 | ||
43 | #define PREFIX "ACPI: " | ||
44 | |||
42 | #define ACPI_PROCESSOR_CLASS "processor" | 45 | #define ACPI_PROCESSOR_CLASS "processor" |
43 | #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" | 46 | #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" |
44 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | 47 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
@@ -150,21 +153,78 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) | |||
150 | return 0; | 153 | return 0; |
151 | } | 154 | } |
152 | 155 | ||
153 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr) | 156 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 |
157 | /* | ||
158 | * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status | ||
159 | * @handle: ACPI processor handle | ||
160 | * @status: the status code of _PPC evaluation | ||
161 | * 0: success. OSPM is now using the performance state specificed. | ||
162 | * 1: failure. OSPM has not changed the number of P-states in use | ||
163 | */ | ||
164 | static void acpi_processor_ppc_ost(acpi_handle handle, int status) | ||
165 | { | ||
166 | union acpi_object params[2] = { | ||
167 | {.type = ACPI_TYPE_INTEGER,}, | ||
168 | {.type = ACPI_TYPE_INTEGER,}, | ||
169 | }; | ||
170 | struct acpi_object_list arg_list = {2, params}; | ||
171 | acpi_handle temp; | ||
172 | |||
173 | params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; | ||
174 | params[1].integer.value = status; | ||
175 | |||
176 | /* when there is no _OST , skip it */ | ||
177 | if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) | ||
178 | return; | ||
179 | |||
180 | acpi_evaluate_object(handle, "_OST", &arg_list, NULL); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) | ||
154 | { | 185 | { |
155 | int ret; | 186 | int ret; |
156 | 187 | ||
157 | if (ignore_ppc) | 188 | if (ignore_ppc) { |
189 | /* | ||
190 | * Only when it is notification event, the _OST object | ||
191 | * will be evaluated. Otherwise it is skipped. | ||
192 | */ | ||
193 | if (event_flag) | ||
194 | acpi_processor_ppc_ost(pr->handle, 1); | ||
158 | return 0; | 195 | return 0; |
196 | } | ||
159 | 197 | ||
160 | ret = acpi_processor_get_platform_limit(pr); | 198 | ret = acpi_processor_get_platform_limit(pr); |
161 | 199 | /* | |
200 | * Only when it is notification event, the _OST object | ||
201 | * will be evaluated. Otherwise it is skipped. | ||
202 | */ | ||
203 | if (event_flag) { | ||
204 | if (ret < 0) | ||
205 | acpi_processor_ppc_ost(pr->handle, 1); | ||
206 | else | ||
207 | acpi_processor_ppc_ost(pr->handle, 0); | ||
208 | } | ||
162 | if (ret < 0) | 209 | if (ret < 0) |
163 | return (ret); | 210 | return (ret); |
164 | else | 211 | else |
165 | return cpufreq_update_policy(pr->id); | 212 | return cpufreq_update_policy(pr->id); |
166 | } | 213 | } |
167 | 214 | ||
215 | int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) | ||
216 | { | ||
217 | struct acpi_processor *pr; | ||
218 | |||
219 | pr = per_cpu(processors, cpu); | ||
220 | if (!pr || !pr->performance || !pr->performance->state_count) | ||
221 | return -ENODEV; | ||
222 | *limit = pr->performance->states[pr->performance_platform_limit]. | ||
223 | core_frequency * 1000; | ||
224 | return 0; | ||
225 | } | ||
226 | EXPORT_SYMBOL(acpi_processor_get_bios_limit); | ||
227 | |||
168 | void acpi_processor_ppc_init(void) | 228 | void acpi_processor_ppc_init(void) |
169 | { | 229 | { |
170 | if (!cpufreq_register_notifier | 230 | if (!cpufreq_register_notifier |
@@ -354,7 +414,11 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) | |||
354 | if (result) | 414 | if (result) |
355 | goto update_bios; | 415 | goto update_bios; |
356 | 416 | ||
357 | return 0; | 417 | /* We need to call _PPC once when cpufreq starts */ |
418 | if (ignore_ppc != 1) | ||
419 | result = acpi_processor_get_platform_limit(pr); | ||
420 | |||
421 | return result; | ||
358 | 422 | ||
359 | /* | 423 | /* |
360 | * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that | 424 | * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that |
@@ -383,8 +447,8 @@ int acpi_processor_notify_smm(struct module *calling_module) | |||
383 | if (!try_module_get(calling_module)) | 447 | if (!try_module_get(calling_module)) |
384 | return -EINVAL; | 448 | return -EINVAL; |
385 | 449 | ||
386 | /* is_done is set to negative if an error occured, | 450 | /* is_done is set to negative if an error occurred, |
387 | * and to postitive if _no_ error occured, but SMM | 451 | * and to postitive if _no_ error occurred, but SMM |
388 | * was already notified. This avoids double notification | 452 | * was already notified. This avoids double notification |
389 | * which might lead to unexpected results... | 453 | * which might lead to unexpected results... |
390 | */ | 454 | */ |
@@ -498,7 +562,7 @@ end: | |||
498 | } | 562 | } |
499 | 563 | ||
500 | int acpi_processor_preregister_performance( | 564 | int acpi_processor_preregister_performance( |
501 | struct acpi_processor_performance *performance) | 565 | struct acpi_processor_performance __percpu *performance) |
502 | { | 566 | { |
503 | int count, count_target; | 567 | int count, count_target; |
504 | int retval = 0; | 568 | int retval = 0; |
@@ -509,7 +573,7 @@ int acpi_processor_preregister_performance( | |||
509 | struct acpi_processor *match_pr; | 573 | struct acpi_processor *match_pr; |
510 | struct acpi_psd_package *match_pdomain; | 574 | struct acpi_psd_package *match_pdomain; |
511 | 575 | ||
512 | if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL)) | 576 | if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)) |
513 | return -ENOMEM; | 577 | return -ENOMEM; |
514 | 578 | ||
515 | mutex_lock(&performance_mutex); | 579 | mutex_lock(&performance_mutex); |
@@ -556,7 +620,6 @@ int acpi_processor_preregister_performance( | |||
556 | * Now that we have _PSD data from all CPUs, lets setup P-state | 620 | * Now that we have _PSD data from all CPUs, lets setup P-state |
557 | * domain info. | 621 | * domain info. |
558 | */ | 622 | */ |
559 | cpumask_clear(covered_cpus); | ||
560 | for_each_possible_cpu(i) { | 623 | for_each_possible_cpu(i) { |
561 | pr = per_cpu(processors, i); | 624 | pr = per_cpu(processors, i); |
562 | if (!pr) | 625 | if (!pr) |