aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu
diff options
context:
space:
mode:
authorVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>2006-09-01 17:02:24 -0400
committerDave Jones <davej@redhat.com>2006-09-05 17:28:42 -0400
commit8adcc0c674004c0f9467031a93dc639c2b01411f (patch)
treec927083c7ad6be78749ad0ecc2fff1f018a7dd5f /arch/i386/kernel/cpu
parentdb44aaf3a2f599163c53ce96658aca688b3466f0 (diff)
[CPUFREQ] Workaround for BIOS bug in software coordination of frequency
Some buggy BIOSes do a "software any" kind of coordination without telling about it to OS. So, when OS sets frequency on one CPU on these platforms, it will also impact all the other logical CPUs that are in the same power domain. Attached patch is a workaround for those buggy BIOSes. Patch should be a noop on the normal non-buggy platforms. Applies over previously sent acpi-cpufreq and software coordination bug fix patch Signed-off-by: Denis Sadykov <denis.m.sadykov@intel.com> Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'arch/i386/kernel/cpu')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c39
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c42
2 files changed, 79 insertions, 2 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index e6ea00edcb54..ea19d091fd41 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -32,6 +32,7 @@
32#include <linux/seq_file.h> 32#include <linux/seq_file.h>
33#include <linux/compiler.h> 33#include <linux/compiler.h>
34#include <linux/sched.h> /* current */ 34#include <linux/sched.h> /* current */
35#include <linux/dmi.h>
35#include <asm/io.h> 36#include <asm/io.h>
36#include <asm/delay.h> 37#include <asm/delay.h>
37#include <asm/uaccess.h> 38#include <asm/uaccess.h>
@@ -387,6 +388,33 @@ static int acpi_cpufreq_early_init_acpi(void)
387 return acpi_processor_preregister_performance(acpi_perf_data); 388 return acpi_processor_preregister_performance(acpi_perf_data);
388} 389}
389 390
391/*
392 * Some BIOSes do SW_ANY coordination internally, either set it up in hw
393 * or do it in BIOS firmware and won't inform about it to OS. If not
394 * detected, this has a side effect of making CPU run at a different speed
395 * than OS intended it to run at. Detect it and handle it cleanly.
396 */
397static int bios_with_sw_any_bug;
398
399static int __init sw_any_bug_found(struct dmi_system_id *d)
400{
401 bios_with_sw_any_bug = 1;
402 return 0;
403}
404
405static struct dmi_system_id __initdata sw_any_bug_dmi_table[] = {
406 {
407 .callback = sw_any_bug_found,
408 .ident = "Supermicro Server X6DLP",
409 .matches = {
410 DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
411 DMI_MATCH(DMI_BIOS_VERSION, "080010"),
412 DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
413 },
414 },
415 { }
416};
417
390static int 418static int
391acpi_cpufreq_cpu_init ( 419acpi_cpufreq_cpu_init (
392 struct cpufreq_policy *policy) 420 struct cpufreq_policy *policy)
@@ -422,8 +450,17 @@ acpi_cpufreq_cpu_init (
422 * coordination is required. 450 * coordination is required.
423 */ 451 */
424 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || 452 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
425 policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 453 policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
426 policy->cpus = perf->shared_cpu_map; 454 policy->cpus = perf->shared_cpu_map;
455 }
456
457#ifdef CONFIG_SMP
458 dmi_check_system(sw_any_bug_dmi_table);
459 if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
460 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
461 policy->cpus = cpu_core_map[cpu];
462 }
463#endif
427 464
428 if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { 465 if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
429 acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; 466 acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index b77f1358bd79..dba6bb28d298 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -23,6 +23,7 @@
23 23
24#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI 24#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
25#include <linux/acpi.h> 25#include <linux/acpi.h>
26#include <linux/dmi.h>
26#include <acpi/processor.h> 27#include <acpi/processor.h>
27#endif 28#endif
28 29
@@ -377,6 +378,35 @@ static int centrino_cpu_early_init_acpi(void)
377 return 0; 378 return 0;
378} 379}
379 380
381
382/*
383 * Some BIOSes do SW_ANY coordination internally, either set it up in hw
384 * or do it in BIOS firmware and won't inform about it to OS. If not
385 * detected, this has a side effect of making CPU run at a different speed
386 * than OS intended it to run at. Detect it and handle it cleanly.
387 */
388static int bios_with_sw_any_bug;
389static int __init sw_any_bug_found(struct dmi_system_id *d)
390{
391 bios_with_sw_any_bug = 1;
392 return 0;
393}
394
395
396static struct dmi_system_id __initdata sw_any_bug_dmi_table[] = {
397 {
398 .callback = sw_any_bug_found,
399 .ident = "Supermicro Server X6DLP",
400 .matches = {
401 DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
402 DMI_MATCH(DMI_BIOS_VERSION, "080010"),
403 DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
404 },
405 },
406 { }
407};
408
409
380/* 410/*
381 * centrino_cpu_init_acpi - register with ACPI P-States library 411 * centrino_cpu_init_acpi - register with ACPI P-States library
382 * 412 *
@@ -398,14 +428,24 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
398 dprintk(PFX "obtaining ACPI data failed\n"); 428 dprintk(PFX "obtaining ACPI data failed\n");
399 return -EIO; 429 return -EIO;
400 } 430 }
431
401 policy->shared_type = p->shared_type; 432 policy->shared_type = p->shared_type;
402 /* 433 /*
403 * Will let policy->cpus know about dependency only when software 434 * Will let policy->cpus know about dependency only when software
404 * coordination is required. 435 * coordination is required.
405 */ 436 */
406 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || 437 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
407 policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 438 policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
408 policy->cpus = p->shared_cpu_map; 439 policy->cpus = p->shared_cpu_map;
440 }
441
442#ifdef CONFIG_SMP
443 dmi_check_system(sw_any_bug_dmi_table);
444 if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
445 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
446 policy->cpus = cpu_core_map[cpu];
447 }
448#endif
409 449
410 /* verify the acpi_data */ 450 /* verify the acpi_data */
411 if (p->state_count <= 1) { 451 if (p->state_count <= 1) {