On Tue, Oct 09, 2007 at 07:41:25PM -0400, Dave Jones wrote:
> On Tue, Oct 09, 2007 at 03:43:20PM -0500, Mark Langsdorf wrote:
>  > This patch should apply cleanly to the 2.6.23-rc8-mm2 kernel.  It changes 
>  > the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom,
>  > and later processors to match the architectual pstate driver described
>  > in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18.  The
>  > initial implementation of the hardware pstate driver for PowerNow!
>  > used some processor-version specific features, and would not be
>  > maintainable in the long term as the processor features changed.
>  > This architectural driver should work on all future AMD processors.
>  
> Has this been tested on older implementations of powernow yet?
> I'm happy to merge this and give it some time in -mm, before it
> goes to mainline, but if no-one is testing on those older
> opterons/turions etc then we're not going to know we regressed
> until its too late.   If it hasn't been tested yet, any chance
> you can scrounge some up at AMD and give it a spin just to be sure?


I'd like to see this driver in the next kernel release.

So I have done some tests with this code - based on kernel version 2.6.23.
I have tested it on Athlon 64 X2, Athlon 64, Turion X2 and some other parts
(e.g.family 0x10) and with different cpufreq governors.
I did not observe any problems with this driver update.
Behaviour is the same as before.

I just had to fix one minor compile error.

So please consider to add the attached patch for 2.6.24.
Patch is against current Linus' git tree. This means the patch
"[CPUFREQ] Support different families in fid/did to frequency conversion"
which is contained in the cpufreq.git should be ommitted. The issue
fixed with that patch is solved with this driver update, too.

If you need a patch against the x86 tree I can provide one as well.


Thanks and Regards,

Andreas
--

[PATCH] architectural pstate driver for powernow-k8

This changes the powernow-k8 driver code that deals with 3rd
generation Opteron, Phenom, and later processors to match the
architectual pstate driver described in the AMD64 Architecture
Programmer's Manual Volume 2 Chapter The initial implementation of the
hardware pstate driver for PowerNow!  used some processor-version
specific features, and would not be maintainable in the long term as
the processor features changed.  This architectural driver should work
on all future AMD processors.

Signed-off-by: Mark Langsdorf <[EMAIL PROTECTED]>
Signed-off-by: Andreas Herrmann3 <[EMAIL PROTECTED]>
---
 arch/i386/kernel/cpu/cpufreq/powernow-k8.c |   85 ++++++++--------------------
 arch/i386/kernel/cpu/cpufreq/powernow-k8.h |   20 ++-----
 2 files changed, 29 insertions(+), 76 deletions(-)

diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 
b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index 34ed53a..ef8be4a 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -46,7 +46,7 @@
 
 #define PFX "powernow-k8: "
 #define BFX PFX "BIOS error: "
-#define VERSION "version 2.00.00"
+#define VERSION "version 2.20.00"
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
@@ -73,29 +73,9 @@ static u32 find_khz_freq_from_fid(u32 fid)
        return 1000 * find_freq_from_fid(fid);
 }
 
-/* Return a frequency in MHz, given an input fid and did */
-static u32 find_freq_from_fiddid(u32 fid, u32 did)
+static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, u32 
pstate)
 {
-       return 100 * (fid + 0x10) >> did;
-}
-
-static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
-{
-       return 1000 * find_freq_from_fiddid(fid, did);
-}
-
-static u32 find_fid_from_pstate(u32 pstate)
-{
-       u32 hi, lo;
-       rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
-       return lo & HW_PSTATE_FID_MASK;
-}
-
-static u32 find_did_from_pstate(u32 pstate)
-{
-       u32 hi, lo;
-       rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
-       return (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
+       return data[pstate].frequency;
 }
 
 /* Return the vco fid for an input fid
@@ -139,9 +119,7 @@ static int query_current_values_with_pending_wait(struct 
powernow_k8_data *data)
        if (cpu_family == CPU_HW_PSTATE) {
                rdmsr(MSR_PSTATE_STATUS, lo, hi);
                i = lo & HW_PSTATE_MASK;
-               rdmsr(MSR_PSTATE_DEF_BASE + i, lo, hi);
-               data->currfid = lo & HW_PSTATE_FID_MASK;
-               data->currdid = (lo & HW_PSTATE_DID_MASK) >> 
HW_PSTATE_DID_SHIFT;
+               data->currpstate = i;
                return 0;
        }
        do {
@@ -292,7 +270,7 @@ static int decrease_vid_code_by_step(struct 
powernow_k8_data *data, u32 reqvid,
 static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
 {
        wrmsr(MSR_PSTATE_CTRL, pstate, 0);
-       data->currfid = find_fid_from_pstate(pstate);
+       data->currpstate = pstate;
        return 0;
 }
 
@@ -842,17 +820,20 @@ err_out:
 static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct 
cpufreq_frequency_table *powernow_table)
 {
        int i;
+       u32 hi = 0, lo = 0;
+       rdmsr(MSR_PSTATE_CUR_LIMIT, hi, lo);
+       data->max_hw_pstate = (hi & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
 
        for (i = 0; i < data->acpi_data.state_count; i++) {
                u32 index;
                u32 hi = 0, lo = 0;
-               u32 fid;
-               u32 did;
 
                index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
-               if (index > MAX_HW_PSTATE) {
+               if (index > data->max_hw_pstate) {
                        printk(KERN_ERR PFX "invalid pstate %d - bad value 
%d.\n", i, index);
                        printk(KERN_ERR PFX "Please report to BIOS 
manufacturer\n");
+                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       continue;
                }
                rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
                if (!(hi & HW_PSTATE_VALID_MASK)) {
@@ -861,22 +842,9 @@ static int fill_powernow_table_pstate(struct 
powernow_k8_data *data, struct cpuf
                        continue;
                }
 
-               fid = lo & HW_PSTATE_FID_MASK;
-               did = (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
+               powernow_table[i].index = index;
 
-               dprintk("   %d : fid 0x%x, did 0x%x\n", index, fid, did);
-
-               powernow_table[i].index = index | (fid << HW_FID_INDEX_SHIFT) | 
(did << HW_DID_INDEX_SHIFT);
-
-               powernow_table[i].frequency = find_khz_freq_from_fiddid(fid, 
did);
-
-               if (powernow_table[i].frequency != 
(data->acpi_data.states[i].core_frequency * 1000)) {
-                       printk(KERN_INFO PFX "invalid freq entries %u kHz vs. 
%u kHz\n",
-                               powernow_table[i].frequency,
-                               (unsigned int) 
(data->acpi_data.states[i].core_frequency * 1000));
-                       powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
-                       continue;
-               }
+               powernow_table[i].frequency = 
data->acpi_data.states[i].core_frequency * 1000;
        }
        return 0;
 }
@@ -1017,8 +985,6 @@ static int transition_frequency_fidvid(struct 
powernow_k8_data *data, unsigned i
 /* Take a frequency, and issue the hardware pstate transition command */
 static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned 
int index)
 {
-       u32 fid = 0;
-       u32 did = 0;
        u32 pstate = 0;
        int res, i;
        struct cpufreq_freqs freqs;
@@ -1027,12 +993,10 @@ static int transition_frequency_pstate(struct 
powernow_k8_data *data, unsigned i
 
        /* get fid did for hardware pstate transition */
        pstate = index & HW_PSTATE_MASK;
-       if (pstate > MAX_HW_PSTATE)
+       if (pstate > data->max_hw_pstate);
                return 0;
-       fid = (index & HW_FID_INDEX_MASK) >> HW_FID_INDEX_SHIFT;
-       did = (index & HW_DID_INDEX_MASK) >> HW_DID_INDEX_SHIFT;
-       freqs.old = find_khz_freq_from_fiddid(data->currfid, data->currdid);
-       freqs.new = find_khz_freq_from_fiddid(fid, did);
+       freqs.old = find_khz_freq_from_pstate(data->powernow_table, 
data->currpstate);
+       freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
 
        for_each_cpu_mask(i, *(data->available_cores)) {
                freqs.cpu = i;
@@ -1040,9 +1004,7 @@ static int transition_frequency_pstate(struct 
powernow_k8_data *data, unsigned i
        }
 
        res = transition_pstate(data, pstate);
-       data->currfid = find_fid_from_pstate(pstate);
-       data->currdid = find_did_from_pstate(pstate);
-       freqs.new = find_khz_freq_from_fiddid(data->currfid, data->currdid);
+       freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
 
        for_each_cpu_mask(i, *(data->available_cores)) {
                freqs.cpu = i;
@@ -1088,8 +1050,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, 
unsigned targfreq, unsi
                goto err_out;
 
        if (cpu_family == CPU_HW_PSTATE)
-               dprintk("targ: curr fid 0x%x, did 0x%x\n",
-                       data->currfid, data->currdid);
+               dprintk("cpu_init done, current pstate 0x%x\n",
+                       data->currpstate);
        else {
                dprintk("targ: curr fid 0x%x, vid 0x%x\n",
                data->currfid, data->currvid);
@@ -1121,7 +1083,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, 
unsigned targfreq, unsi
        mutex_unlock(&fidvid_mutex);
 
        if (cpu_family == CPU_HW_PSTATE)
-               pol->cur = find_khz_freq_from_fiddid(data->currfid, 
data->currdid);
+               pol->cur = find_khz_freq_from_pstate(data->powernow_table, 
newstate);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
        ret = 0;
@@ -1221,7 +1183,7 @@ static int __cpuinit powernowk8_cpu_init(struct 
cpufreq_policy *pol)
            + (3 * (1 << data->irt) * 10)) * 1000;
 
        if (cpu_family == CPU_HW_PSTATE)
-               pol->cur = find_khz_freq_from_fiddid(data->currfid, 
data->currdid);
+               pol->cur = find_khz_freq_from_pstate(data->powernow_table, 
data->currpstate);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
        dprintk("policy current frequency %d kHz\n", pol->cur);
@@ -1238,8 +1200,7 @@ static int __cpuinit powernowk8_cpu_init(struct 
cpufreq_policy *pol)
        cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
 
        if (cpu_family == CPU_HW_PSTATE)
-               dprintk("cpu_init done, current fid 0x%x, did 0x%x\n",
-                       data->currfid, data->currdid);
+               dprintk("cpu_init done, current pstate 0x%x\n", 
data->currpstate);
        else
                dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
                        data->currfid, data->currvid);
@@ -1295,7 +1256,7 @@ static unsigned int powernowk8_get (unsigned int cpu)
                goto out;
 
        if (cpu_family == CPU_HW_PSTATE)
-               khz = find_khz_freq_from_fiddid(data->currfid, data->currdid);
+               khz = find_khz_freq_from_pstate(data->powernow_table, 
data->currpstate);
        else
                khz = find_khz_freq_from_fid(data->currfid);
 
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h 
b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index b06c812..8ae88f1 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -10,6 +10,7 @@ struct powernow_k8_data {
 
        u32 numps;  /* number of p-states */
        u32 batps;  /* number of p-states supported on battery */
+       u32 max_hw_pstate; /* maximum legal hardware pstate */
 
        /* these values are constant when the PSB is used to determine
         * vid/fid pairings, but are modified during the ->target() call
@@ -21,8 +22,8 @@ struct powernow_k8_data {
        u32 plllock; /* pll lock time, units 1 us */
         u32 exttype; /* extended interface = 1 */
 
-       /* keep track of the current fid / vid or did */
-       u32 currvid, currfid, currdid;
+       /* keep track of the current fid / vid or pstate */
+       u32 currvid, currfid, currpstate;
 
        /* the powernow_table includes all frequency and vid/fid pairings:
         * fid are the lower 8 bits of the index, vid are the upper 8 bits.
@@ -87,23 +88,14 @@ struct powernow_k8_data {
 
 /* Hardware Pstate _PSS and MSR definitions */
 #define USE_HW_PSTATE          0x00000080
-#define HW_PSTATE_FID_MASK     0x0000003f
-#define HW_PSTATE_DID_MASK     0x000001c0
-#define HW_PSTATE_DID_SHIFT    6
 #define HW_PSTATE_MASK                 0x00000007
 #define HW_PSTATE_VALID_MASK   0x80000000
-#define HW_FID_INDEX_SHIFT     8
-#define HW_FID_INDEX_MASK      0x0000ff00
-#define HW_DID_INDEX_SHIFT     16
-#define HW_DID_INDEX_MASK      0x00ff0000
-#define HW_WATTS_MASK          0xff
-#define HW_PWR_DVR_MASK                0x300
-#define HW_PWR_DVR_SHIFT       8
-#define HW_PWR_MAX_MULT                3
-#define MAX_HW_PSTATE          8       /* hw pstate supports up to 8 */
+#define HW_PSTATE_MAX_MASK     0x000000f0
+#define HW_PSTATE_MAX_SHIFT    4
 #define MSR_PSTATE_DEF_BASE    0xc0010064 /* base of Pstate MSRs */
 #define MSR_PSTATE_STATUS      0xc0010063 /* Pstate Status MSR */
 #define MSR_PSTATE_CTRL        0xc0010062 /* Pstate control MSR */
+#define MSR_PSTATE_CUR_LIMIT   0xc0010061 /* pstate current limit MSR */
 
 /* define the two driver architectures */
 #define CPU_OPTERON 0
-- 
1.5.3.4




-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to