Commit 8adcc0c674004c0f9467031a93dc639c2b01411f

Authored by Venkatesh Pallipadi
Committed by Dave Jones
1 parent db44aaf3a2

[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>

Showing 2 changed files with 79 additions and 2 deletions Side-by-side Diff

arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
... ... @@ -32,6 +32,7 @@
32 32 #include <linux/seq_file.h>
33 33 #include <linux/compiler.h>
34 34 #include <linux/sched.h> /* current */
  35 +#include <linux/dmi.h>
35 36 #include <asm/io.h>
36 37 #include <asm/delay.h>
37 38 #include <asm/uaccess.h>
... ... @@ -387,6 +388,33 @@
387 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 + */
  397 +static int bios_with_sw_any_bug;
  398 +
  399 +static int __init sw_any_bug_found(struct dmi_system_id *d)
  400 +{
  401 + bios_with_sw_any_bug = 1;
  402 + return 0;
  403 +}
  404 +
  405 +static 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 +
390 418 static int
391 419 acpi_cpufreq_cpu_init (
392 420 struct cpufreq_policy *policy)
393 421  
... ... @@ -422,8 +450,17 @@
422 450 * coordination is required.
423 451 */
424 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 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 465 if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
429 466 acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
... ... @@ -23,6 +23,7 @@
23 23  
24 24 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
25 25 #include <linux/acpi.h>
  26 +#include <linux/dmi.h>
26 27 #include <acpi/processor.h>
27 28 #endif
28 29  
29 30  
... ... @@ -377,7 +378,36 @@
377 378 return 0;
378 379 }
379 380  
  381 +
380 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 + */
  388 +static int bios_with_sw_any_bug;
  389 +static 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 +
  396 +static 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 +
  410 +/*
381 411 * centrino_cpu_init_acpi - register with ACPI P-States library
382 412 *
383 413 * Register with the ACPI P-States library (part of drivers/acpi/processor.c)
384 414  
385 415  
... ... @@ -398,14 +428,24 @@
398 428 dprintk(PFX "obtaining ACPI data failed\n");
399 429 return -EIO;
400 430 }
  431 +
401 432 policy->shared_type = p->shared_type;
402 433 /*
403 434 * Will let policy->cpus know about dependency only when software
404 435 * coordination is required.
405 436 */
406 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 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 450 /* verify the acpi_data */
411 451 if (p->state_count <= 1) {