x86, cpufreq: Change powernow's CPB status immediately
authorBoris Ostrovsky <boris.ostrovsky@amd.com>
Mon, 18 Jun 2012 14:08:43 +0000 (15:08 +0100)
committerBoris Ostrovsky <boris.ostrovsky@amd.com>
Mon, 18 Jun 2012 14:08:43 +0000 (15:08 +0100)
When command to modify turbo mode (CPB on AMD processors) comes
in the actual change happens later, when P-state transition is
requested. There is no time limit on when this transition will
occur and therefore change in CPB state may take long time from
the moment when command to toggle it is issued.

This patch makes CPB mode change happen immediately when request
is made.

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@amd.com>
Committed-by: Keir Fraser <keir@xen.org>
xen/arch/x86/acpi/cpufreq/powernow.c
xen/drivers/acpi/pmstat.c
xen/drivers/cpufreq/utility.c
xen/include/acpi/cpufreq/cpufreq.h

index 69d7f94a1eaca8623b825388aec96818d93ab3c1..48b7188b8ac2bad04c419fc0546d6d11d08b676f 100644 (file)
@@ -68,16 +68,37 @@ static void transition_pstate(void *drvcmd)
     struct drv_cmd *cmd;
     cmd = (struct drv_cmd *) drvcmd;
 
-    if (cmd->turbo != CPUFREQ_TURBO_UNSUPPORTED) {
+
+    wrmsrl(MSR_PSTATE_CTRL, cmd->val);
+}
+
+static void update_cpb(void *data)
+{
+    struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
+
+    if (policy->turbo != CPUFREQ_TURBO_UNSUPPORTED) {
         uint64_t msr_content;
         rdmsrl(MSR_K8_HWCR, msr_content);
-        if (cmd->turbo == CPUFREQ_TURBO_ENABLED)
+
+        if (policy->turbo == CPUFREQ_TURBO_ENABLED)
             msr_content &= ~MSR_HWCR_CPBDIS_MASK;
         else
             msr_content |= MSR_HWCR_CPBDIS_MASK; 
+
         wrmsrl(MSR_K8_HWCR, msr_content);
     }
-    wrmsrl(MSR_PSTATE_CTRL, cmd->val);
+}
+
+static int powernow_cpufreq_update (int cpuid,
+                                    struct cpufreq_policy *policy)
+{
+    if (!cpumask_test_cpu(cpuid, &cpu_online_map))
+        return -EINVAL;
+
+    on_selected_cpus(cpumask_of(cpuid), update_cpb, policy, 1);
+
+    return 0;
 }
 
 static int powernow_cpufreq_target(struct cpufreq_policy *policy,
@@ -300,7 +321,8 @@ static struct cpufreq_driver powernow_cpufreq_driver = {
     .verify = powernow_cpufreq_verify,
     .target = powernow_cpufreq_target,
     .init   = powernow_cpufreq_cpu_init,
-    .exit   = powernow_cpufreq_cpu_exit
+    .exit   = powernow_cpufreq_cpu_exit,
+    .update = powernow_cpufreq_update
 };
 
 unsigned int __init powernow_register_driver()
index dbc1c44a613f3ff19626e7cb96602e3e6b0e8e1d..8788f01f7038c79e3d612cb2a29dfaf726fee433 100644 (file)
@@ -494,13 +494,13 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
 
     case XEN_SYSCTL_pm_op_enable_turbo:
     {
-        cpufreq_enable_turbo(op->cpuid);
+        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_ENABLED);
         break;
     }
 
     case XEN_SYSCTL_pm_op_disable_turbo:
     {
-        cpufreq_disable_turbo(op->cpuid);
+        ret = cpufreq_update_turbo(op->cpuid, CPUFREQ_TURBO_DISABLED);
         break;
     }
 
index fad54651b31a76637b8748411c48f00679002b3b..3dd70e271634aade4d7cd556c8472509e922dab7 100644 (file)
@@ -390,24 +390,39 @@ int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag)
     return policy->cur;
 }
 
-void cpufreq_enable_turbo(int cpuid)
+int cpufreq_update_turbo(int cpuid, int new_state)
 {
     struct cpufreq_policy *policy;
+    int curr_state;
+    int ret = 0;
+
+    if (new_state != CPUFREQ_TURBO_ENABLED &&
+        new_state != CPUFREQ_TURBO_DISABLED)
+        return -EINVAL;
 
     policy = per_cpu(cpufreq_cpu_policy, cpuid);
-    if (policy && policy->turbo != CPUFREQ_TURBO_UNSUPPORTED)
-        policy->turbo = CPUFREQ_TURBO_ENABLED;
-}
+    if (!policy)
+        return -EACCES;
 
-void cpufreq_disable_turbo(int cpuid)
-{
-    struct cpufreq_policy *policy;
+    if (policy->turbo == CPUFREQ_TURBO_UNSUPPORTED)
+        return -EOPNOTSUPP;
 
-    policy = per_cpu(cpufreq_cpu_policy, cpuid);
-    if (policy && policy->turbo != CPUFREQ_TURBO_UNSUPPORTED)
-        policy->turbo = CPUFREQ_TURBO_DISABLED;
+    curr_state = policy->turbo;
+    if (curr_state == new_state)
+        return 0;
+
+    policy->turbo = new_state;
+    if (cpufreq_driver->update)
+    {
+        ret = cpufreq_driver->update(cpuid, policy);
+        if (ret)
+            policy->turbo = curr_state;
+    }
+
+    return ret;
 }
 
+
 int cpufreq_get_turbo_status(int cpuid)
 {
     struct cpufreq_policy *policy;
index 1798b9bb196f603fba73fc3dfe0775565fb6f536..f96c3e4ccf2aaf46889a9774d76deed2d93d4783 100644 (file)
@@ -124,8 +124,7 @@ extern int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag);
 #define CPUFREQ_TURBO_UNSUPPORTED   0
 #define CPUFREQ_TURBO_ENABLED       1
 
-extern void cpufreq_enable_turbo(int cpuid);
-extern void cpufreq_disable_turbo(int cpuid);
+extern int cpufreq_update_turbo(int cpuid, int new_state);
 extern int cpufreq_get_turbo_status(int cpuid);
 
 static __inline__ int 
@@ -146,6 +145,7 @@ struct cpufreq_driver {
     char   name[CPUFREQ_NAME_LEN];
     int    (*init)(struct cpufreq_policy *policy);
     int    (*verify)(struct cpufreq_policy *policy);
+    int    (*update)(int cpuid, struct cpufreq_policy *policy);
     int    (*target)(struct cpufreq_policy *policy,
                      unsigned int target_freq,
                      unsigned int relation);