Pull button into test branch
[linux-drm-fsl-dcu.git] / arch / i386 / kernel / cpu / cpufreq / speedstep-centrino.c
index b77f1358bd79e341bd3d2a9a8606819bb1a1f01a..5113e923163404c2b74b9718d24631b2aafec95d 100644 (file)
@@ -23,6 +23,7 @@
 
 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <acpi/processor.h>
 #endif
 
@@ -35,6 +36,7 @@
 
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
 
+#define INTEL_MSR_RANGE        (0xffff)
 
 struct cpu_id
 {
@@ -377,6 +379,35 @@ static int centrino_cpu_early_init_acpi(void)
        return 0;
 }
 
+
+#ifdef CONFIG_SMP
+/*
+ * Some BIOSes do SW_ANY coordination internally, either set it up in hw
+ * or do it in BIOS firmware and won't inform about it to OS. If not
+ * detected, this has a side effect of making CPU run at a different speed
+ * than OS intended it to run at. Detect it and handle it cleanly.
+ */
+static int bios_with_sw_any_bug;
+static int sw_any_bug_found(struct dmi_system_id *d)
+{
+       bios_with_sw_any_bug = 1;
+       return 0;
+}
+
+static struct dmi_system_id sw_any_bug_dmi_table[] = {
+       {
+               .callback = sw_any_bug_found,
+               .ident = "Supermicro Server X6DLP",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "080010"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
+               },
+       },
+       { }
+};
+#endif
+
 /*
  * centrino_cpu_init_acpi - register with ACPI P-States library
  *
@@ -398,14 +429,24 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
                dprintk(PFX "obtaining ACPI data failed\n");
                return -EIO;
        }
+
        policy->shared_type = p->shared_type;
        /*
         * Will let policy->cpus know about dependency only when software 
         * coordination is required.
         */
        if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
-           policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+           policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
                policy->cpus = p->shared_cpu_map;
+       }
+
+#ifdef CONFIG_SMP
+       dmi_check_system(sw_any_bug_dmi_table);
+       if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
+               policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+               policy->cpus = cpu_core_map[cpu];
+       }
+#endif
 
        /* verify the acpi_data */
        if (p->state_count <= 1) {
@@ -423,8 +464,9 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
        }
 
        for (i=0; i<p->state_count; i++) {
-               if (p->states[i].control != p->states[i].status) {
-                       dprintk("Different control (%llu) and status values (%llu)\n",
+               if ((p->states[i].control & INTEL_MSR_RANGE) !=
+                   (p->states[i].status & INTEL_MSR_RANGE)) {
+                       dprintk("Different MSR bits in control (%llu) and status (%llu)\n",
                                p->states[i].control, p->states[i].status);
                        result = -EINVAL;
                        goto err_unreg;
@@ -460,7 +502,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
         }
 
         for (i=0; i<p->state_count; i++) {
-               centrino_model[cpu]->op_points[i].index = p->states[i].control;
+               centrino_model[cpu]->op_points[i].index = p->states[i].control & INTEL_MSR_RANGE;
                centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
                dprintk("adding state %i with frequency %u and control value %04x\n", 
                        i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
@@ -491,6 +533,9 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
 
        /* notify BIOS that we exist */
        acpi_processor_notify_smm(THIS_MODULE);
+       printk("speedstep-centrino with X86_SPEEDSTEP_CENTRINO_ACPI"
+                       "config is deprecated.\n "
+                       "Use X86_ACPI_CPUFREQ (acpi-cpufreq instead.\n" );
 
        return 0;