diff options
author | Andreas Herrmann <andreas.herrmann3@amd.com> | 2012-01-06 15:57:55 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-13 11:17:04 -0800 |
commit | 8f44619e1e633884c5f0bfcf6ae05d7b0304cca3 (patch) | |
tree | 1629c45babfba71875df5641dbf839f66bdbe02e | |
parent | af2ff521425c83a3043af8a600b62d32443031dd (diff) | |
download | lwn-8f44619e1e633884c5f0bfcf6ae05d7b0304cca3.tar.gz lwn-8f44619e1e633884c5f0bfcf6ae05d7b0304cca3.zip |
powernow-k8: Fix indexing issue
commit a8eb28480e9b637cc78b9aa5e08612ba97e1317a upstream.
The driver uses the pstate number from the status register as index in
its table of ACPI pstates (powernow_table). This is wrong as this is
not a 1-to-1 mapping.
For example we can have _PSS information to just utilize Pstate 0 and
Pstate 4, ie.
powernow-k8: Core Performance Boosting: on.
powernow-k8: 0 : pstate 0 (2200 MHz)
powernow-k8: 1 : pstate 4 (1400 MHz)
In this example the driver's powernow_table has just 2 entries. Using
the pstate number (4) as index into this table is just plain wrong.
Signed-off-by: Andreas Herrmann <andreas.herrmann3@amd.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/cpufreq/powernow-k8.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e0329f9fa40e..ad683ec2c57e 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -54,6 +54,9 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); static int cpu_family = CPU_OPTERON; +/* array to map SW pstate number to acpi state */ +static u32 ps_to_as[8]; + /* core performance boost */ static bool cpb_capable, cpb_enabled; static struct msr __percpu *msrs; @@ -80,9 +83,9 @@ static u32 find_khz_freq_from_fid(u32 fid) } static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, - u32 pstate) + u32 pstate) { - return data[pstate].frequency; + return data[ps_to_as[pstate]].frequency; } /* Return the vco fid for an input fid @@ -926,6 +929,9 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, invalidate_entry(powernow_table, i); continue; } + + ps_to_as[index] = i; + /* Frequency may be rounded for these */ if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) || boot_cpu_data.x86 == 0x11) { @@ -1190,7 +1196,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, powernow_k8_acpi_pst_values(data, newstate); if (cpu_family == CPU_HW_PSTATE) - ret = transition_frequency_pstate(data, newstate); + ret = transition_frequency_pstate(data, + data->powernow_table[newstate].index); else ret = transition_frequency_fidvid(data, newstate); if (ret) { @@ -1203,7 +1210,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, if (cpu_family == CPU_HW_PSTATE) pol->cur = find_khz_freq_from_pstate(data->powernow_table, - newstate); + data->powernow_table[newstate].index); else pol->cur = find_khz_freq_from_fid(data->currfid); ret = 0; |