diff options
Diffstat (limited to 'drivers/acpi/processor_perflib.c')
-rw-r--r-- | drivers/acpi/processor_perflib.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b4749969c6b4..dc98f7a6f2c4 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | #endif | 40 | #endif |
41 | #include <asm/cpufeature.h> | ||
41 | 42 | ||
42 | #include <acpi/acpi_bus.h> | 43 | #include <acpi/acpi_bus.h> |
43 | #include <acpi/processor.h> | 44 | #include <acpi/processor.h> |
@@ -64,15 +65,21 @@ static DEFINE_MUTEX(performance_mutex); | |||
64 | * policy is adjusted accordingly. | 65 | * policy is adjusted accordingly. |
65 | */ | 66 | */ |
66 | 67 | ||
67 | static unsigned int ignore_ppc = 0; | 68 | /* ignore_ppc: |
68 | module_param(ignore_ppc, uint, 0644); | 69 | * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet |
70 | * ignore _PPC | ||
71 | * 0 -> cpufreq low level drivers initialized -> consider _PPC values | ||
72 | * 1 -> ignore _PPC totally -> forced by user through boot param | ||
73 | */ | ||
74 | static int ignore_ppc = -1; | ||
75 | module_param(ignore_ppc, int, 0644); | ||
69 | MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ | 76 | MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ |
70 | "limited by BIOS, this should help"); | 77 | "limited by BIOS, this should help"); |
71 | 78 | ||
72 | #define PPC_REGISTERED 1 | 79 | #define PPC_REGISTERED 1 |
73 | #define PPC_IN_USE 2 | 80 | #define PPC_IN_USE 2 |
74 | 81 | ||
75 | static int acpi_processor_ppc_status = 0; | 82 | static int acpi_processor_ppc_status; |
76 | 83 | ||
77 | static int acpi_processor_ppc_notifier(struct notifier_block *nb, | 84 | static int acpi_processor_ppc_notifier(struct notifier_block *nb, |
78 | unsigned long event, void *data) | 85 | unsigned long event, void *data) |
@@ -81,13 +88,18 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, | |||
81 | struct acpi_processor *pr; | 88 | struct acpi_processor *pr; |
82 | unsigned int ppc = 0; | 89 | unsigned int ppc = 0; |
83 | 90 | ||
84 | if (ignore_ppc) | 91 | if (event == CPUFREQ_START && ignore_ppc <= 0) { |
92 | ignore_ppc = 0; | ||
85 | return 0; | 93 | return 0; |
94 | } | ||
86 | 95 | ||
87 | mutex_lock(&performance_mutex); | 96 | if (ignore_ppc) |
97 | return 0; | ||
88 | 98 | ||
89 | if (event != CPUFREQ_INCOMPATIBLE) | 99 | if (event != CPUFREQ_INCOMPATIBLE) |
90 | goto out; | 100 | return 0; |
101 | |||
102 | mutex_lock(&performance_mutex); | ||
91 | 103 | ||
92 | pr = per_cpu(processors, policy->cpu); | 104 | pr = per_cpu(processors, policy->cpu); |
93 | if (!pr || !pr->performance) | 105 | if (!pr || !pr->performance) |
@@ -115,7 +127,7 @@ static struct notifier_block acpi_ppc_notifier_block = { | |||
115 | static int acpi_processor_get_platform_limit(struct acpi_processor *pr) | 127 | static int acpi_processor_get_platform_limit(struct acpi_processor *pr) |
116 | { | 128 | { |
117 | acpi_status status = 0; | 129 | acpi_status status = 0; |
118 | unsigned long ppc = 0; | 130 | unsigned long long ppc = 0; |
119 | 131 | ||
120 | 132 | ||
121 | if (!pr) | 133 | if (!pr) |
@@ -323,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) | |||
323 | acpi_status status = AE_OK; | 335 | acpi_status status = AE_OK; |
324 | acpi_handle handle = NULL; | 336 | acpi_handle handle = NULL; |
325 | 337 | ||
326 | |||
327 | if (!pr || !pr->performance || !pr->handle) | 338 | if (!pr || !pr->performance || !pr->handle) |
328 | return -EINVAL; | 339 | return -EINVAL; |
329 | 340 | ||
@@ -336,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) | |||
336 | 347 | ||
337 | result = acpi_processor_get_performance_control(pr); | 348 | result = acpi_processor_get_performance_control(pr); |
338 | if (result) | 349 | if (result) |
339 | return result; | 350 | goto update_bios; |
340 | 351 | ||
341 | result = acpi_processor_get_performance_states(pr); | 352 | result = acpi_processor_get_performance_states(pr); |
342 | if (result) | 353 | if (result) |
343 | return result; | 354 | goto update_bios; |
344 | 355 | ||
345 | return 0; | 356 | return 0; |
357 | |||
358 | /* | ||
359 | * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that | ||
360 | * the BIOS is older than the CPU and does not know its frequencies | ||
361 | */ | ||
362 | update_bios: | ||
363 | if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){ | ||
364 | if(boot_cpu_has(X86_FEATURE_EST)) | ||
365 | printk(KERN_WARNING FW_BUG "BIOS needs update for CPU " | ||
366 | "frequency support\n"); | ||
367 | } | ||
368 | return result; | ||
346 | } | 369 | } |
347 | 370 | ||
348 | int acpi_processor_notify_smm(struct module *calling_module) | 371 | int acpi_processor_notify_smm(struct module *calling_module) |
@@ -513,13 +536,13 @@ static int acpi_processor_get_psd(struct acpi_processor *pr) | |||
513 | 536 | ||
514 | psd = buffer.pointer; | 537 | psd = buffer.pointer; |
515 | if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { | 538 | if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { |
516 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | 539 | printk(KERN_ERR PREFIX "Invalid _PSD data\n"); |
517 | result = -EFAULT; | 540 | result = -EFAULT; |
518 | goto end; | 541 | goto end; |
519 | } | 542 | } |
520 | 543 | ||
521 | if (psd->package.count != 1) { | 544 | if (psd->package.count != 1) { |
522 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | 545 | printk(KERN_ERR PREFIX "Invalid _PSD data\n"); |
523 | result = -EFAULT; | 546 | result = -EFAULT; |
524 | goto end; | 547 | goto end; |
525 | } | 548 | } |
@@ -532,19 +555,19 @@ static int acpi_processor_get_psd(struct acpi_processor *pr) | |||
532 | status = acpi_extract_package(&(psd->package.elements[0]), | 555 | status = acpi_extract_package(&(psd->package.elements[0]), |
533 | &format, &state); | 556 | &format, &state); |
534 | if (ACPI_FAILURE(status)) { | 557 | if (ACPI_FAILURE(status)) { |
535 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | 558 | printk(KERN_ERR PREFIX "Invalid _PSD data\n"); |
536 | result = -EFAULT; | 559 | result = -EFAULT; |
537 | goto end; | 560 | goto end; |
538 | } | 561 | } |
539 | 562 | ||
540 | if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { | 563 | if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { |
541 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); | 564 | printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n"); |
542 | result = -EFAULT; | 565 | result = -EFAULT; |
543 | goto end; | 566 | goto end; |
544 | } | 567 | } |
545 | 568 | ||
546 | if (pdomain->revision != ACPI_PSD_REV0_REVISION) { | 569 | if (pdomain->revision != ACPI_PSD_REV0_REVISION) { |
547 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); | 570 | printk(KERN_ERR PREFIX "Unknown _PSD:revision\n"); |
548 | result = -EFAULT; | 571 | result = -EFAULT; |
549 | goto end; | 572 | goto end; |
550 | } | 573 | } |