x86/cpufreq: fix turbo mode detection
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 7 May 2010 08:46:50 +0000 (09:46 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 7 May 2010 08:46:50 +0000 (09:46 +0100)
{acpi,powernow}_cpufreq_cpu_init() generally don't run on the CPU the
policy they deal with is related to, hence using cpuid() directly
works only as long as all CPUs in the system are identical (which
admittedly is commonly the case).

Further add a per-policy flag indicating the availability of
APERF/MPERF MSRs, so that globally setting the .getavg accessor won't
be a problem on heterogeneous configurations.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/acpi/cpufreq/cpufreq.c
xen/arch/x86/acpi/cpufreq/powernow.c
xen/include/acpi/cpufreq/cpufreq.h

index af591ee94fc6e983ee9dfec4685bc617dfcb4dfc..6948d7d816a348584d3a6efc2c1ee2c84f33b9de 100644 (file)
@@ -280,7 +280,7 @@ unsigned int get_measured_perf(unsigned int cpu, unsigned int flag)
         return 0;
 
     policy = cpufreq_cpu_policy[cpu];
-    if (!policy)
+    if (!policy || !policy->aperf_mperf)
         return 0;
 
     switch (flag)
@@ -377,6 +377,26 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
     return freq;
 }
 
+static void feature_detect(void *info)
+{
+    struct cpufreq_policy *policy = info;
+    unsigned int eax, ecx;
+
+    ecx = cpuid_ecx(6);
+    if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY) {
+        policy->aperf_mperf = 1;
+        acpi_cpufreq_driver.getavg = get_measured_perf;
+    }
+
+    eax = cpuid_eax(6);
+    if (eax & 0x2) {
+        policy->turbo = CPUFREQ_TURBO_ENABLED;
+        if (cpufreq_verbose)
+            printk(XENLOG_INFO "CPU%u: Turbo Mode detected and enabled\n",
+                   smp_processor_id());
+    }
+}
+
 static unsigned int check_freqs(cpumask_t mask, unsigned int freq,
                                 struct acpi_cpufreq_data *data)
 {
@@ -615,18 +635,8 @@ acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
     /* Check for APERF/MPERF support in hardware
      * also check for boost support */
-    if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6) {
-        unsigned int ecx;
-        unsigned int eax;
-        ecx = cpuid_ecx(6);
-        if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY)
-            acpi_cpufreq_driver.getavg = get_measured_perf;
-        eax = cpuid_eax(6);
-        if ( eax & 0x2 ) {
-            policy->turbo = CPUFREQ_TURBO_ENABLED;
-            printk(XENLOG_INFO "Turbo Mode detected and enabled!\n");
-        }
-    }
+    if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6)
+        on_selected_cpus(cpumask_of(cpu), feature_detect, policy, 1);
 
     /*
      * the first call to ->target() should result in us actually
index 3d34c0512bc7fee3b9f408098e623878d9fb7c36..27b53372d2e12b510eb65df5764dcf7646837ae0 100644 (file)
@@ -165,6 +165,27 @@ static int powernow_cpufreq_verify(struct cpufreq_policy *policy)
     return cpufreq_frequency_table_verify(policy, data->freq_table);
 }
 
+static void feature_detect(void *info)
+{
+    struct cpufreq_policy *policy = info;
+    unsigned int ecx, edx;
+
+    ecx = cpuid_ecx(6);
+    if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY) {
+        policy->aperf_mperf = 1;
+        powernow_cpufreq_driver.getavg = get_measured_perf;
+    }
+
+    edx = cpuid_edx(CPUID_FREQ_VOLT_CAPABILITIES);
+    if ((edx & CPB_CAPABLE) == CPB_CAPABLE) {
+        policy->turbo = CPUFREQ_TURBO_ENABLED;
+        if (cpufreq_verbose)
+            printk(XENLOG_INFO
+                   "CPU%u: Core Boost/Turbo detected and enabled\n",
+                   smp_processor_id());
+    }
+}
+
 static int powernow_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
     unsigned int i;
@@ -250,18 +271,8 @@ static int powernow_cpufreq_cpu_init(struct cpufreq_policy *policy)
     if (result)
         goto err_freqfree;
 
-    if (c->cpuid_level >= 6) {
-        unsigned int edx;
-        unsigned int ecx;
-        ecx = cpuid_ecx(6);
-        if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY)
-            powernow_cpufreq_driver.getavg = get_measured_perf;
-        edx = cpuid_edx(CPUID_FREQ_VOLT_CAPABILITIES);
-        if ((edx & CPB_CAPABLE) == CPB_CAPABLE) {
-            policy->turbo = CPUFREQ_TURBO_ENABLED;
-            printk(XENLOG_INFO "Core Boost/Turbo detected and enabled\n");
-        }
-    }
+    if (c->cpuid_level >= 6)
+        on_selected_cpus(cpumask_of(cpu), feature_detect, policy, 1);
       
     /*
      * the first call to ->target() should result in us actually
index 662c1bd3d4aa43f2e693295f13e0c6f654375303..32067e55cba66f00540efc2ed966a6e31c8cf148 100644 (file)
@@ -52,11 +52,12 @@ struct cpufreq_policy {
                                  * governors are used */
     struct cpufreq_governor     *governor;
 
-    unsigned int        resume; /* flag for cpufreq 1st run
+    bool_t              resume; /* flag for cpufreq 1st run
                                  * S3 wakeup, hotplug cpu, etc */
-    int                 turbo;  /* tristate flag: 0 for unsupported
+    s8                  turbo;  /* tristate flag: 0 for unsupported
                                  * -1 for disable, 1 for enabled
                                  * See CPUFREQ_TURBO_* below for defines */
+    bool_t              aperf_mperf; /* CPU has APERF/MPERF MSRs */
 };
 extern struct cpufreq_policy *cpufreq_cpu_policy[NR_CPUS];