Commit 732553e5 authored by Mark Langsdorf's avatar Mark Langsdorf Committed by Dave Jones

[CPUFREQ] powernow-k8: Get transition latency from ACPI _PSS table

At this time, the PowerNow! driver for K8 uses an experimentally
derived formula to calculate transition latency.  The value it
provides is orders of magnitude too large on modern systems.
This patch replaces the formula with ACPI _PSS latency values
for more accuracy and better performance.

I've tested it on two 2nd generation Opteron systems, a 3rd
generation Operton system, and a Turion X2 without seeing any
stability problems.
Signed-off-by: default avatarMark Langsdorf <mark.langsdorf@amd.com>
Signed-off-by: default avatarThomas Renninger <trenn@suse.de>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
parent 1ca3abdb
...@@ -939,10 +939,25 @@ static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) ...@@ -939,10 +939,25 @@ static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
free_cpumask_var(data->acpi_data.shared_cpu_map); free_cpumask_var(data->acpi_data.shared_cpu_map);
} }
static int get_transition_latency(struct powernow_k8_data *data)
{
int max_latency = 0;
int i;
for (i = 0; i < data->acpi_data.state_count; i++) {
int cur_latency = data->acpi_data.states[i].transition_latency
+ data->acpi_data.states[i].bus_master_latency;
if (cur_latency > max_latency)
max_latency = cur_latency;
}
/* value in usecs, needs to be in nanoseconds */
return 1000 * max_latency;
}
#else #else
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; } static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; }
static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; } static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; }
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; } static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; }
static int get_transition_latency(struct powernow_k8_data *data) { return 0; }
#endif /* CONFIG_X86_POWERNOW_K8_ACPI */ #endif /* CONFIG_X86_POWERNOW_K8_ACPI */
/* Take a frequency, and issue the fid/vid transition command */ /* Take a frequency, and issue the fid/vid transition command */
...@@ -1173,7 +1188,13 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1173,7 +1188,13 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
if (rc) { if (rc) {
goto err_out; goto err_out;
} }
} /* Take a crude guess here.
* That guess was in microseconds, so multiply with 1000 */
pol->cpuinfo.transition_latency = (
((data->rvo + 8) * data->vstable * VST_UNITS_20US) +
((1 << data->irt) * 30)) * 1000;
} else /* ACPI _PSS objects available */
pol->cpuinfo.transition_latency = get_transition_latency(data);
/* only run on specific CPU from here on */ /* only run on specific CPU from here on */
oldmask = current->cpus_allowed; oldmask = current->cpus_allowed;
...@@ -1204,11 +1225,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1204,11 +1225,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
cpumask_copy(pol->cpus, &per_cpu(cpu_core_map, pol->cpu)); cpumask_copy(pol->cpus, &per_cpu(cpu_core_map, pol->cpu));
data->available_cores = pol->cpus; data->available_cores = pol->cpus;
/* Take a crude guess here.
* That guess was in microseconds, so multiply with 1000 */
pol->cpuinfo.transition_latency = (((data->rvo + 8) * data->vstable * VST_UNITS_20US)
+ (3 * (1 << data->irt) * 10)) * 1000;
if (cpu_family == CPU_HW_PSTATE) if (cpu_family == CPU_HW_PSTATE)
pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate); pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment