public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Pavel Machek <pavel@ucw.cz>
To: paul.devriendt@amd.com
Cc: davej@redhat.com, cpufreq@www.linux.org.uk, linux-kernel@vger.kernel.org
Subject: Re: powernow-k8-acpi driver
Date: Thu, 4 Mar 2004 14:44:22 +0100	[thread overview]
Message-ID: <20040304134422.GE308@elf.ucw.cz> (raw)
In-Reply-To: <99F2150714F93F448942F9A9F112634C109A3935@txexmtae.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?]

  reply	other threads:[~2004-03-04 13:51 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-03-03 23:57 powernow-k8-acpi driver paul.devriendt
2004-03-04 13:44 ` Pavel Machek [this message]
  -- strict thread matches above, loose matches on Subject: below --
2004-03-04  2:00 richard.brunner
2004-03-04 23:16 ` Pavel Machek
2004-03-03 23:48 paul.devriendt
2004-03-04 12:35 ` Pavel Machek
2004-03-03 21:54 Pavel Machek
2004-03-03 22:27 ` Dave Jones
2004-03-03 22:35   ` Pavel Machek
2004-03-03 22:48     ` Dave Jones
2004-03-03 22:54       ` Pavel Machek
2004-03-03 23:36         ` Dave Jones
2004-03-04  0:07           ` Pavel Machek
2004-03-04  9:38             ` Russell King
2004-03-05 19:18             ` Bruno Ducrot
2004-03-07 13:15               ` Colin Marquardt
2004-03-03 23:09       ` Pavel Machek
2004-03-03 23:11       ` Pavel Machek
2004-03-03 23:39         ` Dave Jones
2004-03-03 23:45           ` Pavel Machek
2004-03-03 23:26       ` Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040304134422.GE308@elf.ucw.cz \
    --to=pavel@ucw.cz \
    --cc=cpufreq@www.linux.org.uk \
    --cc=davej@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=paul.devriendt@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox