Re: powernow-k8-acpi driver

From: Pavel Machek (pavel_at_ucw.cz)
Date: 03/04/04

  • Next message: Michael Kerrisk: "open(O_ASYNC) is (still) broken in 2.6.3"
    Date:	Thu, 4 Mar 2004 14:44:22 +0100
    To: paul.devriendt@amd.com
    
    

    Hi!

    I've merged powernow-k8-acpi.h with powernow-k8.h, and moved common
    code (static inline function) from powernow-k8.c and
    powernow-k8-acpi.c there.

    Diffstat looks reasonably nice:

    pavel@amd:/usr/src/linux$ cat /tmp/delme.quilt-diff | diffstat
     powernow-k8-acpi.c | 138 ++++++++++++++++++++++-------------------
     powernow-k8-acpi.h | 144 ------------------------------------------
     powernow-k8.c | 178 +++++++++++++++++------------------------------------
     powernow-k8.h | 128 ++++++++++++++++++++++++++------------
     4 files changed, 220 insertions(+), 368 deletions(-)

    I guess that next step is to convert per-cpu state into struct, and
    make both powernow-k8-acpi and powernow-k8 use that struct.
                                                                    Pavel

    --- tmp/linux/arch/i386/kernel/cpu/cpufreq/powernow-k8-acpi.c 2004-03-04 14:33:36.000000000 +0100
    +++ linux/arch/i386/kernel/cpu/cpufreq/powernow-k8-acpi.c 2004-03-04 14:32:11.000000000 +0100
    @@ -36,9 +36,82 @@
     #include <asm/io.h>
     #include <asm/delay.h>
     
    +#define PFX "powernow-k8-acpi: "
    +#define DFX KERN_DEBUG PFX
    +#define IFX KERN_INFO PFX
    +#define EFX KERN_ERR PFX
    +
     #undef DEBUG
     #define VERSION "Version 1.20.02a"
    -#include "powernow-k8-acpi.h"
    +#include "powernow-k8.h"
    +
    +/* byte offsets into the perproc struct */
    +#define PP_OFF_NUMPS 0 /* number of p-states */
    +#define PP_OFF_SHARE 1 /* index of shared control */
    +#define PP_OFF_CVID 2 /* current voltage id */
    +#define PP_OFF_CFID 3 /* current frequency id */
    +#define PP_OFF_BYTES 4 /* size in bytes */
    +
    +struct pstate { /* info on each performance state, per processor */
    + u16 freq; /* frequency is in megahertz */
    + u8 fid;
    + u8 vid;
    + u8 irt;
    + u8 rvo;
    + u8 plllock;
    + u8 vidmvs;
    + u8 vstable;
    + u8 pad1;
    + u16 pad2;
    +};
    +
    +/* Explanation of the perproc data structures:
    + * static u8 **procs; declared in the .c file is an array of pointers to u8.
    + * There is one such pointer for each cpu in the system.
    + * Each pointer points to 4 u8s (indexed by the PP_OFF constants above),
    + * followed by an array of struct pstate, where each processor may have
    + * a different number of entries in its array. I.e., processor 0 may have
    + * 3 pstates, processor 1 may have 5 pstates.
    + */
    +
    +struct proc_pss { /* the acpi _PSS structure */
    + acpi_integer freq;
    + acpi_integer pow;
    + acpi_integer tlat;
    + acpi_integer blat;
    + acpi_integer cntl;
    + acpi_integer stat;
    +};
    +
    +#define PSS_FMT_STR "NNNNNN"
    +
    +#define IRT_SHIFT 30
    +#define RVO_SHIFT 28
    +#define PLL_L_SHIFT 20
    +#define MVS_SHIFT 18
    +#define VST_SHIFT 11
    +#define VID_SHIFT 6
    +#define IRT_MASK 3
    +#define RVO_MASK 3
    +#define PLL_L_MASK 0x7f
    +#define MVS_MASK 3
    +#define VST_MASK 0x7f
    +#define VID_MASK 0x1f
    +#define FID_MASK 0x3f
    +
    +#define POW_AC 0 /* The power supply states we care about - mains, battery, */
    +#define POW_BAT 1 /* or unknown, which presumably means that there is no */
    +#define POW_UNK 2 /* acpi support for the psr object, so there is no battery.*/
    +
    +#define POLLER_NOT_RUNNING 0 /* The state of the poller (which watches for */
    +#define POLLER_RUNNING 1 /* power transitions). It is only running if we */
    +#define POLLER_UNLOAD 2 /* are on mains power, at a high frequency, and */
    +#define POLLER_DEAD 3 /* if there are battery restrictions. */
    +
    +static void start_ac_poller(int frompoller);
    +static int powernowk8_verify(struct cpufreq_policy *p);
    +static int powernowk8_target(struct cpufreq_policy *p, unsigned t, unsigned r);
    +static int __init powernowk8_cpu_init(struct cpufreq_policy *p);
     
     static u8 **procs; /* per processor data structure */
     static u32 rstps; /* pstates allowed restrictions */
    @@ -59,11 +132,6 @@
             .owner = THIS_MODULE,
     };
     
    -static inline u32 freq_from_fid(u8 fid)
    -{
    - return 800 + (fid * 100);
    -}
    -
     static inline u32 kfreq_from_fid(u8 fid)
     {
             return KHZ * freq_from_fid(fid);
    @@ -74,24 +142,6 @@
             return (freq - 800) / 100;
     }
     
    -static inline u32 convert_fid_to_vfid(u8 fid)
    -{
    - if (fid < HI_FID_TABLE_BOTTOM) {
    - return 8 + (2 * fid);
    - } else {
    - return fid;
    - }
    -}
    -
    -static inline int pending_bit_stuck(void)
    -{
    - u32 lo;
    - u32 hi;
    -
    - rdmsr(MSR_FIDVID_STAT, lo, hi);
    - return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
    -}
    -
     static int query_current_values_with_pending_wait(u8 *perproc)
     {
             u32 lo = MSR_S_LO_CHANGE_PENDING;
    @@ -127,16 +177,6 @@
             wrmsr(MSR_FIDVID_CTL, lo, hi);
     }
     
    -static inline void count_off_irt(u8 irt)
    -{
    - udelay((1 << irt) * 10);
    -}
    -
    -static inline void count_off_vst(u8 vstable)
    -{
    - udelay(vstable * VST_UNITS_20US);
    -}
    -
     static int write_new_fid(u8 *perproc, u32 idx, u8 fid)
     {
             u32 lo;
    @@ -413,36 +453,6 @@
             return 0;
     }
     
    -static inline int check_supported_cpu(void)
    -{
    - struct cpuinfo_x86 *c = cpu_data;
    - u32 eax, ebx, ecx, edx;
    -
    - if (c->x86_vendor != X86_VENDOR_AMD)
    - return 0;
    -
    - eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
    - if (!(((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) ||
    - ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD))) {
    - dprintk(DFX "AMD Athlon 64 / Opteron processor required\n");
    - return 0;
    - }
    -
    - eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
    - if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
    - printk(IFX "No freq change capabilities\n");
    - return 0;
    - }
    -
    - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
    - if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
    - printk(IFX "P-state transitions not supported\n");
    - return 0;
    - }
    -
    - return 1;
    -}
    -
     /* evaluating this object tells us whether we are using mains or battery */
     static inline int process_psr(acpi_handle objh)
     {
    --- tmp/linux/arch/i386/kernel/cpu/cpufreq/powernow-k8-acpi.h 2004-03-04 14:33:36.000000000 +0100
    +++ linux/arch/i386/kernel/cpu/cpufreq/powernow-k8-acpi.h 2004-03-04 14:18:38.000000000 +0100
    @@ -1,144 +0,0 @@
    -/*
    - * (c) 2003, 2004 Advanced Micro Devices, Inc.
    - * Your use of this code is subject to the terms and conditions of the
    - * GNU general public license version 2. See "../../../../../COPYING" or
    - * http://www.gnu.org/licenses/gpl.html
    - */
    -
    -/* processor's cpuid instruction support */
    -#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
    -#define CPUID_XFAM_MOD 0x0ff00ff0 /* xtended fam, fam + model */
    -#define ATHLON64_XFAM_MOD 0x00000f40 /* xtended fam, fam + model */
    -#define OPTERON_XFAM_MOD 0x00000f50 /* xtended fam, fam + model */
    -#define CPUID_GET_MAX_CAPABILITIES 0x80000000
    -#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
    -#define P_STATE_TRANSITION_CAPABLE 6
    -
    -#define MSR_FIDVID_CTL 0xc0010041
    -#define MSR_FIDVID_STAT 0xc0010042
    -
    -/* control MSR - low part */
    -#define MSR_C_LO_INIT 0x00010000
    -#define MSR_C_LO_NEW_VID 0x00001f00
    -#define MSR_C_LO_NEW_FID 0x0000003f
    -#define MSR_C_LO_VID_SHIFT 8
    -
    -/* control MSR - high part */
    -#define MSR_C_HI_STP_GNT_TO 0x000fffff
    -#define MSR_C_HI_STP_GNT_BENIGN 1
    -
    -/* status MSR - low part */
    -#define MSR_S_LO_CHANGE_PENDING 0x80000000 /* cleared when completed */
    -#define MSR_S_LO_MAX_RAMP_VID 0x1f000000
    -#define MSR_S_LO_MAX_FID 0x003f0000
    -#define MSR_S_LO_START_FID 0x00003f00
    -#define MSR_S_LO_CURRENT_FID 0x0000003f
    -
    -/* status MSR - high part */
    -#define MSR_S_HI_MAX_WORKING_VID 0x001f0000
    -#define MSR_S_HI_START_VID 0x00001f00
    -#define MSR_S_HI_CURRENT_VID 0x0000001f
    -
    -#define LO_FID_TABLE_TOP 6 /* valid fids exist in 2 tables */
    -#define HI_FID_TABLE_BOTTOM 8
    -#define LO_VCOFREQ_TABLE_TOP 1400 /* corresponding vco frequency values */
    -#define HI_VCOFREQ_TABLE_BOTTOM 1600
    -
    -#define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */
    -#define FSTEP 2
    -#define KHZ 1000
    -
    -#define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */
    -#define LEAST_VID 0x1e /* Lowest (numerically highest) useful vid value */
    -
    -#define MIN_FREQ 800
    -#define MAX_FREQ 5000
    -
    -#define INVALID_FID_MASK 0xffffffc1 /* not a valid fid if these bits are set */
    -#define INVALID_VID_MASK 0xffffffe0 /* not a valid vid if these bits are set */
    -
    -
    -#define STOP_GRANT_5NS 1 /* min memory access latency for voltage change */
    -#define MAXIMUM_VID_STEPS 1 /* Current cpus only allow a single step of 25mV */
    -#define VST_UNITS_20US 20 /* Voltage Stabilization Time is in units of 20us */
    -
    -#define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */
    -
    -/* byte offsets into the perproc struct */
    -#define PP_OFF_NUMPS 0 /* number of p-states */
    -#define PP_OFF_SHARE 1 /* index of shared control */
    -#define PP_OFF_CVID 2 /* current voltage id */
    -#define PP_OFF_CFID 3 /* current frequency id */
    -#define PP_OFF_BYTES 4 /* size in bytes */
    -
    -struct pstate { /* info on each performance state, per processor */
    - u16 freq; /* frequency is in megahertz */
    - u8 fid;
    - u8 vid;
    - u8 irt;
    - u8 rvo;
    - u8 plllock;
    - u8 vidmvs;
    - u8 vstable;
    - u8 pad1;
    - u16 pad2;
    -};
    -
    -/* Explanation of the perproc data structures:
    - * static u8 **procs; declared in the .c file is an array of pointers to u8.
    - * There is one such pointer for each cpu in the system.
    - * Each pointer points to 4 u8s (indexed by the PP_OFF constants above),
    - * followed by an array of struct pstate, where each processor may have
    - * a different number of entries in its array. I.e., processor 0 may have
    - * 3 pstates, processor 1 may have 5 pstates.
    - */
    -
    -struct proc_pss { /* the acpi _PSS structure */
    - acpi_integer freq;
    - acpi_integer pow;
    - acpi_integer tlat;
    - acpi_integer blat;
    - acpi_integer cntl;
    - acpi_integer stat;
    -};
    -
    -#define PSS_FMT_STR "NNNNNN"
    -
    -#define IRT_SHIFT 30
    -#define RVO_SHIFT 28
    -#define PLL_L_SHIFT 20
    -#define MVS_SHIFT 18
    -#define VST_SHIFT 11
    -#define VID_SHIFT 6
    -#define IRT_MASK 3
    -#define RVO_MASK 3
    -#define PLL_L_MASK 0x7f
    -#define MVS_MASK 3
    -#define VST_MASK 0x7f
    -#define VID_MASK 0x1f
    -#define FID_MASK 0x3f
    -
    -#define POW_AC 0 /* The power supply states we care about - mains, battery, */
    -#define POW_BAT 1 /* or unknown, which presumably means that there is no */
    -#define POW_UNK 2 /* acpi support for the psr object, so there is no battery.*/
    -
    -#define POLLER_NOT_RUNNING 0 /* The state of the poller (which watches for */
    -#define POLLER_RUNNING 1 /* power transitions). It is only running if we */
    -#define POLLER_UNLOAD 2 /* are on mains power, at a high frequency, and */
    -#define POLLER_DEAD 3 /* if there are battery restrictions. */
    -
    -#define PFX "powernow-k8-acpi: "
    -#define DFX KERN_DEBUG PFX
    -#define IFX KERN_INFO PFX
    -#define EFX KERN_ERR PFX
    -
    -#ifdef DEBUG
    -#define dprintk(msg...) printk(msg)
    -#else
    -#define dprintk(msg...) do { } while(0)
    -#endif
    -
    -static void start_ac_poller(int frompoller);
    -static int powernowk8_verify(struct cpufreq_policy *p);
    -static int powernowk8_target(struct cpufreq_policy *p, unsigned t, unsigned r);
    -static int __init powernowk8_cpu_init(struct cpufreq_policy *p);
    --- tmp/linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-03-04 14:33:36.000000000 +0100
    +++ linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-03-04 14:29:22.000000000 +0100
    @@ -36,6 +36,45 @@
     #define VERSION "version 1.00.08b"
     #include "powernow-k8.h"
     
    +/*
    + * Version 1.4 of the PSB table. This table is constructed by BIOS and is
    + * to tell the OS's power management driver which VIDs and FIDs are
    + * supported by this particular processor. This information is obtained from
    + * the data sheets for each processor model by the system vendor and
    + * incorporated into the BIOS.
    + * If the data in the PSB / PST is wrong, then this driver will program the
    + * wrong values into hardware, which is very likely to lead to a crash.
    + */
    +
    +#define PSB_ID_STRING "AMDK7PNOW!"
    +#define PSB_ID_STRING_LEN 10
    +
    +#define PSB_VERSION_1_4 0x14
    +
    +struct psb_s {
    + u8 signature[10];
    + u8 tableversion;
    + u8 flags1;
    + u16 voltagestabilizationtime;
    + u8 flags2;
    + u8 numpst;
    + u32 cpuid;
    + u8 plllocktime;
    + u8 maxfid;
    + u8 maxvid;
    + u8 numpstates;
    +};
    +
    +/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */
    +struct pst_s {
    + u8 fid;
    + u8 vid;
    +};
    +
    +static inline int core_voltage_pre_transition(u32 reqvid);
    +static inline int core_voltage_post_transition(u32 reqvid);
    +static inline int core_frequency_transition(u32 reqfid);
    +
     static u32 vstable; /* voltage stabalization time, from PSB, units 20 us */
     static u32 plllock; /* pll lock time, from PSB, units 1 us */
     static u32 numps; /* number of p-states, from PSB */
    @@ -70,37 +109,6 @@
     static u32 batps; /* limit on the number of p states when on battery */
                             /* - set by BIOS in the PSB/PST */
     
    - /* Return a frequency in MHz, given an input fid */
    -static u32 find_freq_from_fid(u32 fid)
    -{
    - return 800 + (fid * 100);
    -}
    -
    -
    -/* Return the vco fid for an input fid */
    -static u32
    -convert_fid_to_vco_fid(u32 fid)
    -{
    - if (fid < HI_FID_TABLE_BOTTOM) {
    - return 8 + (2 * fid);
    - } else {
    - return fid;
    - }
    -}
    -
    -/*
    - * Return 1 if the pending bit is set. Unless we are actually just told the
    - * processor to transition a state, seeing this bit set is really bad news.
    - */
    -static inline int
    -pending_bit_stuck(void)
    -{
    - u32 lo, hi;
    -
    - rdmsr(MSR_FIDVID_STAT, lo, hi);
    - return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
    -}
    -
     /*
      * Update the global current fid / vid values from the status msr. Returns 1
      * on error.
    @@ -119,29 +127,11 @@
                     }
                     rdmsr(MSR_FIDVID_STAT, lo, hi);
             }
    -
             currvid = hi & MSR_S_HI_CURRENT_VID;
             currfid = lo & MSR_S_LO_CURRENT_FID;
    -
             return 0;
     }
     
    -/* the isochronous relief time */
    -static inline void
    -count_off_irt(void)
    -{
    - udelay((1 << irt) * 10);
    - return;
    -}
    -
    -/* the voltage stabalization time */
    -static inline void
    -count_off_vst(void)
    -{
    - udelay(vstable * VST_UNITS_20US);
    - return;
    -}
    -
     /* write the new fid value along with the other control fields to the msr */
     static int
     write_new_fid(u32 fid)
    @@ -164,7 +154,7 @@
             if (query_current_values_with_pending_wait())
                     return 1;
     
    - count_off_irt();
    + count_off_irt(irt);
     
             if (savevid != currvid) {
                     printk(KERN_ERR PFX
    @@ -237,7 +227,7 @@
             if (write_new_vid(reqvid))
                     return 1;
     
    - count_off_vst();
    + count_off_vst(vstable);
     
             return 0;
     }
    @@ -248,25 +238,19 @@
     {
             if (core_voltage_pre_transition(reqvid))
                     return 1;
    -
             if (core_frequency_transition(reqfid))
                     return 1;
    -
             if (core_voltage_post_transition(reqvid))
                     return 1;
    -
             if (query_current_values_with_pending_wait())
                     return 1;
    -
             if ((reqfid != currfid) || (reqvid != currvid)) {
                     printk(KERN_ERR PFX "failed: req 0x%x 0x%x, curr 0x%x 0x%x\n",
                            reqfid, reqvid, currfid, currvid);
                     return 1;
             }
    -
             dprintk(KERN_INFO PFX
                     "transitioned: new fid 0x%x, vid 0x%x\n", currfid, currvid);
    -
             return 0;
     }
     
    @@ -342,8 +326,8 @@
                     "ph2 starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
                     currfid, currvid, reqfid);
     
    - vcoreqfid = convert_fid_to_vco_fid(reqfid);
    - vcocurrfid = convert_fid_to_vco_fid(currfid);
    + vcoreqfid = convert_fid_to_vfid(reqfid);
    + vcocurrfid = convert_fid_to_vfid(currfid);
             vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
                 : vcoreqfid - vcocurrfid;
     
    @@ -355,7 +339,7 @@
                                     }
                             } else {
                                     if (write_new_fid
    - (2 + convert_fid_to_vco_fid(currfid))) {
    + (2 + convert_fid_to_vfid(currfid))) {
                                             return 1;
                                     }
                             }
    @@ -364,7 +348,7 @@
                                     return 1;
                     }
     
    - vcocurrfid = convert_fid_to_vco_fid(currfid);
    + vcocurrfid = convert_fid_to_vfid(currfid);
                     vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
                         : vcoreqfid - vcocurrfid;
             }
    @@ -444,57 +428,6 @@
             return 0;
     }
     
    -static inline int
    -check_supported_cpu(void)
    -{
    - struct cpuinfo_x86 *c = cpu_data;
    - u32 eax, ebx, ecx, edx;
    -
    - if (num_online_cpus() != 1) {
    - printk(KERN_INFO PFX "multiprocessor systems not supported\n");
    - return 0;
    - }
    -
    - if (c->x86_vendor != X86_VENDOR_AMD) {
    -#ifdef MODULE
    - printk(KERN_INFO PFX "Not an AMD processor\n");
    -#endif
    - return 0;
    - }
    -
    - eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
    - if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
    - dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
    - if ((eax & CPUID_F1_STEP) < ATHLON64_REV_C0) {
    - printk(KERN_INFO PFX "Revision C0 or better "
    - "AMD Athlon 64 processor required\n");
    - return 0;
    - }
    - } else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
    - dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
    - } else {
    - printk(KERN_INFO PFX
    - "AMD Athlon 64 or AMD Opteron processor required\n");
    - return 0;
    - }
    -
    - eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
    - if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
    - printk(KERN_INFO PFX
    - "No frequency change capabilities detected\n");
    - return 0;
    - }
    -
    - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
    - if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
    - printk(KERN_INFO PFX "Power state transitions not supported\n");
    - return 0;
    - }
    -
    - printk(KERN_INFO PFX "Found AMD64 processor supporting PowerNow (" VERSION ")\n");
    - return 1;
    -}
    -
     static int check_pst_table(struct pst_s *pst, u8 maxvid)
     {
             unsigned int j;
    @@ -599,7 +532,7 @@
     
                     maxvid = psb->maxvid;
                     printk("maxfid 0x%x (%d MHz), maxvid 0x%x\n",
    - psb->maxfid, find_freq_from_fid(psb->maxfid), maxvid);
    + psb->maxfid, freq_from_fid(psb->maxfid), maxvid);
     
                     numps = arima ? 3 : psb->numpstates;
                     if (numps < 2) {
    @@ -649,7 +582,7 @@
                     }
     
                     for (j = 0; j < numps; j++) {
    - powernow_table[j].frequency = find_freq_from_fid(powernow_table[j].index & 0xff)*1000;
    + powernow_table[j].frequency = freq_from_fid(powernow_table[j].index & 0xff)*1000;
                             printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n", j,
                                    powernow_table[j].index & 0xff,
                                    powernow_table[j].frequency/1000,
    @@ -665,7 +598,7 @@
                     }
     
                     printk(KERN_INFO PFX "currfid 0x%x (%d MHz), currvid 0x%x\n",
    - currfid, find_freq_from_fid(currfid), currvid);
    + currfid, freq_from_fid(currfid), currvid);
     
                     for (j = 0; j < numps; j++)
                             if ((pst[j].fid==currfid) && (pst[j].vid==currvid))
    @@ -720,13 +653,13 @@
     
             freqs.cpu = 0; /* only true because SMP not supported */
     
    - freqs.old = find_freq_from_fid(currfid);
    - freqs.new = find_freq_from_fid(fid);
    + freqs.old = freq_from_fid(currfid);
    + freqs.new = freq_from_fid(fid);
             cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
     
             res = transition_fid_vid(fid, vid);
     
    - freqs.new = find_freq_from_fid(currfid);
    + freqs.new = freq_from_fid(currfid);
             cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
     
             return res;
    @@ -769,7 +702,7 @@
                     return 1;
             }
     
    - pol->cur = 1000 * find_freq_from_fid(currfid);
    + pol->cur = 1000 * freq_from_fid(currfid);
     
             return 0;
     }
    @@ -805,7 +738,7 @@
             if (query_current_values_with_pending_wait())
                     return -EIO;
     
    - pol->cur = 1000 * find_freq_from_fid(currfid);
    + pol->cur = 1000 * freq_from_fid(currfid);
             dprintk(KERN_DEBUG PFX "policy current frequency %d kHz\n", pol->cur);
     
             /* min/max the cpu is capable of */
    @@ -855,6 +788,11 @@
             }
     #endif
     
    + if (num_online_cpus() != 1) {
    + printk(KERN_INFO PFX "multiprocessor systems not supported\n");
    + return -ENODEV;
    + }
    +
             if (check_supported_cpu() == 0)
                     return -ENODEV;
     
    --- tmp/linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.h 2004-03-04 14:33:36.000000000 +0100
    +++ linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.h 2004-03-04 14:29:33.000000000 +0100
    @@ -22,11 +22,12 @@
     /* control MSR - low part */
     #define MSR_C_LO_INIT 0x00010000
     #define MSR_C_LO_NEW_VID 0x00001f00
    -#define MSR_C_LO_NEW_FID 0x0000002f
    +#define MSR_C_LO_NEW_FID 0x0000002f /* FIXME: acpi driver uses 0x3f here?! */
     #define MSR_C_LO_VID_SHIFT 8
     
     /* control MSR - high part */
     #define MSR_C_HI_STP_GNT_TO 0x000fffff
    +#define MSR_C_HI_STP_GNT_BENIGN 1
     
     /* status MSR - low part */
     #define MSR_S_LO_CHANGE_PENDING 0x80000000 /* cleared when completed */
    @@ -47,6 +48,8 @@
     #define HI_VCOFREQ_TABLE_BOTTOM 1600
     
     #define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */
    +#define FSTEP 2
    +#define KHZ 1000
     
     #define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */
     #define LEAST_VID 0x1e /* Lowest (numerically highest) useful vid value */
    @@ -64,48 +67,93 @@
     
     #define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */
     
    -
    -/*
    - * Version 1.4 of the PSB table. This table is constructed by BIOS and is
    - * to tell the OS's power management driver which VIDs and FIDs are
    - * supported by this particular processor. This information is obtained from
    - * the data sheets for each processor model by the system vendor and
    - * incorporated into the BIOS.
    - * If the data in the PSB / PST is wrong, then this driver will program the
    - * wrong values into hardware, which is very likely to lead to a crash.
    - */
    -
    -#define PSB_ID_STRING "AMDK7PNOW!"
    -#define PSB_ID_STRING_LEN 10
    -
    -#define PSB_VERSION_1_4 0x14
    -
    -struct psb_s {
    - u8 signature[10];
    - u8 tableversion;
    - u8 flags1;
    - u16 voltagestabilizationtime;
    - u8 flags2;
    - u8 numpst;
    - u32 cpuid;
    - u8 plllocktime;
    - u8 maxfid;
    - u8 maxvid;
    - u8 numpstates;
    -};
    -
    -/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */
    -struct pst_s {
    - u8 fid;
    - u8 vid;
    -};
    -
     #ifdef DEBUG
     #define dprintk(msg...) printk(msg)
     #else
     #define dprintk(msg...) do { } while(0)
     #endif
     
    -static inline int core_voltage_pre_transition(u32 reqvid);
    -static inline int core_voltage_post_transition(u32 reqvid);
    -static inline int core_frequency_transition(u32 reqfid);
    +/* Return a frequency in MHz, given an input fid */
    +static inline u32 freq_from_fid(u8 fid)
    +{
    + return 800 + (fid * 100);
    +}
    +
    +/* Return the vco fid for an input fid */
    +static inline u32 convert_fid_to_vfid(u8 fid)
    +{
    + if (fid < HI_FID_TABLE_BOTTOM) {
    + return 8 + (2 * fid);
    + } else {
    + return fid;
    + }
    +}
    +
    +/*
    + * Return 1 if the pending bit is set. Unless we are actually just told the
    + * processor to transition a state, seeing this bit set is really bad news.
    + */
    +static inline int
    +pending_bit_stuck(void)
    +{
    + u32 lo, hi;
    +
    + rdmsr(MSR_FIDVID_STAT, lo, hi);
    + return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
    +}
    +
    +static inline void count_off_irt(u8 irt)
    +{
    + udelay((1 << irt) * 10);
    +}
    +
    +static inline void count_off_vst(u8 vstable)
    +{
    + udelay(vstable * VST_UNITS_20US);
    +}
    +
    +static inline int
    +check_supported_cpu(void)
    +{
    + struct cpuinfo_x86 *c = cpu_data;
    + u32 eax, ebx, ecx, edx;
    +
    + if (c->x86_vendor != X86_VENDOR_AMD) {
    +#ifdef MODULE
    + printk(KERN_INFO PFX "Not an AMD processor\n");
    +#endif
    + return 0;
    + }
    +
    + eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
    + if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
    + dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
    + if ((eax & CPUID_F1_STEP) < ATHLON64_REV_C0) {
    + printk(KERN_INFO PFX "Revision C0 or better "
    + "AMD Athlon 64 processor required\n");
    + return 0;
    + }
    + } else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
    + dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
    + } else {
    + printk(KERN_INFO PFX
    + "AMD Athlon 64 or AMD Opteron processor required\n");
    + return 0;
    + }
    +
    + eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
    + if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
    + printk(KERN_INFO PFX
    + "No frequency change capabilities detected\n");
    + return 0;
    + }
    +
    + cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
    + if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
    + printk(KERN_INFO PFX "Power state transitions not supported\n");
    + return 0;
    + }
    +
    + printk(KERN_INFO PFX "Found AMD64 processor supporting PowerNow (" VERSION ")\n");
    + return 1;
    +}

    -- 
    When do you have a heart between your knees?
    [Johanka's followup: and *two* hearts?]
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at  http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at  http://www.tux.org/lkml/
    

  • Next message: Michael Kerrisk: "open(O_ASYNC) is (still) broken in 2.6.3"
  • Quantcast