diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2006-03-08 03:33:22 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2006-03-08 03:33:22 +0000 |
commit | 86a2e554404338ac982b3b81b956f08e324aebc0 (patch) | |
tree | 2440e43a112194e25af13ccd000055593210af52 /sys/arch | |
parent | 04c30bf2d76475394d2e5b4f46c78daa68de854b (diff) |
Patch from Gordon Klock to update AMD PowerNow K8 support on i386,
and to add amd64 K8 support from FreeBSD.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/identcpu.c | 34 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/powernow-k8.c | 404 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 6 | ||||
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 4 | ||||
-rw-r--r-- | sys/arch/i386/i386/powernow-k8.c | 60 |
6 files changed, 464 insertions, 47 deletions
diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index e66a1f8d3e3..d0e1381527f 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.7 2006/03/07 05:21:40 jsg Exp $ */ +/* $OpenBSD: identcpu.c,v 1.8 2006/03/08 03:33:21 uwe Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -94,6 +94,18 @@ const struct { { CPUIDECX_SSE3, "SSE3" } }; +const struct { + u_int32_t mask; + const char * name; +} amd_pn_flags[] = { + { 0x01, "TS"}, + { 0x02, "FID"}, + { 0x04, "VID"}, + { 0x08, "TTP"}, + { 0x10, "TM"}, + { 0x20, "STC"} +}; + int cpu_amd64speed(int *freq) { @@ -105,13 +117,14 @@ void identifycpu(struct cpu_info *ci) { u_int64_t last_tsc; - u_int32_t dummy, val; + u_int32_t dummy, val, pnfeatset; u_int32_t brand[12]; int i, max; char *brandstr_from, *brandstr_to; int skipspace; CPUID(1, ci->ci_signature, val, dummy, ci->ci_feature_flags); + CPUID(0x80000000, pnfeatset, dummy, dummy, dummy); CPUID(0x80000001, dummy, dummy, dummy, ci->ci_feature_eflags); CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]); @@ -168,6 +181,23 @@ identifycpu(struct cpu_info *ci) printf("\n"); x86_print_cacheinfo(ci); + +#ifndef MULTIPROCESSOR + if (pnfeatset > 0x80000007) { + CPUID(0x80000007, dummy, dummy, dummy, pnfeatset); + printf("%s: AMD Powernow:", ci->ci_dev->dv_xname); + for (i = 0; i < 6; i++) { + if (pnfeatset & amd_pn_flags[i].mask) + printf(" %s", amd_pn_flags[i].name); + } + printf("\n"); + + if (pnfeatset & 0x06) { + if ((ci->ci_signature & 0xF00) == 0xf00) + k8_powernow_init(); + } + } +#endif } void diff --git a/sys/arch/amd64/amd64/powernow-k8.c b/sys/arch/amd64/amd64/powernow-k8.c new file mode 100644 index 00000000000..29c4f4f15da --- /dev/null +++ b/sys/arch/amd64/amd64/powernow-k8.c @@ -0,0 +1,404 @@ +/* $OpenBSD: powernow-k8.c,v 1.1 2006/03/08 03:33:21 uwe Exp $ */ +/* + * Copyright (c) 2004 Martin Végiard. + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + * + * Copyright (c) 2004-2005 Bruno Ducrot + * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp> + * + * 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. + */ +/* AMD POWERNOW K8 driver */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/sysctl.h> + +#include <dev/isa/isareg.h> +#include <amd64/include/isa_machdep.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/bus.h> + +#define BIOS_START 0xe0000 +#define BIOS_LEN 0x20000 + +extern int cpuspeed; + +/* + * MSRs and bits used by Powernow technology + */ +#define MSR_AMDK7_FIDVID_CTL 0xc0010041 +#define MSR_AMDK7_FIDVID_STATUS 0xc0010042 + +/* Bitfields used by K8 */ + +#define PN8_CTR_FID(x) ((x) & 0x3f) +#define PN8_CTR_VID(x) (((x) & 0x1f) << 8) +#define PN8_CTR_PENDING(x) (((x) & 1) << 32) + +#define PN8_STA_CFID(x) ((x) & 0x3f) +#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f) +#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f) +#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01) +#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f) +#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f) +#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f) + +/* Reserved1 to powernow k8 configuration */ +#define PN8_PSB_TO_RVO(x) ((x) & 0x03) +#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03) +#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03) +#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03) + +/* ACPI ctr_val status register to powernow k8 configuration */ +#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f) +#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f) +#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f) +#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03) +#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f) +#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03) +#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03) + +#define WRITE_FIDVID(fid, vid, ctrl) \ + wrmsr(MSR_AMDK7_FIDVID_CTL, \ + (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) + + +#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt))) +#define COUNT_OFF_VST(vst) DELAY(20 * (vst)) + +#define FID_TO_VCO_FID(fid) \ + (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) + +#define POWERNOW_MAX_STATES 16 + +struct k8pnow_state { + int freq; + uint8_t fid; + uint8_t vid; +}; + +struct k8pnow_cpu_state { + struct k8pnow_state state_table[POWERNOW_MAX_STATES]; + unsigned int n_states; + unsigned int sgtc; + unsigned int vst; + unsigned int mvs; + unsigned int pll; + unsigned int rvo; + unsigned int irt; + int low; +}; + +struct psb_s { + char signature[10]; /* AMDK7PNOW! */ + uint8_t version; + uint8_t flags; + uint16_t ttime; /* Min Settling time */ + uint8_t reserved; + uint8_t n_pst; +}; + +struct pst_s { + uint32_t cpuid; + uint8_t pll; + uint8_t fid; + uint8_t vid; + uint8_t n_states; +}; + +struct k8pnow_cpu_state *k8pnow_current_state; + +/* + * Prototypes + */ +int k8pnow_read_pending_wait(uint64_t *); +int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *); +int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int, + unsigned int); + +int k8pnow_read_pending_wait(uint64_t * status) { + unsigned int i = 1000; + while(i--) { + *status = rdmsr(MSR_AMDK7_FIDVID_STATUS); + if (!PN8_STA_PENDING(*status)) + return 0; + + } + printf("k8pnow_read_pending_wait: change pending stuck.\n"); + return 1; +} + +int +k8_powernow_setperf(int level) +{ + unsigned int i, low, high, freq; + uint64_t status; + int cfid, cvid, fid = 0, vid = 0; + int rvo; + u_int val; + struct k8pnow_cpu_state *cstate; + + /* + * We dont do a k8pnow_read_pending_wait here, need to ensure that the + * change pending bit isn't stuck, + */ + status = rdmsr(MSR_AMDK7_FIDVID_STATUS); + if (PN8_STA_PENDING(status)) + return 1; + cfid = PN8_STA_CFID(status); + cvid = PN8_STA_CVID(status); + + cstate = k8pnow_current_state; + low = cstate->state_table[0].freq; + high = cstate->state_table[cstate->n_states-1].freq; + + freq = low + (high - low) * level / 100; + + for (i = 0; i < cstate->n_states; i++) { + if (cstate->state_table[i].freq >= freq) { + fid = cstate->state_table[i].fid; + vid = cstate->state_table[i].vid; + break; + } + } + + if (fid == cfid && vid == cvid) + return (0); + + /* + * Phase 1: Raise core voltage to requested VID if frequency is + * going up. + */ + while (cvid > vid) { + val = cvid - (1 << cstate->mvs); + WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL); + if (k8pnow_read_pending_wait(&status)) + return 1; + cvid = PN8_STA_CVID(status); + COUNT_OFF_VST(cstate->vst); + } + + /* ... then raise to voltage + RVO (if required) */ + for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) { + /* XXX It's not clear from spec if we have to do that + * in 0.25 step or in MVS. Therefore do it as it's done + * under Linux */ + WRITE_FIDVID(cfid, cvid - 1, 1ULL); + if (k8pnow_read_pending_wait(&status)) + return 1; + cvid = PN8_STA_CVID(status); + COUNT_OFF_VST(cstate->vst); + } + + /* Phase 2: change to requested core frequency */ + if (cfid != fid) { + u_int 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; + WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5); + + if (k8pnow_read_pending_wait(&status)) + return 1; + cfid = PN8_STA_CFID(status); + COUNT_OFF_IRT(cstate->irt); + + vco_cfid = FID_TO_VCO_FID(cfid); + } + + WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5); + if (k8pnow_read_pending_wait(&status)) + return 1; + cfid = PN8_STA_CFID(status); + COUNT_OFF_IRT(cstate->irt); + } + + /* Phase 3: change to requested voltage */ + if (cvid != vid) { + WRITE_FIDVID(cfid, vid, 1ULL); + if (k8pnow_read_pending_wait(&status)) + return 1; + cvid = PN8_STA_CVID(status); + COUNT_OFF_VST(cstate->vst); + } + + /* Check if transition failed. */ + if (cfid != fid || cvid != vid) + return (1); + + cpuspeed = cstate->state_table[i].freq; + return (0); +} + +/* + * Given a set of pair of fid/vid, and number of performance states, + * compute state_table via an insertion sort. + */ +int +k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p) +{ + int i, j, n; + struct k8pnow_state state; + 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 800MHz + * The maximum supported frequency is 5000MHz. + */ + state.freq = 800 + state.fid * 100; + j = n; + while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { + memcpy(&cstate->state_table[j], + &cstate->state_table[j - 1], + sizeof(struct k8pnow_state)); + --j; + } + memcpy(&cstate->state_table[j], &state, + sizeof(struct k8pnow_state)); + n++; + } + return 1; +} + +int +k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig, + unsigned int fid, unsigned int vid) +{ + struct psb_s *psb; + struct pst_s *pst; + uint8_t *p; + int i; + + for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START); + p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p += 16) { + if (memcmp(p, "AMDK7PNOW!", 10) == 0) { + psb = (struct psb_s *)p; + if (psb->version != 0x14) + 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 psb_s); + + for(i = 0; i < psb->n_pst; ++i) { + pst = (struct pst_s *) p; + + cstate->pll = pst->pll; + cstate->n_states = pst->n_states; + if (cpusig == pst->cpuid && + pst->fid == fid && pst->vid == vid) { + return (k8pnow_decode_pst(cstate, + p+= sizeof (struct pst_s))); + } + p += sizeof(struct pst_s) + 2 * cstate->n_states; + } + } + } + + return 0; + +} + +void +k8_powernow_init(void) +{ + uint64_t status; + u_int maxfid, maxvid, i; + struct k8pnow_cpu_state *cstate; + struct k8pnow_state *state; + struct cpu_info * ci; + char * techname = NULL; + ci = curcpu(); + + cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT); + if (!cstate) + return; + + status = rdmsr(MSR_AMDK7_FIDVID_STATUS); + maxfid = PN8_STA_MFID(status); + maxvid = PN8_STA_MVID(status); + + /* + * If start FID is different to max FID, then it is a + * mobile processor. If not, it is a low powered desktop + * processor. + */ + if (PN8_STA_SFID(status) != PN8_STA_MFID(status)) + techname = "PowerNow! K8"; + else + techname = "Cool`n'Quiet K8"; + + if (k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid)) { + if (cstate->n_states) { + printf("%s: AMD %s available states ", + ci->ci_dev->dv_xname, techname); + for(i= 0; i < cstate->n_states; i++) { + state = &cstate->state_table[i]; + printf("%c%d", i==0 ? '(' : ',', + state->freq); + } + printf(")\n"); + k8pnow_current_state = cstate; + cpu_setperf = k8_powernow_setperf; + } + } +} diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index 7d40cbcf4a3..9655fff362e 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.19 2006/02/12 19:55:36 miod Exp $ +# $OpenBSD: files.amd64,v 1.20 2006/03/08 03:33:21 uwe Exp $ maxpartitions 16 maxusers 2 16 128 @@ -56,6 +56,7 @@ file arch/amd64/amd64/kgdb_machdep.c kgdb file arch/amd64/isa/clock.c file dev/clock_subr.c +file arch/amd64/amd64/powernow-k8.c include "dev/mii/files.mii" diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index d48c00bf267..372a26d080c 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.17 2005/12/13 00:18:19 jsg Exp $ */ +/* $OpenBSD: cpu.h,v 1.18 2006/03/08 03:33:21 uwe Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -305,6 +305,10 @@ void kgdb_port_init(void); void x86_bus_space_init(void); void x86_bus_space_mallocok(void); +/* powernow-k8.c */ +void k8_powernow_init(void); +int k8_powernow_setperf(int); + #endif /* _KERNEL */ /* diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index a26e4980b54..79edd4e2a7a 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.341 2006/03/07 05:18:08 jsg Exp $ */ +/* $OpenBSD: machdep.c,v 1.342 2006/03/08 03:33:21 uwe Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -1430,6 +1430,7 @@ amd_family6_setup(struct cpu_info *ci) pagezero = sse2_pagezero; else pagezero = i686_pagezero; +#if !defined(MULTIPROCESSOR) cpuid(0x80000000, regs); if (regs[0] > 0x80000007) { cpuid(0x80000007, regs); @@ -1451,6 +1452,7 @@ amd_family6_setup(struct cpu_info *ci) } } } +#endif #endif } diff --git a/sys/arch/i386/i386/powernow-k8.c b/sys/arch/i386/i386/powernow-k8.c index 16c05e1690c..4ee4d61811c 100644 --- a/sys/arch/i386/i386/powernow-k8.c +++ b/sys/arch/i386/i386/powernow-k8.c @@ -1,4 +1,4 @@ -/* $OpenBSD: powernow-k8.c,v 1.3 2005/11/26 11:22:12 tedu Exp $ */ +/* $OpenBSD: powernow-k8.c,v 1.4 2006/03/08 03:33:21 uwe Exp $ */ /* * Copyright (c) 2004 Martin Végiard. * All rights reserved. @@ -112,29 +112,6 @@ #define FID_TO_VCO_FID(fid) \ (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) -/* - * Divide each value by 10 to get the processor multiplier. - */ - -static int pn8_fid_to_mult[32] = { - 40, 50, 60, 70, 80, 90, 100, 110, - 120, 130, 140, 150, 160, 170, 180, 190, - 220, 230, 240, 250, 260, 270, 280, 290, - 300, 310, 320, 330, 340, 350, -}; - -/* - * Units are in mV. - */ - -/* Desktop and Mobile VRM (K8) */ -static int pn8_vid_to_volts[] = { - 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375, - 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175, - 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, - 950, 925, 900, 875, 850, 825, 800, 0, -}; - #define POWERNOW_MAX_STATES 16 struct k8pnow_state { @@ -146,7 +123,6 @@ struct k8pnow_state { struct k8pnow_cpu_state { struct k8pnow_state state_table[POWERNOW_MAX_STATES]; unsigned int n_states; - unsigned int fsb; unsigned int sgtc; unsigned int vst; unsigned int mvs; @@ -154,7 +130,6 @@ struct k8pnow_cpu_state { unsigned int rvo; unsigned int irt; int low; - int *vid_to_volts; }; struct psb_s { @@ -174,7 +149,7 @@ struct pst_s { uint8_t n_states; }; -struct k8pnow_cpu_state *k8pnow_current_state[I386_MAXPROCS]; +struct k8pnow_cpu_state *k8pnow_current_state = NULL; /* * Prototypes @@ -216,7 +191,7 @@ k8_powernow_setperf(int level) cfid = PN8_STA_CFID(status); cvid = PN8_STA_CVID(status); - cstate = k8pnow_current_state[cpu_number()]; + cstate = k8pnow_current_state; low = cstate->state_table[0].freq; high = cstate->state_table[cstate->n_states-1].freq; @@ -273,8 +248,7 @@ k8_powernow_setperf(int level) val = FID_TO_VCO_FID(cfid) + 2; } else val = cfid - 2; - WRITE_FIDVID(val, cvid, cstate->pll * - (uint64_t)cstate->fsb); + WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5); if (k8pnow_read_pending_wait(&status)) return 1; @@ -284,7 +258,7 @@ k8_powernow_setperf(int level) vco_cfid = FID_TO_VCO_FID(cfid); } - WRITE_FIDVID(fid, cvid, cstate->pll * (uint64_t)cstate->fsb); + WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5); if (k8pnow_read_pending_wait(&status)) return 1; cfid = PN8_STA_CFID(status); @@ -304,7 +278,7 @@ k8_powernow_setperf(int level) if (cfid != fid || cvid != vid) return (1); - pentium_mhz = ((cstate->state_table[i].freq / 100000)+1)*100; + pentium_mhz = cstate->state_table[i].freq; return (0); } @@ -320,8 +294,12 @@ k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p) for (n = 0, i = 0; i < cstate->n_states; i++) { state.fid = *p++; state.vid = *p++; - - state.freq = 100 * pn8_fid_to_mult[state.fid >>1] *cstate->fsb; + + /* + * The minimum supported frequency per the data sheet is 800MHz + * The maximum supported frequency is 5000MHz. + */ + state.freq = 800 + state.fid * 100; j = n; while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { memcpy(&cstate->state_table[j], @@ -382,13 +360,16 @@ void k8_powernow_init(void) { uint64_t status; - u_int maxfid, maxvid, currentfid, i; + u_int maxfid, maxvid, i; struct k8pnow_cpu_state *cstate; struct k8pnow_state *state; struct cpu_info * ci; char * techname = NULL; ci = curcpu(); + if(k8pnow_current_state) + return; + cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT); if (!cstate) return; @@ -396,12 +377,7 @@ k8_powernow_init(void) status = rdmsr(MSR_AMDK7_FIDVID_STATUS); maxfid = PN8_STA_MFID(status); maxvid = PN8_STA_MVID(status); - currentfid = PN8_STA_CFID(status); - - CPU_CLOCKUPDATE(); - cstate->fsb = pentium_base_tsc/ 100000/ pn8_fid_to_mult[currentfid>>1]; - cstate->vid_to_volts = pn8_vid_to_volts; /* * If start FID is different to max FID, then it is a * mobile processor. If not, it is a low powered desktop @@ -419,10 +395,10 @@ k8_powernow_init(void) for(i= 0; i < cstate->n_states; i++) { state = &cstate->state_table[i]; printf("%c%d", i==0 ? '(' : ',', - ((state->freq / 100000)+1)*100); + state->freq); } printf(")\n"); - k8pnow_current_state[cpu_number()] = cstate; + k8pnow_current_state = cstate; cpu_setperf = k8_powernow_setperf; } } |