diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 8 | ||||
-rw-r--r-- | sys/arch/i386/i386/powernow.c | 105 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 6 | ||||
-rw-r--r-- | sys/arch/i386/include/specialreg.h | 5 |
5 files changed, 123 insertions, 4 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 2a2b58a6abc..eae2de26a13 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.111 2003/12/20 18:23:17 tedu Exp $ +# $OpenBSD: files.i386,v 1.112 2004/04/02 22:28:40 tedu Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -33,6 +33,7 @@ file arch/i386/i386/microtime.s file arch/i386/i386/ns_cksum.c ns file arch/i386/i386/p4tcc.c !small_kernel & i686_cpu file arch/i386/i386/pmap.c +file arch/i386/i386/powernow.c !small_kernel file arch/i386/i386/process_machdep.c file arch/i386/i386/procfs_machdep.c procfs file arch/i386/i386/random.s diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index c9476af4188..04f78890f05 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.287 2004/03/26 04:00:59 drahn Exp $ */ +/* $OpenBSD: machdep.c,v 1.288 2004/04/02 22:28:40 tedu Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -1641,6 +1641,12 @@ amd_family5_setup(cpu_device, model, step) * XXX the pmap somehow. How does the MP branch do this? */ break; + case 12: + case 13: +#ifndef SMALL_KERNEL + k6_powernow_init(); +#endif + break; } } diff --git a/sys/arch/i386/i386/powernow.c b/sys/arch/i386/i386/powernow.c new file mode 100644 index 00000000000..ef9982a36b3 --- /dev/null +++ b/sys/arch/i386/i386/powernow.c @@ -0,0 +1,105 @@ +/* $OpenBSD */ +/* + * Copyright (c) 2004 Ted Unangst + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * AMD K6 PowerNow driver, see AMD tech doc #23525 + * Numerous hints from Linux cpufreq driver + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/specialreg.h> +#include <machine/pio.h> + +/* table 27 in amd 23535. entries after 45 taken from linux cpufreq */ +struct { + int mult; /* not actually used, maybe for cpuspeed */ + int magic; +} k6_multipliers[] = { + { 20, 4 }, + { 30, 5 }, + { 35, 7 }, + { 40, 2 }, + { 45, 0 }, + { 55, 3 }, + { 50, 1 }, + { 60, 6 }, +}; +#define NUM_K6_ENTRIES (sizeof k6_multipliers / sizeof k6_multipliers[0]) + +int k6_maxindex; /* no setting higher than this */ + +/* linux says: "it doesn't matter where, as long as it is unused */ +#define K6PORT 0xfff0 + +void +k6_powernow_init(void) +{ + uint64_t msrval; + uint32_t portval; + int i; + + /* on */ + msrval = K6PORT | 0x1; + wrmsr(MSR_K6_EPMR, msrval); + /* read */ + portval = inl(K6PORT + 8); + /* off */ + wrmsr(MSR_K6_EPMR, 0LL); + + portval = (portval >> 5) & 7; + + for (i = 0; i < NUM_K6_ENTRIES; i++) + if (portval == k6_multipliers[i].magic) { + k6_maxindex = i; + break; + } + if (i == NUM_K6_ENTRIES) { + printf("bad value for current multiplier\n"); + return; + } + + cpu_setperf = k6_powernow_setperf; +} + +int +k6_powernow_setperf(int level) +{ + uint64_t msrval; + uint32_t portval; + int index; + + index = level * k6_maxindex / 100; + + /* on */ + msrval = K6PORT | 0x1; + wrmsr(MSR_K6_EPMR, msrval); + /* read and update */ + portval = inl(K6PORT + 8); + portval &= 0xf; + portval |= 1 << 12 | 1 << 10 | 1 << 9 | + k6_multipliers[index].magic << 5; + outl(K6PORT + 8, portval); + /* off */ + wrmsr(MSR_K6_EPMR, 0LL); + + return (0); +} diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 13b9e47a513..a82def3a6ce 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.58 2004/02/14 15:09:22 grange Exp $ */ +/* $OpenBSD: cpu.h,v 1.59 2004/04/02 22:28:41 tedu Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -208,6 +208,10 @@ void p4tcc_init(int, int); int p4tcc_setperf(int); #endif +void k6_powernow_init(void); +int k6_powernow_setperf(int); + + /* npx.c */ void npxdrop(void); void npxsave(void); diff --git a/sys/arch/i386/include/specialreg.h b/sys/arch/i386/include/specialreg.h index fbcc328e6f5..15c87a430ab 100644 --- a/sys/arch/i386/include/specialreg.h +++ b/sys/arch/i386/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.21 2004/02/19 22:33:29 grange Exp $ */ +/* $OpenBSD: specialreg.h,v 1.22 2004/04/02 22:28:41 tedu Exp $ */ /* $NetBSD: specialreg.h,v 1.7 1994/10/27 04:16:26 cgd Exp $ */ /*- @@ -233,6 +233,9 @@ #define MSR_MC3_ADDR 0x412 #define MSR_MC3_MISC 0x413 +/* AMD MSRs */ +#define MSR_K6_EPMR 0xc0000086 + /* * Constants related to MTRRs */ |