Module Name:    src
Committed By:   jruoho
Date:           Thu Feb 24 10:56:03 UTC 2011

Modified Files:
        src/sys/arch/amd64/conf: GENERIC XEN3_DOM0
        src/sys/arch/i386/conf: ALL GENERIC XEN3_DOM0 files.i386
        src/sys/arch/x86/conf: files.x86
        src/sys/arch/x86/include: powernow.h
        src/sys/arch/x86/x86: cpu.c identcpu.c
        src/sys/arch/xen/conf: files.xen
        src/sys/arch/xen/x86: cpu.c
Added Files:
        src/sys/arch/x86/x86: powernow.c
Removed Files:
        src/sys/arch/i386/i386: powernow_k7.c
        src/sys/arch/x86/x86: powernow_common.c powernow_k8.c

Log Message:
Move PowerNow! to the cpufeaturebus.


To generate a diff of this commit:
cvs rdiff -u -r1.313 -r1.314 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.63 -r1.64 src/sys/arch/amd64/conf/XEN3_DOM0
cvs rdiff -u -r1.294 -r1.295 src/sys/arch/i386/conf/ALL
cvs rdiff -u -r1.1021 -r1.1022 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.45 -r1.46 src/sys/arch/i386/conf/XEN3_DOM0
cvs rdiff -u -r1.355 -r1.356 src/sys/arch/i386/conf/files.i386
cvs rdiff -u -r1.33 -r0 src/sys/arch/i386/i386/powernow_k7.c
cvs rdiff -u -r1.60 -r1.61 src/sys/arch/x86/conf/files.x86
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/x86/include/powernow.h
cvs rdiff -u -r1.83 -r1.84 src/sys/arch/x86/x86/cpu.c
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/x86/x86/identcpu.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/powernow.c
cvs rdiff -u -r1.11 -r0 src/sys/arch/x86/x86/powernow_common.c
cvs rdiff -u -r1.28 -r0 src/sys/arch/x86/x86/powernow_k8.c
cvs rdiff -u -r1.112 -r1.113 src/sys/arch/xen/conf/files.xen
cvs rdiff -u -r1.53 -r1.54 src/sys/arch/xen/x86/cpu.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.313 src/sys/arch/amd64/conf/GENERIC:1.314
--- src/sys/arch/amd64/conf/GENERIC:1.313	Wed Feb 23 11:43:21 2011
+++ src/sys/arch/amd64/conf/GENERIC	Thu Feb 24 10:56:00 2011
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.313 2011/02/23 11:43:21 jruoho Exp $
+# $NetBSD: GENERIC,v 1.314 2011/02/24 10:56:00 jruoho Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.313 $"
+#ident 		"GENERIC-$Revision: 1.314 $"
 
 maxusers	64		# estimated number of users
 
@@ -78,12 +78,10 @@
 #options 	PIPE_SOCKETPAIR	# smaller, but slower pipe(2)
 options 	SYSCTL_INCLUDE_DESCR	# Include sysctl descriptions in kernel
 
-# AMD PowerNow! and Cool`n'Quiet technology
-options 	POWERNOW_K8
-
 # CPU features
 coretemp*	at cpu?		# Intel on-die thermal sensor
 est0		at cpu0		# Intel Enhanced SpeedStep (non-ACPI)
+powernow0	at cpu0		# AMD PowerNow! and Cool'n'Quiet (non-ACPI)
 
 # Intel(R) On Demand Clock Modulation (aka ODCM)
 # options       INTEL_ONDEMAND_CLOCKMOD

Index: src/sys/arch/amd64/conf/XEN3_DOM0
diff -u src/sys/arch/amd64/conf/XEN3_DOM0:1.63 src/sys/arch/amd64/conf/XEN3_DOM0:1.64
--- src/sys/arch/amd64/conf/XEN3_DOM0:1.63	Thu Feb 24 04:42:54 2011
+++ src/sys/arch/amd64/conf/XEN3_DOM0	Thu Feb 24 10:56:00 2011
@@ -1,4 +1,4 @@
-# $NetBSD: XEN3_DOM0,v 1.63 2011/02/24 04:42:54 jruoho Exp $
+# $NetBSD: XEN3_DOM0,v 1.64 2011/02/24 10:56:00 jruoho Exp $
 
 include 	"arch/amd64/conf/std.xen"
 
@@ -20,11 +20,9 @@
 #options 	VM86		# virtual 8086 emulation
 #options 	USER_LDT	# user-settable LDT; used by WINE
 
-# AMD PowerNow! and Cool`n'Quiet technology
-options		POWERNOW_K8
-
 # CPU features
 est0		at cpu0		# Intel Enhanced SpeedStep (non-ACPI)
+powernow0	at cpu0		# AMD PowerNow! and Cool'n'Quiet (non-ACPI)
 
 #options 	MTRR		# memory-type range register syscall support
 

Index: src/sys/arch/i386/conf/ALL
diff -u src/sys/arch/i386/conf/ALL:1.294 src/sys/arch/i386/conf/ALL:1.295
--- src/sys/arch/i386/conf/ALL:1.294	Wed Feb 23 11:43:22 2011
+++ src/sys/arch/i386/conf/ALL	Thu Feb 24 10:56:01 2011
@@ -1,4 +1,4 @@
-# $NetBSD: ALL,v 1.294 2011/02/23 11:43:22 jruoho Exp $
+# $NetBSD: ALL,v 1.295 2011/02/24 10:56:01 jruoho Exp $
 # From NetBSD: GENERIC,v 1.787 2006/10/01 18:37:54 bouyer Exp
 #
 # ALL machine description file
@@ -17,7 +17,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"ALL-$Revision: 1.294 $"
+#ident 		"ALL-$Revision: 1.295 $"
 
 maxusers	64		# estimated number of users
 
@@ -29,16 +29,11 @@
 options 	X86EMU		# 386 Real Mode emulator
 options 	PAE		# PAE mode (36 bits physical addressing)
 
-# AMD PowerNow! K7
-options 	POWERNOW_K7
-
-# AMD PowerNow! and Cool`n'Quiet technology
-options 	POWERNOW_K8
-
 # CPU features
 coretemp*	at cpu?		# Intel on-die thermal sensor
 est0		at cpu0		# Intel Enhanced SpeedStep (non-ACPI)
 padlock0	at cpu0		# VIA PadLock
+powernow0	at cpu0		# AMD PowerNow! and Cool'n'Quiet (non-ACPI)
 
 # Intel(R) On Demand Clock Modulation (aka ODCM)
 options 	INTEL_ONDEMAND_CLOCKMOD

Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.1021 src/sys/arch/i386/conf/GENERIC:1.1022
--- src/sys/arch/i386/conf/GENERIC:1.1021	Wed Feb 23 11:43:22 2011
+++ src/sys/arch/i386/conf/GENERIC	Thu Feb 24 10:56:01 2011
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.1021 2011/02/23 11:43:22 jruoho Exp $
+# $NetBSD: GENERIC,v 1.1022 2011/02/24 10:56:01 jruoho Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.1021 $"
+#ident 		"GENERIC-$Revision: 1.1022 $"
 
 maxusers	64		# estimated number of users
 
@@ -37,16 +37,11 @@
 options 	USER_LDT	# user-settable LDT; used by WINE
 #options 	PAE		# PAE mode (36 bits physical addressing)
 
-# AMD PowerNow! K7
-options 	POWERNOW_K7
-
-# AMD PowerNow! and Cool`n'Quiet technology
-options 	POWERNOW_K8
-
 # CPU features
 coretemp*	at cpu?		# Intel on-die thermal sensor
 est0		at cpu0		# Intel Enhanced SpeedStep (non-ACPI)
 #padlock0	at cpu0		# VIA PadLock
+powernow0	at cpu0		# AMD PowerNow! and Cool'n'Quiet (non-ACPI)
 
 # Intel(R) On Demand Clock Modulation (aka ODCM)
 #options 	INTEL_ONDEMAND_CLOCKMOD

Index: src/sys/arch/i386/conf/XEN3_DOM0
diff -u src/sys/arch/i386/conf/XEN3_DOM0:1.45 src/sys/arch/i386/conf/XEN3_DOM0:1.46
--- src/sys/arch/i386/conf/XEN3_DOM0:1.45	Thu Feb 24 07:51:16 2011
+++ src/sys/arch/i386/conf/XEN3_DOM0	Thu Feb 24 10:56:01 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: XEN3_DOM0,v 1.45 2011/02/24 07:51:16 jruoho Exp $
+#	$NetBSD: XEN3_DOM0,v 1.46 2011/02/24 10:56:01 jruoho Exp $
 #
 #	XEN3_0: Xen 3.0 domain0 kernel
 
@@ -30,14 +30,9 @@
 #options 	VM86		# virtual 8086 emulation
 #options 	USER_LDT	# user-settable LDT; used by WINE
 
-# AMD PowerNow! K7
-options 	POWERNOW_K7
-
-# AMD PowerNow! and Cool`n'Quiet technology
-options 	POWERNOW_K8
-
 # CPU features
 est0		at cpu0		# Intel Enhanced SpeedStep (non-ACPI)
+powernow0	at cpu0		# AMD PowerNow! and Cool'n'Quiet (non-ACPI)
 
 #options 	MTRR		# memory-type range register syscall support
 

Index: src/sys/arch/i386/conf/files.i386
diff -u src/sys/arch/i386/conf/files.i386:1.355 src/sys/arch/i386/conf/files.i386:1.356
--- src/sys/arch/i386/conf/files.i386:1.355	Thu Jul  8 11:24:59 2010
+++ src/sys/arch/i386/conf/files.i386	Thu Feb 24 10:56:01 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i386,v 1.355 2010/07/08 11:24:59 rmind Exp $
+#	$NetBSD: files.i386,v 1.356 2011/02/24 10:56:01 jruoho Exp $
 #
 # new style config file for i386 architecture
 #
@@ -59,9 +59,6 @@
 obsolete 	defparam		MULTIBOOT_SYMTAB_SPACE
 file 	arch/i386/i386/multiboot.c	multiboot
 
-# PowerNow K7
-defflag 	POWERNOW_K7
-
 file	arch/i386/i386/autoconf.c
 file	arch/i386/i386/aout_machdep.c	exec_aout
 file	arch/i386/i386/busfunc.S
@@ -489,9 +486,6 @@
 obsolete	defparam opt_vesafb.h	VESAFB_WIDTH VESAFB_HEIGHT VESAFB_DEPTH
 obsolete	defflag	opt_vesafb.h	VESAFB_PM
 
-# AMD PowerNow K7
-file	arch/i386/i386/powernow_k7.c	powernow_k7
-
 # AMD Geode LX Security Block
 device	glxsb: opencrypto
 attach	glxsb at pci    

Index: src/sys/arch/x86/conf/files.x86
diff -u src/sys/arch/x86/conf/files.x86:1.60 src/sys/arch/x86/conf/files.x86:1.61
--- src/sys/arch/x86/conf/files.x86:1.60	Wed Feb 23 11:43:22 2011
+++ src/sys/arch/x86/conf/files.x86	Thu Feb 24 10:56:02 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.x86,v 1.60 2011/02/23 11:43:22 jruoho Exp $
+#	$NetBSD: files.x86,v 1.61 2011/02/24 10:56:02 jruoho Exp $
 
 # options for MP configuration through the MP spec
 defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
@@ -16,9 +16,6 @@
 # Pentium 4+ Thermal Monitor ODCM (aka On Demand Clock Modulation)
 defflag opt_intel_odcm.h 	INTEL_ONDEMAND_CLOCKMOD
 
-# AMD Powernow/Cool`n'Quiet Technology
-defflag opt_powernow_k8.h	POWERNOW_K8
-
 # VIA C7 Temperature sensor
 defflag	opt_via_c7temp.h	VIA_C7TEMP: sysmon_envsys
 
@@ -37,19 +34,23 @@
 attach	cpu at cpubus
 file 	arch/x86/x86/cpu.c 		cpu
 
+device	coretemp: sysmon_envsys
+attach	coretemp at cpufeaturebus
+file	arch/x86/x86/coretemp.c		coretemp
+
 device	est
 attach	est at cpufeaturebus
 file	arch/x86/x86/est.c		est
 file	arch/x86/x86/intel_busclock.c	est
 
-device	coretemp: sysmon_envsys
-attach	coretemp at cpufeaturebus
-file	arch/x86/x86/coretemp.c		coretemp
-
 device	padlock: opencrypto
 attach	padlock at cpufeaturebus
 file	arch/x86/x86/via_padlock.c	padlock
 
+device	powernow
+attach	powernow at cpufeaturebus
+file	arch/x86/x86/powernow.c		powernow
+
 file	arch/x86/x86/apic.c		ioapic | lapic
 file	arch/x86/x86/bus_dma.c
 file	arch/x86/x86/bus_space.c
@@ -98,10 +99,6 @@
 
 file	arch/x86/isa/isa_machdep.c	isa
 
-# Powernow common functions
-file	arch/x86/x86/powernow_k8.c	powernow_k8
-file	arch/x86/x86/powernow_common.c	powernow_k8 | powernow_k7
-
 # Intel On Demand Clock Modulation
 file	arch/x86/x86/iclockmod.c	intel_ondemand_clockmod
 

Index: src/sys/arch/x86/include/powernow.h
diff -u src/sys/arch/x86/include/powernow.h:1.12 src/sys/arch/x86/include/powernow.h:1.13
--- src/sys/arch/x86/include/powernow.h:1.12	Tue Oct 26 07:54:12 2010
+++ src/sys/arch/x86/include/powernow.h	Thu Feb 24 10:56:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: powernow.h,v 1.12 2010/10/26 07:54:12 jruoho Exp $	*/
+/*	$NetBSD: powernow.h,v 1.13 2011/02/24 10:56:02 jruoho Exp $	*/
 
 /*-
  * Copyright (c) 2004 Martin Végiard.
@@ -52,8 +52,8 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef X86_POWERNOW_H
-#define X86_POWERNOW_H
+#ifndef _X86_POWERNOW_H
+#define _X86_POWERNOW_H
 
 #ifdef POWERNOW_DEBUG
 #define DPRINTF(x)		do { printf x; } while (0)
@@ -126,7 +126,7 @@
 };
 
 struct powernow_cpu_state {
-	struct powernow_state state_table[POWERNOW_MAX_STATES];
+	struct powernow_state	state_table[POWERNOW_MAX_STATES];
 	unsigned int fsb;
 	unsigned int n_states;
 	unsigned int sgtc;
@@ -155,14 +155,4 @@
 	uint8_t n_states;
 };
 
-int powernow_probe(struct cpu_info *);
-
-/* i386/i386/powernow_k7.c */
-void k7_powernow_init(void);
-void k7_powernow_destroy(void);
-
-/* x86/x86/powernow_k8.c */
-void k8_powernow_init(void);
-void k8_powernow_destroy(void);
-
-#endif
+#endif	/* !_X86_POWERNOW_H */

Index: src/sys/arch/x86/x86/cpu.c
diff -u src/sys/arch/x86/x86/cpu.c:1.83 src/sys/arch/x86/x86/cpu.c:1.84
--- src/sys/arch/x86/x86/cpu.c:1.83	Wed Feb 23 11:43:23 2011
+++ src/sys/arch/x86/x86/cpu.c	Thu Feb 24 10:56:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.83 2011/02/23 11:43:23 jruoho Exp $	*/
+/*	$NetBSD: cpu.c,v 1.84 2011/02/24 10:56:02 jruoho Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.83 2011/02/23 11:43:23 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.84 2011/02/24 10:56:02 jruoho Exp $");
 
 #include "opt_ddb.h"
 #include "opt_mpbios.h"		/* for MPDEBUG */
@@ -470,6 +470,12 @@
 			    "cpufeaturebus", &cfaa, NULL);
 		}
 
+		if (ci->ci_frequency == NULL) {
+			cfaa.name = "powernow";
+			ci->ci_frequency = config_found_ia(self,
+			    "cpufeaturebus", &cfaa, NULL);
+		}
+
 		if (ci->ci_padlock == NULL) {
 			cfaa.name = "padlock";
 			ci->ci_padlock = config_found_ia(self,

Index: src/sys/arch/x86/x86/identcpu.c
diff -u src/sys/arch/x86/x86/identcpu.c:1.25 src/sys/arch/x86/x86/identcpu.c:1.26
--- src/sys/arch/x86/x86/identcpu.c:1.25	Wed Feb 23 11:43:23 2011
+++ src/sys/arch/x86/x86/identcpu.c	Thu Feb 24 10:56:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: identcpu.c,v 1.25 2011/02/23 11:43:23 jruoho Exp $	*/
+/*	$NetBSD: identcpu.c,v 1.26 2011/02/24 10:56:02 jruoho Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -30,15 +30,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.25 2011/02/23 11:43:23 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.26 2011/02/24 10:56:02 jruoho Exp $");
 
 #include "opt_intel_odcm.h"
 #include "opt_via_c7temp.h"
-#include "opt_powernow_k8.h"
 #include "opt_xen.h"
-#ifdef i386	/* XXX */
-#include "opt_powernow_k7.h"
-#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -54,7 +50,6 @@
 #include <x86/cacheinfo.h>
 #include <x86/cpuvar.h>
 #include <x86/cpu_msr.h>
-#include <x86/powernow.h>
 
 static const struct x86_cache_info intel_cpuid_cache_info[] = INTEL_CACHE_INFO;
 
@@ -813,25 +808,6 @@
 	}
 #endif
 
-#if defined(POWERNOW_K7) || defined(POWERNOW_K8)
-	if (cpu_vendor == CPUVENDOR_AMD && powernow_probe(ci)) {
-		switch (CPUID2FAMILY(ci->ci_signature)) {
-#ifdef POWERNOW_K7
-		case 6:
-			k7_powernow_init();
-			break;
-#endif
-#ifdef POWERNOW_K8
-		case 15:
-			k8_powernow_init();
-			break;
-#endif
-		default:
-			break;
-		}
-	}
-#endif /* POWERNOW_K7 || POWERNOW_K8 */
-
 #ifdef INTEL_ONDEMAND_CLOCKMOD
 	if (cpuid_level >= 1) {
 		clockmod_init();

Index: src/sys/arch/xen/conf/files.xen
diff -u src/sys/arch/xen/conf/files.xen:1.112 src/sys/arch/xen/conf/files.xen:1.113
--- src/sys/arch/xen/conf/files.xen:1.112	Thu Feb 24 04:42:54 2011
+++ src/sys/arch/xen/conf/files.xen	Thu Feb 24 10:56:03 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.xen,v 1.112 2011/02/24 04:42:54 jruoho Exp $
+#	$NetBSD: files.xen,v 1.113 2011/02/24 10:56:03 jruoho Exp $
 #	NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp 
 #	NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp 
 
@@ -33,12 +33,6 @@
 
 defparam		PCI_CONF_MODE
 
-# AMD Powernow/Cool`n'Quiet Technology
-defflag opt_powernow_k8.h	POWERNOW_K8
-# Powernow common functions
-file	arch/x86/x86/powernow_k8.c	powernow_k8
-file	arch/x86/x86/powernow_common.c	powernow_k8 | powernow_k7
-
 file	arch/xen/x86/autoconf.c
 ifdef i386
 file	arch/i386/i386/aout_machdep.c	exec_aout
@@ -73,10 +67,6 @@
 file	crypto/blowfish/arch/i386/bf_enc.S	blowfish
 file	crypto/blowfish/arch/i386/bf_cbc.S	blowfish
 
-# AMD PowerNow K7
-defflag					POWERNOW_K7
-file	arch/i386/i386/powernow_k7.c		powernow_k7
-
 elifdef amd64
 file	arch/amd64/amd64/busfunc.S
 file	arch/amd64/amd64/cpufunc.S
@@ -302,6 +292,10 @@
 file	arch/x86/x86/est.c		est
 file	arch/x86/x86/intel_busclock.c	est
 
+device	powernow
+attach	powernow at cpufeaturebus
+file	arch/x86/x86/powernow.c		powernow
+
 #
 # Compatibility modules
 #

Index: src/sys/arch/xen/x86/cpu.c
diff -u src/sys/arch/xen/x86/cpu.c:1.53 src/sys/arch/xen/x86/cpu.c:1.54
--- src/sys/arch/xen/x86/cpu.c:1.53	Thu Feb 24 04:42:55 2011
+++ src/sys/arch/xen/x86/cpu.c	Thu Feb 24 10:56:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.53 2011/02/24 04:42:55 jruoho Exp $	*/
+/*	$NetBSD: cpu.c,v 1.54 2011/02/24 10:56:03 jruoho Exp $	*/
 /* NetBSD: cpu.c,v 1.18 2004/02/20 17:35:01 yamt Exp  */
 
 /*-
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.53 2011/02/24 04:42:55 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.54 2011/02/24 10:56:03 jruoho Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -290,6 +290,12 @@
 			ci->ci_frequency = config_found_ia(self,
 			    "cpufeaturebus", &cfaa, NULL);
 		}
+
+		if (ci->ci_frequency == NULL) {
+			cfaa.name = "powernow";
+			ci->ci_frequency = config_found_ia(self,
+			    "cpufeaturebus", &cfaa, NULL);
+		}
 	}
 
 	return 0;

Added files:

Index: src/sys/arch/x86/x86/powernow.c
diff -u /dev/null src/sys/arch/x86/x86/powernow.c:1.1
--- /dev/null	Thu Feb 24 10:56:04 2011
+++ src/sys/arch/x86/x86/powernow.c	Thu Feb 24 10:56:02 2011
@@ -0,0 +1,1000 @@
+/*	$NetBSD: powernow.c,v 1.1 2011/02/24 10:56:02 jruoho Exp $ */
+/*	$OpenBSD: powernow-k8.c,v 1.8 2006/06/16 05:58:50 gwk Exp $ */
+
+/*-
+ * Copyright (c) 2004, 2006, 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juan Romero Pardines and Martin Vegiard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004-2005 Bruno Ducrot
+ * Copyright (c) 2004 FUKUDA Nobuhiko <nfuk...@spa.is.uec.ac.jp>
+ * Copyright (c) 2004 Martin Vegiard
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: powernow.c,v 1.1 2011/02/24 10:56:02 jruoho Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/xcall.h>
+
+#include <dev/isa/isareg.h>
+
+#include <x86/cpuvar.h>
+#include <x86/cputypes.h>
+#include <x86/cpu_msr.h>
+#include <x86/isa_machdep.h>
+#include <x86/powernow.h>
+#include <x86/specialreg.h>
+
+#ifdef __i386__
+/*
+ * Divide each value by 10 to get the processor multiplier.
+ * Taken from powernow-k7.c/Linux by Dave Jones.
+ */
+static int powernow_k7_fidtomult[32] = {
+	110, 115, 120, 125, 50, 55, 60, 65,
+	70, 75, 80, 85, 90, 95, 100, 105,
+	30, 190, 40, 200, 130, 135, 140, 210,
+	150, 225, 160, 165, 170, 180, -1, -1
+};
+
+/*
+ * The following CPUs do not have same CPUID signature
+ * in the PST tables, but they have correct FID/VID values.
+ */
+static struct powernow_k7_quirk {
+	uint32_t rcpusig;	/* Correct cpu signature */
+	uint32_t pcpusig;	/* PST cpu signature */
+} powernow_k7_quirk[] = {
+	{ 0x680, 0x780 }, 	/* Reported by Olaf 'Rhialto' Seibert */
+	{ 0x6a0, 0x781 },	/* Reported by Eric Schnoebelen */
+	{ 0x6a0, 0x7a0 },	/* Reported by Nino Dehne */
+	{ 0, 0 }
+};
+
+#endif	/* __i386__ */
+
+struct powernow_softc {
+	device_t		   sc_dev;
+	struct cpu_info		  *sc_ci;
+	struct sysctllog	  *sc_log;
+	struct powernow_cpu_state *sc_state;
+	const char		  *sc_tech;
+	char			  *sc_freqs;
+	size_t			   sc_freqs_len;
+	unsigned int		   sc_freqs_cur;
+	int			   sc_node_target;
+	int			   sc_node_current;
+	int			   sc_flags;
+};
+
+static int	powernow_match(device_t, cfdata_t, void *);
+static void	powernow_attach(device_t, device_t, void *);
+static int	powernow_detach(device_t, int);
+static int	powernow_sysctl(device_t);
+static int	powernow_sysctl_helper(SYSCTLFN_PROTO);
+
+#ifdef __i386__
+static int	powernow_k7_init(device_t);
+static int	powernow_k7_states(device_t, unsigned int, unsigned int);
+static int	powernow_k7_setperf(device_t, unsigned int);
+static bool	powernow_k7_check(uint32_t, uint32_t);
+static int	powernow_k7_decode_pst(struct powernow_softc *, uint8_t *,int);
+#endif
+
+static int	powernow_k8_init(device_t);
+static int	powernow_k8_states(device_t, unsigned int, unsigned int);
+static int	powernow_k8_setperf(device_t, unsigned int);
+static uint64_t powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl);
+static int	powernow_k8_decode_pst(struct powernow_cpu_state *, uint8_t *);
+
+CFATTACH_DECL_NEW(powernow, sizeof(struct powernow_softc),
+    powernow_match, powernow_attach, powernow_detach, NULL);
+
+static int
+powernow_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct cpufeature_attach_args *cfaa = aux;
+	struct cpu_info *ci = cfaa->ci;
+	uint32_t family, regs[4];
+
+	if (strcmp(cfaa->name, "powernow") != 0)
+		return 0;
+
+	if (cpu_vendor != CPUVENDOR_AMD)
+		return 0;
+
+	family = CPUID2FAMILY(ci->ci_signature);
+
+	if (family != 0x06 && family != 0x0f)
+		return 0;
+	else {
+		x86_cpuid(0x80000000, regs);
+
+		if (regs[0] < 0x80000007)
+			return 0;
+
+		x86_cpuid(0x80000007, regs);
+	}
+
+	return (regs[3] & AMD_PN_FID_VID) == AMD_PN_FID_VID;
+}
+
+static void
+powernow_attach(device_t parent, device_t self, void *aux)
+{
+	struct powernow_softc *sc = device_private(self);
+	struct cpufeature_attach_args *cfaa = aux;
+	struct cpu_info *ci = cfaa->ci;
+	uint32_t family;
+	int rv;
+
+	sc->sc_ci = ci;
+	sc->sc_dev = self;
+
+	sc->sc_flags = 0;
+	sc->sc_log = NULL;
+	sc->sc_tech = NULL;
+	sc->sc_state = NULL;
+	sc->sc_freqs = NULL;
+
+	family = CPUID2FAMILY(ci->ci_signature);
+
+	switch (family) {
+
+#ifdef __i386__
+	case 0x06:
+		rv = powernow_k7_init(self);
+		break;
+#endif
+	case 0x0f:
+		rv = powernow_k8_init(self);
+		break;
+
+	default:
+		rv = ENODEV;
+	}
+
+	if (rv != 0) {
+		aprint_normal(": failed to initialize (err %d)\n", rv);
+		return;
+	}
+
+	rv = powernow_sysctl(self);
+
+	if (rv != 0) {
+		aprint_normal(": failed to initialize sysctl (err %d)\n", rv);
+		return;
+	}
+
+	KASSERT(sc->sc_tech != NULL);
+
+	aprint_naive("\n");
+	aprint_normal(": AMD %s\n", sc->sc_tech);
+
+	(void)pmf_device_register(self, NULL, NULL);
+}
+
+static int
+powernow_detach(device_t self, int flags)
+{
+	struct powernow_softc *sc = device_private(self);
+
+	if (sc->sc_log != NULL)
+		sysctl_teardown(&sc->sc_log);
+
+	if (sc->sc_state != NULL)
+		kmem_free(sc->sc_state, sizeof(*sc->sc_state));
+
+	if (sc->sc_freqs != NULL)
+		kmem_free(sc->sc_freqs, sc->sc_freqs_len);
+
+	pmf_device_deregister(self);
+
+	return 0;
+}
+
+static int
+powernow_sysctl(device_t self)
+{
+	const struct sysctlnode *freqnode, *node, *pnownode;
+	struct powernow_softc *sc = device_private(self);
+	int rv;
+
+	/*
+	 * Setup the sysctl sub-tree machdep.powernow.
+	 */
+	rv = sysctl_createv(&sc->sc_log, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
+	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	rv = sysctl_createv(&sc->sc_log, 0, &node, &pnownode,
+	    0, CTLTYPE_NODE, "powernow", NULL,
+	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	rv = sysctl_createv(&sc->sc_log, 0, &pnownode, &freqnode,
+	    0, CTLTYPE_NODE, "frequency", NULL,
+	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
+	    powernow_sysctl_helper, 0, sc, 0, CTL_CREATE, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	sc->sc_node_target = node->sysctl_num;
+
+	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+	    0, CTLTYPE_INT, "current", NULL,
+	    powernow_sysctl_helper, 0, sc, 0, CTL_CREATE, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	sc->sc_node_current = node->sysctl_num;
+
+	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+	    0, CTLTYPE_STRING, "available", NULL,
+	    NULL, 0, sc->sc_freqs, sc->sc_freqs_len, CTL_CREATE, CTL_EOL);
+
+	if (rv != 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	sysctl_teardown(&sc->sc_log);
+	sc->sc_log = NULL;
+
+	return rv;
+}
+
+static int
+powernow_sysctl_helper(SYSCTLFN_ARGS)
+{
+	struct powernow_softc *sc;
+	struct sysctlnode node;
+	int fq, oldfq, error;
+	uint32_t family;
+	int rv;
+
+	fq = oldfq = 0;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	if (sc->sc_state == NULL)
+		return EOPNOTSUPP;
+
+	node.sysctl_data = &fq;
+
+	if (rnode->sysctl_num == sc->sc_node_target)
+		fq = oldfq = sc->sc_freqs_cur;
+	else if (rnode->sysctl_num == sc->sc_node_current)
+		fq = sc->sc_freqs_cur;
+	else
+		return EOPNOTSUPP;
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+
+	if (error || newp == NULL)
+		return error;
+
+	family = CPUID2FAMILY(sc->sc_ci->ci_signature);
+
+	if (rnode->sysctl_num == sc->sc_node_target && fq != oldfq) {
+
+		switch (family) {
+
+#ifdef __i386__
+		case 0x06:
+			rv = powernow_k7_setperf(sc->sc_dev, fq);
+			break;
+#endif
+		case 0x0f:
+			rv = powernow_k8_setperf(sc->sc_dev, fq);
+			break;
+
+		default:
+			return ENODEV;
+		}
+
+		if (rv != 0)
+			return EINVAL;
+
+		sc->sc_freqs_cur = fq;
+	}
+
+	return 0;
+}
+
+#ifdef __i386__
+
+static int
+powernow_k7_init(device_t self)
+{
+	struct powernow_softc *sc = device_private(self);
+	uint32_t currentfid, maxfid, mhz, startvid;
+	uint64_t status;
+	int i, rv, len;
+	char tmp[6];
+
+	sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP);
+
+	if (sc->sc_state == NULL)
+		return ENOMEM;
+
+	if (sc->sc_ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
+		sc->sc_flags |= PN7_FLAG_ERRATA_A0;
+
+	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+	maxfid = PN7_STA_MFID(status);
+	startvid = PN7_STA_SVID(status);
+	currentfid = PN7_STA_CFID(status);
+
+	mhz = sc->sc_ci->ci_data.cpu_cc_freq / 1000000;
+	sc->sc_state->fsb = mhz / (powernow_k7_fidtomult[currentfid] / 10);
+
+	if (powernow_k7_states(self, maxfid, startvid) == 0) {
+		rv = ENXIO;
+		goto fail;
+	}
+
+	if (sc->sc_state->n_states == 0) {
+		rv = ENODEV;
+		goto fail;
+	}
+
+	sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1;
+	sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP);
+
+	if (sc->sc_freqs == NULL) {
+		rv = ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < sc->sc_state->n_states; i++) {
+
+		/* Skip duplicated matches. */
+		if (sc->sc_state->state_table[i].freq ==
+		    sc->sc_state->state_table[i - 1].freq)
+			continue;
+
+		DPRINTF(("%s: cstate->state_table.freq=%d\n",
+			__func__, sc->sc_state->state_table[i].freq));
+		DPRINTF(("%s: fid=%d vid=%d\n", __func__,
+			sc->sc_state->state_table[i].fid,
+			sc->sc_state->state_table[i].vid));
+
+		len += snprintf(tmp, sizeof(tmp), "%d%s",
+		    sc->sc_state->state_table[i].freq,
+		    i < sc->sc_state->n_states - 1 ? " " : "");
+
+		DPRINTF(("%s: tmp=%s\n", __func__, tmp));
+
+		(void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len);
+	}
+
+	sc->sc_tech = ((sc->sc_flags & PN7_FLAG_DESKTOP_VRM) != 0) ?
+	    "Cool`n'Quiet K7" : "Powernow! K7";
+
+	return 0;
+
+fail:
+	kmem_free(sc->sc_state, sizeof(*sc->sc_state));
+	sc->sc_state = NULL;
+
+	return rv;
+}
+
+static int
+powernow_k7_states(device_t self, unsigned int fid, unsigned int vid)
+{
+	struct powernow_softc *sc = device_private(self);
+	struct powernow_cpu_state *cstate;
+	struct powernow_psb_s *psb;
+	struct powernow_pst_s *pst;
+	uint32_t cpusig, maxpst;
+	bool cpusig_ok;
+	uint8_t *p;
+
+	cstate = sc->sc_state;
+	cpusig = sc->sc_ci->ci_signature;
+
+	/*
+	 * Look in the 0xe0000 - 0x100000 physical address
+	 * range for the pst tables; 16 byte blocks
+	 */
+	for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START);
+	     p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN);
+	     p+= BIOS_STEP) {
+
+		if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
+
+			psb = (struct powernow_psb_s *)p;
+
+			if (psb->version != PN7_PSB_VERSION)
+				return 0;
+
+			cstate->sgtc = psb->ttime * cstate->fsb;
+
+			if (cstate->sgtc < 100 * cstate->fsb)
+				cstate->sgtc = 100 * cstate->fsb;
+
+			if (psb->flags & 1)
+				sc->sc_flags |= PN7_FLAG_DESKTOP_VRM;
+
+			p += sizeof(struct powernow_psb_s);
+
+			for (maxpst = 0; maxpst < psb->n_pst; maxpst++) {
+				pst = (struct powernow_pst_s*) p;
+
+				/*
+				 * Some models do not have same CPUID
+				 * signature in the PST table. Accept to
+				 * report frequencies via a quirk table
+				 * and fid/vid match.
+				 */
+				DPRINTF(("%s: cpusig=0x%x pst->sig:0x%x\n",
+				    __func__, cpusig, pst->signature));
+
+				cpusig_ok = powernow_k7_check(cpusig,
+				                              pst->signature);
+
+				if ((cpusig_ok != false &&
+				    (fid == pst->fid && vid == pst->vid))) {
+					DPRINTF(("%s: pst->signature ok\n",
+					    __func__));
+					if (abs(cstate->fsb - pst->pll) > 5)
+						continue;
+					cstate->n_states = pst->n_states;
+					return (powernow_k7_decode_pst(sc,
+					    p + sizeof(struct powernow_pst_s),
+					    cstate->n_states));
+
+				}
+
+				p += sizeof(struct powernow_pst_s) +
+				    (2 * pst->n_states);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
+powernow_k7_setperf(device_t self, unsigned int freq)
+{
+	struct powernow_softc *sc = device_private(self);
+	int cvid, cfid, vid = 0, fid = 0;
+	uint64_t status, ctl;
+	unsigned int i;
+
+	DPRINTF(("%s: cstate->n_states=%d\n",
+		__func__, sc->sc_state->n_states));
+
+	for (i = 0; i < sc->sc_state->n_states; i++) {
+
+		if (sc->sc_state->state_table[i].freq >= freq) {
+			DPRINTF(("%s: freq=%d\n", __func__, freq));
+			fid = sc->sc_state->state_table[i].fid;
+			vid = sc->sc_state->state_table[i].vid;
+			DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid));
+			break;
+		}
+	}
+
+	if (fid == 0 || vid == 0)
+		return 0;
+
+	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+	cfid = PN7_STA_CFID(status);
+	cvid = PN7_STA_CVID(status);
+
+	/*
+	 * We're already at the requested level.
+	 */
+	if (fid == cfid && vid == cvid)
+		return 0;
+
+	ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
+
+	ctl |= PN7_CTR_FID(fid);
+	ctl |= PN7_CTR_VID(vid);
+	ctl |= PN7_CTR_SGTC(sc->sc_state->sgtc);
+
+	if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0)
+		x86_disable_intr();
+
+	if (powernow_k7_fidtomult[fid] < powernow_k7_fidtomult[cfid]) {
+
+		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
+
+		if (vid != cvid)
+			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
+
+	} else {
+
+		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
+
+		if (fid != cfid)
+			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
+	}
+
+	if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0)
+		x86_enable_intr();
+
+	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+
+	cfid = PN7_STA_CFID(status);
+	cvid = PN7_STA_CVID(status);
+
+	if (cfid == fid || cvid == vid)
+		freq = sc->sc_state->state_table[i].freq;
+
+	return 0;
+}
+
+static bool
+powernow_k7_check(uint32_t real_cpusig, uint32_t pst_cpusig)
+{
+	int j;
+
+	if (real_cpusig == pst_cpusig)
+		return true;
+
+	for (j = 0; powernow_k7_quirk[j].rcpusig != 0; j++) {
+
+		if ((real_cpusig == powernow_k7_quirk[j].rcpusig) &&
+		    (pst_cpusig == powernow_k7_quirk[j].pcpusig))
+			return true;
+	}
+
+	return false;
+}
+
+static int
+powernow_k7_decode_pst(struct powernow_softc *sc, uint8_t *p, int npst)
+{
+	struct powernow_cpu_state *cstate = sc->sc_state;
+	struct powernow_state state;
+	int i, j, n;
+
+	for (n = 0, i = 0; i < npst; ++i) {
+
+		state.fid = *p++;
+		state.vid = *p++;
+		state.freq = powernow_k7_fidtomult[state.fid]/10 * cstate->fsb;
+
+		if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0 &&
+		    (powernow_k7_fidtomult[state.fid] % 10) == 5)
+			continue;
+
+		j = n;
+
+		while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
+
+			(void)memcpy(&cstate->state_table[j],
+			    &cstate->state_table[j - 1],
+			    sizeof(struct powernow_state));
+
+			--j;
+		}
+
+		(void)memcpy(&cstate->state_table[j], &state,
+		    sizeof(struct powernow_state));
+
+		++n;
+	}
+
+	/*
+	 * Fix powernow_max_states, if errata_a0 gave
+	 * us less states than expected.
+	 */
+	cstate->n_states = n;
+
+	return 1;
+}
+
+#endif	/* __i386__ */
+
+static int
+powernow_k8_init(device_t self)
+{
+	struct powernow_softc *sc = device_private(self);
+	uint32_t i, maxfid, maxvid;
+	uint64_t status;
+	int len, rv;
+	char tmp[6];
+
+	sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP);
+
+	if (sc->sc_state == NULL)
+		return ENOMEM;
+
+	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+	maxfid = PN8_STA_MFID(status);
+	maxvid = PN8_STA_MVID(status);
+
+	if (powernow_k8_states(self, maxfid, maxvid) == 0) {
+		rv = ENXIO;
+		goto fail;
+	}
+
+	if (sc->sc_state->n_states == 0) {
+		rv = ENODEV;
+		goto fail;
+	}
+
+	sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1;
+	sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP);
+
+	if (sc->sc_freqs == NULL) {
+		rv = ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < sc->sc_state->n_states; i++) {
+
+		DPRINTF(("%s: cstate->state_table.freq=%d\n",
+			__func__, sc->sc_state->state_table[i].freq));
+
+		DPRINTF(("%s: fid=%d vid=%d\n", __func__,
+			sc->sc_state->state_table[i].fid,
+			sc->sc_state->state_table[i].vid));
+
+		len += snprintf(tmp, sizeof(tmp), "%d%s",
+		    sc->sc_state->state_table[i].freq,
+		    i < sc->sc_state->n_states - 1 ? " " : "");
+
+		DPRINTF(("%s: tmp=%s\n", __func__, tmp));
+
+		(void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len);
+	}
+
+	/*
+	 * If start FID is different to max FID, then it is a mobile
+	 * processor. If not, it is a low powered desktop processor.
+	 */
+	sc->sc_tech = (PN8_STA_SFID(status) != PN8_STA_MFID(status)) ?
+	    "PowerNow!" : "Cool`n'Quiet";
+
+	return 0;
+
+fail:
+	kmem_free(sc->sc_state, sizeof(*sc->sc_state));
+	sc->sc_state = NULL;
+
+	return rv;
+}
+
+static int
+powernow_k8_states(device_t self, unsigned int fid, unsigned int vid)
+{
+	struct powernow_softc *sc = device_private(self);
+	struct powernow_cpu_state *cstate;
+	struct powernow_psb_s *psb;
+	struct powernow_pst_s *pst;
+	uint32_t cpusig;
+	uint8_t *p;
+	int i;
+
+	cstate = sc->sc_state;
+	cpusig = sc->sc_ci->ci_signature;
+
+	DPRINTF(("%s: before the for loop\n", __func__));
+
+	for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START);
+	     p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p += 16) {
+
+		if (memcmp(p, "AMDK7PNOW!", 10) != 0)
+			continue;
+
+		DPRINTF(("%s: inside the for loop\n", __func__));
+
+		psb = (struct powernow_psb_s *)p;
+
+		if (psb->version != 0x14) {
+			DPRINTF(("%s: psb->version != 0x14\n", __func__));
+			return 0;
+		}
+
+		cstate->vst = psb->ttime;
+		cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
+		cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
+		cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
+		cstate->low = PN8_PSB_TO_BATT(psb->reserved);
+
+		p += sizeof(struct powernow_psb_s);
+
+		for(i = 0; i < psb->n_pst; ++i) {
+
+			pst = (struct powernow_pst_s *)p;
+
+			cstate->pll = pst->pll;
+			cstate->n_states = pst->n_states;
+
+			if (cpusig == pst->signature &&
+			    pst->fid == fid && pst->vid == vid) {
+
+				DPRINTF(("%s: cpusig = sig\n", __func__));
+
+				return (powernow_k8_decode_pst(cstate,
+				    p+= sizeof(struct powernow_pst_s)));
+			}
+
+			p += sizeof(struct powernow_pst_s) +
+			    2 * cstate->n_states;
+		}
+	}
+
+	DPRINTF(("%s: returns 0!\n", __func__));
+
+	return 0;
+}
+
+static int
+powernow_k8_setperf(device_t self, unsigned int freq)
+{
+	struct powernow_softc *sc = device_private(self);
+	int cfid, cvid, fid = 0, vid = 0;
+	uint64_t status;
+	unsigned int i;
+	uint32_t val;
+	int rvo;
+
+	/*
+	 * We dont do a "pending wait" here, given
+	 * that we need to ensure that the change
+	 * pending bit is not stuck.
+	 */
+	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+
+	if (PN8_STA_PENDING(status))
+		return 1;
+
+	cfid = PN8_STA_CFID(status);
+	cvid = PN8_STA_CVID(status);
+
+	DPRINTF(("%s: sc->sc_state->n_states=%d\n",
+		__func__, sc->sc_state->n_states));
+
+	for (i = 0; i < sc->sc_state->n_states; i++) {
+
+		if (sc->sc_state->state_table[i].freq >= freq) {
+			DPRINTF(("%s: freq=%d\n", __func__, freq));
+			fid = sc->sc_state->state_table[i].fid;
+			vid = sc->sc_state->state_table[i].vid;
+			DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid));
+			break;
+		}
+
+	}
+
+	if (fid == cfid && vid == cvid)
+		return 0;
+
+	/*
+	 * Phase 1: raise the core voltage to the
+	 * requested VID if frequency is going up.
+	 */
+	while (cvid > vid) {
+		val = cvid - (1 << sc->sc_state->mvs);
+		status = powernow_k8_fidvid(cfid, (val > 0) ? val : 0, 1ULL);
+		cvid = PN8_STA_CVID(status);
+		COUNT_OFF_VST(sc->sc_state->vst);
+	}
+
+	/*
+	 * Then raise to voltage + RVO (if required).
+	 */
+	for (rvo = sc->sc_state->rvo; rvo > 0 && cvid > 0; --rvo) {
+		/*
+		 * XXX:	It is not clear from the specification if we have
+		 *	to do that in 0.25 step or in MVS. Therefore do it
+		 *	as it is done under Linux.
+		 */
+		status = powernow_k8_fidvid(cfid, cvid - 1, 1ULL);
+		cvid = PN8_STA_CVID(status);
+		COUNT_OFF_VST(sc->sc_state->vst);
+	}
+
+	/*
+	 * Phase 2: change to requested core frequency.
+	 */
+	if (cfid != fid) {
+		uint32_t vco_fid, vco_cfid;
+
+		vco_fid = FID_TO_VCO_FID(fid);
+		vco_cfid = FID_TO_VCO_FID(cfid);
+
+		while (abs(vco_fid - vco_cfid) > 2) {
+
+			if (fid > cfid) {
+				if (cfid > 6)
+					val = cfid + 2;
+				else
+					val = FID_TO_VCO_FID(cfid) + 2;
+			} else
+				val = cfid - 2;
+
+			status = powernow_k8_fidvid(val, cvid,
+			    (uint64_t)sc->sc_state->pll * 1000 / 5);
+
+			cfid = PN8_STA_CFID(status);
+			COUNT_OFF_IRT(sc->sc_state->irt);
+			vco_cfid = FID_TO_VCO_FID(cfid);
+		}
+
+
+		status = powernow_k8_fidvid(fid, cvid,
+		    (uint64_t)sc->sc_state->pll * 1000 / 5);
+
+		cfid = PN8_STA_CFID(status);
+		COUNT_OFF_IRT(sc->sc_state->irt);
+	}
+
+	/*
+	 * Phase 3: change to requested voltage.
+	 */
+	if (cvid != vid) {
+		status = powernow_k8_fidvid(cfid, vid, 1ULL);
+		cvid = PN8_STA_CVID(status);
+		COUNT_OFF_VST(sc->sc_state->vst);
+	}
+
+	if (cfid == fid || cvid == vid)
+		freq = sc->sc_state->state_table[i].freq;
+
+	return 0;
+}
+
+static uint64_t
+powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl)
+{
+	struct msr_rw_info msr;
+	uint64_t status, xc;
+
+	msr.msr_read = false;
+	msr.msr_value = (ctrl << 32) | (1ULL << 16) | (vid << 8) | fid;
+	msr.msr_type = MSR_AMDK7_FIDVID_CTL;
+
+	xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
+	xc_wait(xc);
+
+	do {
+		status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+
+	} while (PN8_STA_PENDING(status));
+
+	return status;
+}
+
+/*
+ * Given a set of pair of FID/VID, and a number of performance
+ * states, compute a state table via an insertion sort.
+ */
+static int
+powernow_k8_decode_pst(struct powernow_cpu_state *cstate, uint8_t *p)
+{
+	struct powernow_state state;
+	int i, j, n;
+
+	for (n = 0, i = 0; i < cstate->n_states; i++) {
+
+		state.fid = *p++;
+		state.vid = *p++;
+
+		/*
+		 * The minimum supported frequency per the data sheet is
+		 * 800 MHz. The maximum supported frequency is 5000 MHz.
+		 */
+		state.freq = 800 + state.fid * 100;
+		j = n;
+
+		while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
+
+			(void)memcpy(&cstate->state_table[j],
+			    &cstate->state_table[j - 1],
+			    sizeof(struct powernow_state));
+
+			--j;
+		}
+
+		(void)memcpy(&cstate->state_table[j], &state,
+		    sizeof(struct powernow_state));
+
+		n++;
+	}
+
+	return 1;
+}
+
+MODULE(MODULE_CLASS_DRIVER, powernow, NULL);
+
+#ifdef _MODULE
+#include "ioconf.c"
+#endif
+
+static int
+powernow_modcmd(modcmd_t cmd, void *aux)
+{
+	int error = 0;
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef _MODULE
+		error = config_init_component(cfdriver_ioconf_powernow,
+		    cfattach_ioconf_powernow, cfdata_ioconf_powernow);
+#endif
+		return error;
+	case MODULE_CMD_FINI:
+#ifdef _MODULE
+		error = config_fini_component(cfdriver_ioconf_powernow,
+		    cfattach_ioconf_powernow, cfdata_ioconf_powernow);
+#endif
+		return error;
+	default:
+		return ENOTTY;
+	}
+}

Reply via email to