Subject: Re: Re: Powernow support?
To: Juan RP <juan@xtrarom.org>
From: Joel CARNAT <joel@carnat.net>
List: port-amd64
Date: 07/31/2006 11:19:06
--WhfpMioaduB5tiZL
Content-Type: multipart/mixed; boundary="gBBFr7Ir9EOA20Yy"
Content-Disposition: inline
--gBBFr7Ir9EOA20Yy
Content-Type: text/plain; charset=iso-8859-15
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Hi,
as my AMD64 box is running /i386, I had to apply your patches to the
i386 arch. maybe I did not made it well... but the kernel does not seem
to recognize anything new :
########################################################################
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD Unknown K7 (Athlon) (686-class), 2009.87 MHz, id 0xf4a
cpu0: features 78bfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR>
cpu0: features 78bfbff<PGE,MCA,CMOV,PAT,PSE36,MPC,MMX>
cpu0: features 78bfbff<FXSR,SSE,SSE2>
cpu0: "AMD Athlon(tm) 64 Processor 3200+"
########################################################################
machdep.biosbasemem =3D 638
machdep.biosextmem =3D 1047488
machdep.nkpde =3D 98
machdep.booted_kernel =3D netbsd
machdep.diskinfo: 80:234441648(1023/255/63),2 sd0 sd1 wd0:80
machdep.fpu_present =3D 1
machdep.osfxsr =3D 1
machdep.sse =3D 1
machdep.sse2 =3D 1
machdep.cpu_brand =3D AMD Athlon(tm) 64 Processor 3200+
machdep.sleep_state =3D 0
machdep.acpi_vbios_reset =3D 1
########################################################################
I'll try to install an amd64 version on an USB external drive when I'll
be back home and let you know if it is better.
On Sun, Jul 30 2006 - 23:14, Juan RP wrote:
> On Sun, 23 Jul 2006 10:01:59 -0700
> Scott Ellis <scotte@warped.com> wrote:
>=20
> > It's been awhile since I've seen this subject broached, so I wanted to=
=20
> > check the status. Are there any pending patches to enable PowerNow=20
> > support on amd64? I see that the i386 PowerNow support is in, but=20
> > nothing in-tree for amd64. Looking at powernow-k7, it looks pretty=20
> > similar to the OpenBSD version. OpenBSD also has powernow-k8 support.
> >=20
> > Google (and a search of the list archives) didn't turn up any "work in=
=20
> > progress" on Amd64 PowerNow support, so I figured I'd ask here: Is=20
> > anyone working on this, and in need of some feedback/broader testing?
>=20
> Ok, this is just the patch I made today... based in the openbsd powernow_=
k8.c
> driver for amd64.
>=20
> Anyone wants to review the patch or try to fix the code if something is w=
rong?
>=20
> http://www.xtrarom.org/~juan/powernow_k8.patch
>=20
> A precompiled NetBSD/amd64 kernel based on GENERIC_ACPI plus
> "options POWERNOW_K8" is available at:
>=20
> http://www.xtrarom.org/~juan/netbsd_amd64_powernow.gz
>=20
> I don't have amd64 hw.... so it's untested.
--gBBFr7Ir9EOA20Yy
Content-Type: text/plain; charset=iso-8859-15
Content-Disposition: attachment; filename="powernow_k8.i386.diff"
Content-Transfer-Encoding: quoted-printable
--- sys/arch/i386/conf/files.i386.orig 2006-07-29 20:37:29.000000000 +0200
+++ sys/arch/i386/conf/files.i386 2006-07-31 00:25:53.000000000 +0200
@@ -66,4 +66,7 @@
defflag POWERNOW_K7
=20
+# AMD Powernow/Cool`n'Quiet Technology
+defflag opt_powernow_k8.h POWERNOW_K8
+
file arch/i386/i386/autoconf.c
file arch/i386/i386/db_dbgreg.S ddb | kstack_check_dr0
@@ -520,3 +523,6 @@
file arch/i386/i386/powernow_k7.c powernow_k7
=20
+# AMD PowerNow K8
+file arch/i386/i386/powernow_k8.c powernow_k8
+
include "arch/i386/conf/majors.i386"
--- sys/arch/i386/i386/mainbus.c.orig 2006-07-29 20:37:31.000000000 +0200
+++ sys/arch/i386/i386/mainbus.c 2006-07-31 00:20:27.000000000 +0200
@@ -58,4 +58,5 @@
#include "opt_acpi.h"
#include "opt_mpbios.h"
+#include "opt_powernow_k8.h"
#include "opt_pcifixup.h"
=20
@@ -355,4 +356,8 @@
#endif
=20
+#if NPOWERNOW_K8 > 0
+ k8_powernow_init();
+#endif
+
#if NAPMBIOS > 0
#if NACPI > 0
--- sys/arch/i386/i386/powernow_k8.c.orig 2006-07-31 00:21:28.000000000 +02=
00
+++ sys/arch/i386/i386/powernow_k8.c 2006-07-31 00:23:03.000000000 +0200
@@ -0,0 +1,539 @@
+/* $NetBSD$ */
+/* $OpenBSD: powernow-k8.c,v 1.8 2006/06/16 05:58:50 gwk Exp $ */
+
+/*
+ * Copyright (c) 2004 Martin V=E9giard.
+ * 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 WARRANTI=
ES
+ * 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 US=
E,
+ * 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 WARRANTI=
ES
+ * 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 US=
E,
+ * 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/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#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 <machine/isa_machdep.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/bus.h>
+
+#define SYSCTLLOG NULL
+
+#define BIOS_START 0xe0000
+#define BIOS_LEN 0x20000
+
+/*
+ * 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;
+struct k8pnow_state *freq_table;
+unsigned int cur_freq;
+int powernow_node_target, powernow_node_current;
+char *freq_names;
+size_t freq_names_len;
+
+/*
+ * Prototypes
+ */
+int powernow_sysctl_helper(SYSCTLFN_PROTO);
+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 k8_powernow_setperf(unsigned int);
+
+int powernow_sysctl_helper(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ int fq, oldfq, error;
+
+ if (freq_table =3D=3D NULL)
+ return EOPNOTSUPP;
+
+ node =3D *rnode;
+ node.sysctl_data =3D &fq;
+
+ oldfq =3D 0;
+ if (rnode->sysctl_num =3D=3D powernow_node_target)
+ fq =3D oldfq =3D cur_freq;
+ else if (rnode->sysctl_num =3D=3D powernow_node_current)
+ fq =3D cur_freq;
+ else
+ return EOPNOTSUPP;
+
+ error =3D sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp =3D=3D NULL)
+ return error;
+
+ /* support writing to ...frequency.target */
+ if (rnode->sysctl_num =3D=3D powernow_node_target && fq !=3D oldfq) {
+ if (k8_powernow_setperf(fq) =3D=3D 0)
+ cur_freq =3D fq;
+ else
+ aprint_normal("\nInvalid CPU frequency request\n");
+ }
+
+ printf("%s called!\n", __func__);
+
+ return 0;
+}
+
+int
+k8pnow_read_pending_wait(uint64_t *status)
+{
+ unsigned int i =3D 1000;
+
+ while (i--) {
+ *status =3D rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ if (!PN8_STA_PENDING(*status)) {
+ printf("%s called with 0\n", __func__);
+ return 0;
+ }
+ }
+ printf("k8pnow_read_pending_wait: change pending stuck.\n");
+ return 1;
+}
+
+int
+k8_powernow_setperf(unsigned int freq)
+{
+ unsigned int i, low, high;
+ uint64_t status;
+ int cfid, cvid, fid =3D 0, vid =3D 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 =3D rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ if (PN8_STA_PENDING(status))
+ return 1;
+ cfid =3D PN8_STA_CFID(status);
+ cvid =3D PN8_STA_CVID(status);
+
+ cstate =3D k8pnow_current_state;
+ low =3D cstate->state_table[0].freq;
+ high =3D cstate->state_table[cstate->n_states-1].freq;
+
+ for (i =3D 0; i < cstate->n_states; i++) {
+ if (cstate->state_table[i].freq =3D=3D freq) {
+ fid =3D cstate->state_table[i].fid;
+ vid =3D cstate->state_table[i].vid;
+ break;
+ }
+ }
+
+ if (fid =3D=3D cfid && vid =3D=3D cvid)
+ return 0;
+
+ /*
+ * Phase 1: Raise core voltage to requested VID if frequency is
+ * going up.
+ */
+ while (cvid > vid) {
+ val =3D cvid - (1 << cstate->mvs);
+ WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cvid =3D PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ /* ... then raise to voltage + RVO (if required) */
+ for (rvo =3D 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 =3D PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ /* Phase 2: change to requested core frequency */
+ if (cfid !=3D fid) {
+ u_int vco_fid, vco_cfid;
+
+ vco_fid =3D FID_TO_VCO_FID(fid);
+ vco_cfid =3D FID_TO_VCO_FID(cfid);
+
+ while (abs(vco_fid - vco_cfid) > 2) {
+ if (fid > cfid) {
+ if (cfid > 6)
+ val =3D cfid + 2;
+ else
+ val =3D FID_TO_VCO_FID(cfid) + 2;
+ } else
+ val =3D cfid - 2;
+ WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5);
+
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cfid =3D PN8_STA_CFID(status);
+ COUNT_OFF_IRT(cstate->irt);
+
+ vco_cfid =3D FID_TO_VCO_FID(cfid);
+ }
+
+ WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cfid =3D PN8_STA_CFID(status);
+ COUNT_OFF_IRT(cstate->irt);
+ }
+
+ /* Phase 3: change to requested voltage */
+ if (cvid !=3D vid) {
+ WRITE_FIDVID(cfid, vid, 1ULL);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cvid =3D PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ if (cfid =3D=3D fid || cvid =3D=3D vid)
+ freq =3D cstate->state_table[i].freq;
+
+ printf("%s called\n", __func__);
+ 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 =3D 0, i =3D 0; i < cstate->n_states; i++) {
+ state.fid =3D *p++;
+ state.vid =3D *p++;
+=09
+ /*
+ * The minimum supported frequency per the data sheet is 800MHz
+ * The maximum supported frequency is 5000MHz.
+ */
+ state.freq =3D 800 + state.fid * 100;
+ j =3D 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 =3D (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
+ p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p +=3D 16) {
+ if (memcmp(p, "AMDK7PNOW!", 10) =3D=3D 0) {
+ psb =3D (struct psb_s *)p;
+ if (psb->version !=3D 0x14)
+ return 0;
+
+ cstate->vst =3D psb->ttime;
+ cstate->rvo =3D PN8_PSB_TO_RVO(psb->reserved);
+ cstate->irt =3D PN8_PSB_TO_IRT(psb->reserved);
+ cstate->mvs =3D PN8_PSB_TO_MVS(psb->reserved);
+ cstate->low =3D PN8_PSB_TO_BATT(psb->reserved);
+ p+=3D sizeof(struct psb_s);
+
+ for(i =3D 0; i < psb->n_pst; ++i) {
+ pst =3D (struct pst_s *) p;
+
+ cstate->pll =3D pst->pll;
+ cstate->n_states =3D pst->n_states;
+ if (cpusig =3D=3D pst->cpuid &&
+ pst->fid =3D=3D fid && pst->vid =3D=3D vid) {
+ return (k8pnow_decode_pst(cstate,
+ p+=3D sizeof (struct pst_s)));
+ }
+ p +=3D sizeof(struct pst_s) + 2 * cstate->n_states;
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+void
+k8_powernow_init(void)
+{
+ uint64_t status;
+ u_int maxfid, maxvid, i;
+ const struct sysctlnode *node, *pnownode, *freqnode;
+ struct k8pnow_cpu_state *cstate;
+ struct k8pnow_state *state;
+ struct cpu_info *ci;
+ char *cpuname;
+ const char *techname;
+ size_t len;
+ int rc;
+
+ ci =3D curcpu();
+
+ freq_names_len =3D len =3D 0;
+ cpuname =3D ci->ci_dev->dv_xname;
+
+
+ cstate =3D malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
+ if (!cstate)
+ return;
+
+ status =3D rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ maxfid =3D PN8_STA_MFID(status);
+ maxvid =3D 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) !=3D PN8_STA_MFID(status))
+ techname =3D "PowerNow!";
+ else
+ techname =3D "Cool`n'Quiet";
+
+ freq_names_len =3D cstate->n_states *(sizeof("9999 ")-1) + 1;
+ freq_names =3D malloc(freq_names_len, M_SYSCTLDATA, M_WAITOK);
+
+ if (freq_names =3D=3D NULL)
+ panic("%s: freq_names alloc not possible", __func__);
+
+ freq_table =3D malloc(sizeof(struct k8pnow_state) *=20
+ cstate->n_states , M_TEMP, M_WAITOK);
+
+ if (freq_table =3D=3D NULL)
+ panic("%s: freq_table alloc not possible", __func__);
+
+ if (k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid)) {
+ if (cstate->n_states) {
+ for (i =3D cstate->n_states; i > 0; i--) {
+ state =3D &cstate->state_table[i-1];
+ freq_table[i].freq =3D state->freq;
+
+ len +=3D snprintf(freq_names + len,
+ freq_names_len - len, "%d%s",
+ freq_table[i].freq,
+ i < cstate->n_states - 1 ? " " : "");
+ }
+ k8pnow_current_state =3D cstate;
+ printf("%s: cstate->n_states =3D %d", __func__,
+ cstate->n_states);
+ }
+ }
+
+ /* Create sysctl machdep.powernow.frequency. */
+ if ((rc =3D sysctl_createv(SYSCTLLOG, 0, NULL, &node,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "machdep", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_EOL)) !=3D 0)
+ goto err;
+
+ if ((rc =3D sysctl_createv(SYSCTLLOG, 0, &node, &pnownode,
+ 0,
+ CTLTYPE_NODE, "powernow", NULL,
+ NULL, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL)) !=3D 0)
+ goto err;
+
+ if ((rc =3D sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
+ CTLFLAG_READWRITE,
+ CTLTYPE_INT, "target", NULL,
+ powernow_sysctl_helper, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL)) !=3D 0)
+ goto err;
+
+ powernow_node_target =3D node->sysctl_num;
+
+ if ((rc =3D sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
+ 0,
+ CTLTYPE_INT, "current", NULL,
+ powernow_sysctl_helper, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL)) !=3D 0)
+ goto err;
+
+ powernow_node_current =3D node->sysctl_num;
+
+ if ((rc =3D sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
+ 0,
+ CTLTYPE_STRING, "available", NULL,
+ NULL, 0, freq_names, freq_names_len,
+ CTL_CREATE, CTL_EOL)) !=3D 0)
+ goto err;
+
+ /* On bootup the frequency should be at its max */
+ cur_freq =3D cstate->state_table[i-1].freq;
+ k8_powernow_setperf(cur_freq);
+
+ aprint_normal("\n");
+ aprint_normal("%s: AMD %s Technology\n", cpuname, techname);
+ aprint_normal("%s: available frequencies (Mhz): %s\n", cpuname,
+ freq_names);
+ aprint_normal("%s: current frequency (Mhz): %d", cpuname, cur_freq);
+
+ return;
+
+ err:
+ if (freq_names)
+ free(freq_names, M_SYSCTLDATA);
+
+ if (freq_table)
+ free(freq_table, M_TEMP);
+}
+
--- sys/arch/i386/include/cpu.h.orig 2006-06-08 20:44:12.000000000 +0200
+++ sys/arch/i386/include/cpu.h 2006-07-31 00:27:25.000000000 +0200
@@ -428,4 +428,7 @@
void pnowk7_init(struct cpu_info *);
=20
+/* powernow_k8.c */
+void k8_powernow_init(void);
+
#endif /* _KERNEL */
=20
--gBBFr7Ir9EOA20Yy--
--WhfpMioaduB5tiZL
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (NetBSD)
iD8DBQFEzcsK0/VH7L7F7Y4RAnYiAKCEkZwn8bk6ydIMtgqyNzgCjvYSZwCfWGqL
cly+CkaZZLNhITBBVJ8mQJ0=
=ylnR
-----END PGP SIGNATURE-----
--WhfpMioaduB5tiZL--