Move PowerNow! to the cpufeaturebus.
This commit is contained in:
parent
8a56601b8f
commit
ad932f2c35
@ -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 @@ include "arch/amd64/conf/std.amd64"
|
||||
|
||||
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 USERCONF # userconf(4) support
|
||||
#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
|
||||
|
@ -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 MSGBUFSIZE=24576
|
||||
#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
|
||||
|
||||
|
@ -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 @@ include "arch/i386/conf/std.i386"
|
||||
|
||||
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 USER_LDT # user-settable LDT; used by WINE
|
||||
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
|
||||
|
@ -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 @@ include "arch/i386/conf/std.i386"
|
||||
|
||||
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 VM86 # virtual 8086 emulation
|
||||
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
|
||||
|
@ -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 @@ makeoptions CPUFLAGS="-march=i686"
|
||||
#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
|
||||
|
||||
|
@ -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 @@ defflag opt_multiboot.h MULTIBOOT
|
||||
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 defflag opt_vesabios.h VESABIOSVERBOSE
|
||||
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
|
||||
|
@ -1,492 +0,0 @@
|
||||
/* $NetBSD: powernow_k7.c,v 1.33 2009/08/23 15:58:39 ahoka Exp $ */
|
||||
/* $OpenBSD: powernow-k7.c,v 1.24 2006/06/16 05:58:50 gwk Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by 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 <nfukuda@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.
|
||||
*/
|
||||
|
||||
/* AMD POWERNOW K7 driver */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: powernow_k7.c,v 1.33 2009/08/23 15:58:39 ahoka Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/isa/isareg.h>
|
||||
|
||||
#include <x86/include/isa_machdep.h>
|
||||
#include <x86/include/powernow.h>
|
||||
|
||||
#ifdef _MODULE
|
||||
static struct sysctllog *sysctllog;
|
||||
#define SYSCTLLOG &sysctllog
|
||||
#else
|
||||
#define SYSCTLLOG NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Divide each value by 10 to get the processor multiplier.
|
||||
* Taken from powernow-k7.c/Linux by Dave Jones
|
||||
*/
|
||||
static int k7pnow_fid_to_mult[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 pnow_cpu_quirk {
|
||||
uint32_t rcpusig; /* Correct cpu signature */
|
||||
uint32_t pcpusig; /* PST cpu signature */
|
||||
} pnow_cpu_quirk[] = {
|
||||
{ 0x680, 0x780 }, /* Reported by Olaf 'Rhialto' Seibert */
|
||||
{ 0x6a0, 0x781 }, /* Reported by Eric Schnoebelen */
|
||||
{ 0x6a0, 0x7a0 }, /* Reported by Nino Dehne */
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static struct powernow_cpu_state *k7pnow_current_state;
|
||||
static unsigned int cur_freq, cpu_mhz;
|
||||
static int powernow_node_target, powernow_node_current;
|
||||
static char *freq_names;
|
||||
static size_t freq_names_len;
|
||||
static uint8_t k7pnow_flag;
|
||||
|
||||
static bool pnow_cpu_check(uint32_t, uint32_t);
|
||||
static int k7_powernow_setperf(unsigned int);
|
||||
static int k7pnow_sysctl_helper(SYSCTLFN_PROTO);
|
||||
static int k7pnow_decode_pst(struct powernow_cpu_state *, uint8_t *, int);
|
||||
static int k7pnow_states(struct powernow_cpu_state *, uint32_t,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
static bool
|
||||
pnow_cpu_check(uint32_t real_cpusig, uint32_t pst_cpusig)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (real_cpusig == pst_cpusig)
|
||||
return true;
|
||||
|
||||
for (j = 0; pnow_cpu_quirk[j].rcpusig != 0; j++) {
|
||||
if ((real_cpusig == pnow_cpu_quirk[j].rcpusig) &&
|
||||
(pst_cpusig == pnow_cpu_quirk[j].pcpusig))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
k7pnow_sysctl_helper(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
int fq, oldfq, error;
|
||||
|
||||
node = *rnode;
|
||||
node.sysctl_data = &fq;
|
||||
|
||||
oldfq = 0;
|
||||
if (rnode->sysctl_num == powernow_node_target)
|
||||
fq = oldfq = cur_freq;
|
||||
else if (rnode->sysctl_num == powernow_node_current)
|
||||
fq = cur_freq;
|
||||
else
|
||||
return EOPNOTSUPP;
|
||||
|
||||
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
if (error || newp == NULL)
|
||||
return error;
|
||||
|
||||
/* support writing to ...frequency.target */
|
||||
if (rnode->sysctl_num == powernow_node_target && fq != oldfq) {
|
||||
if (k7_powernow_setperf(fq) == 0)
|
||||
cur_freq = fq;
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
k7_powernow_setperf(unsigned int freq)
|
||||
{
|
||||
unsigned int i;
|
||||
int cvid, cfid, vid = 0, fid = 0;
|
||||
uint64_t status, ctl;
|
||||
struct powernow_cpu_state * cstate;
|
||||
|
||||
cstate = k7pnow_current_state;
|
||||
|
||||
DPRINTF(("%s: cstate->n_states=%d\n", __func__, cstate->n_states));
|
||||
for (i = 0; i < cstate->n_states; i++) {
|
||||
if (cstate->state_table[i].freq >= freq) {
|
||||
DPRINTF(("%s: freq=%d\n", __func__, freq));
|
||||
fid = cstate->state_table[i].fid;
|
||||
vid = cstate->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(cstate->sgtc);
|
||||
|
||||
if (k7pnow_flag & PN7_FLAG_ERRATA_A0)
|
||||
x86_disable_intr();
|
||||
|
||||
if (k7pnow_fid_to_mult[fid] < k7pnow_fid_to_mult[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 (k7pnow_flag & PN7_FLAG_ERRATA_A0)
|
||||
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 = 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.
|
||||
*/
|
||||
static int
|
||||
k7pnow_decode_pst(struct powernow_cpu_state *cstate, uint8_t *p, int npst)
|
||||
{
|
||||
int i, j, n;
|
||||
struct powernow_state state;
|
||||
|
||||
for (n = 0, i = 0; i < npst; ++i) {
|
||||
state.fid = *p++;
|
||||
state.vid = *p++;
|
||||
state.freq = k7pnow_fid_to_mult[state.fid]/10 * cstate->fsb;
|
||||
if ((k7pnow_flag & PN7_FLAG_ERRATA_A0) &&
|
||||
(k7pnow_fid_to_mult[state.fid] % 10) == 5)
|
||||
continue;
|
||||
|
||||
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 powernow_state));
|
||||
--j;
|
||||
}
|
||||
memcpy(&cstate->state_table[j], &state,
|
||||
sizeof(struct powernow_state));
|
||||
++n;
|
||||
}
|
||||
/*
|
||||
* Fix powernow_max_states, if errata_a0 give us less states
|
||||
* than expected.
|
||||
*/
|
||||
cstate->n_states = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
k7pnow_states(struct powernow_cpu_state *cstate, uint32_t cpusig,
|
||||
unsigned int fid, unsigned int vid)
|
||||
{
|
||||
int j, maxpst;
|
||||
struct powernow_psb_s *psb;
|
||||
struct powernow_pst_s *pst;
|
||||
uint8_t *p;
|
||||
bool cpusig_ok;
|
||||
|
||||
j = 0;
|
||||
/*
|
||||
* 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)
|
||||
k7pnow_flag |= 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->signature:0x%x\n",
|
||||
__func__, cpusig, pst->signature));
|
||||
|
||||
cpusig_ok = pnow_cpu_check(cpusig,
|
||||
pst->signature);
|
||||
|
||||
if ((cpusig_ok &&
|
||||
(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 (k7pnow_decode_pst(cstate,
|
||||
p + sizeof(struct powernow_pst_s),
|
||||
cstate->n_states));
|
||||
}
|
||||
p += sizeof(struct powernow_pst_s) +
|
||||
(2 * pst->n_states);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
k7_powernow_init(void)
|
||||
{
|
||||
uint64_t status;
|
||||
uint32_t maxfid, startvid, currentfid;
|
||||
const struct sysctlnode *freqnode, *node, *pnownode;
|
||||
struct powernow_cpu_state *cstate;
|
||||
struct cpu_info *ci;
|
||||
const char *cpuname;
|
||||
const char *techname;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
ci = curcpu();
|
||||
|
||||
freq_names_len = 0;
|
||||
cpuname = device_xname(ci->ci_dev);
|
||||
|
||||
k7pnow_current_state = NULL;
|
||||
|
||||
cstate = malloc(sizeof(struct powernow_cpu_state), M_DEVBUF, M_NOWAIT);
|
||||
if (!cstate) {
|
||||
DPRINTF(("%s: cstate failed to malloc!\n", __func__));
|
||||
return;
|
||||
}
|
||||
|
||||
k7pnow_flag = 0;
|
||||
if (ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
|
||||
k7pnow_flag |= 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);
|
||||
|
||||
cpu_mhz = ci->ci_data.cpu_cc_freq / 1000000;
|
||||
cstate->fsb = cpu_mhz / (k7pnow_fid_to_mult[currentfid]/10);
|
||||
if (k7pnow_states(cstate, ci->ci_signature, maxfid, startvid)) {
|
||||
freq_names_len = cstate->n_states * (sizeof("9999 ")-1) + 1;
|
||||
freq_names = malloc(freq_names_len, M_SYSCTLDATA, M_WAITOK);
|
||||
freq_names[0] = '\0';
|
||||
len = 0;
|
||||
|
||||
if (cstate->n_states) {
|
||||
for (i = 0; i < cstate->n_states; i++) {
|
||||
/* skip duplicated matches... */
|
||||
if (cstate->state_table[i].freq ==
|
||||
cstate->state_table[i-1].freq)
|
||||
continue;
|
||||
|
||||
DPRINTF(("%s: cstate->state_table.freq=%d\n",
|
||||
__func__, cstate->state_table[i].freq));
|
||||
DPRINTF(("%s: fid=%d vid=%d\n", __func__,
|
||||
cstate->state_table[i].fid,
|
||||
cstate->state_table[i].vid));
|
||||
char tmp[6];
|
||||
len += snprintf(tmp, sizeof(tmp), "%d%s",
|
||||
cstate->state_table[i].freq,
|
||||
i < cstate->n_states - 1 ? " " : "");
|
||||
DPRINTF(("%s: tmp=%s\n", __func__, tmp));
|
||||
(void)strlcat(freq_names, tmp, freq_names_len);
|
||||
}
|
||||
k7pnow_current_state = cstate;
|
||||
DPRINTF(("%s: freq_names=%s\n", __func__, freq_names));
|
||||
}
|
||||
}
|
||||
|
||||
if (k7pnow_current_state == NULL) {
|
||||
if (freq_names)
|
||||
free(freq_names, M_SYSCTLDATA);
|
||||
free(cstate, M_DEVBUF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (k7pnow_flag & PN7_FLAG_DESKTOP_VRM)
|
||||
techname = "Cool`n'Quiet K7";
|
||||
else
|
||||
techname = "Powernow! K7";
|
||||
|
||||
/* Create sysctl machdep.powernow.frequency. */
|
||||
if (sysctl_createv(SYSCTLLOG, 0, NULL, &node,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "machdep", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_MACHDEP, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &node, &pnownode,
|
||||
0,
|
||||
CTLTYPE_NODE, "powernow", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &pnownode, &freqnode,
|
||||
0,
|
||||
CTLTYPE_NODE, "frequency", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "target", NULL,
|
||||
k7pnow_sysctl_helper, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
powernow_node_target = node->sysctl_num;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
0,
|
||||
CTLTYPE_INT, "current", NULL,
|
||||
k7pnow_sysctl_helper, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
powernow_node_current = node->sysctl_num;
|
||||
|
||||
if ((sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
0,
|
||||
CTLTYPE_STRING, "available", NULL,
|
||||
NULL, 0, freq_names, freq_names_len,
|
||||
CTL_CREATE, CTL_EOL)) != 0)
|
||||
goto err;
|
||||
|
||||
cur_freq = cstate->state_table[cstate->n_states-1].freq;
|
||||
|
||||
aprint_normal("%s: AMD %s Technology %d MHz\n",
|
||||
cpuname, techname, cur_freq);
|
||||
aprint_normal("%s: frequencies available (MHz): %s\n",
|
||||
cpuname, freq_names);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
free(freq_names, M_SYSCTLDATA);
|
||||
free(cstate, M_DEVBUF);
|
||||
}
|
||||
|
||||
void
|
||||
k7_powernow_destroy(void)
|
||||
{
|
||||
#ifdef _MODULE
|
||||
sysctl_teardown(SYSCTLLOG);
|
||||
|
||||
if (freq_names)
|
||||
free(freq_names, M_SYSCTLDATA);
|
||||
if (k7pnow_current_state)
|
||||
free(k7pnow_current_state, M_DEVBUF);
|
||||
#endif
|
||||
}
|
@ -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 @@ defflag opt_pcifixup.h PCI_ADDR_FIXUP PCI_BUS_FIXUP
|
||||
# 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 @@ device cpu: cpufeaturebus
|
||||
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/acpi/acpi_cpu_md.c acpi & acpicpu
|
||||
|
||||
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
|
||||
|
||||
|
@ -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_state {
|
||||
};
|
||||
|
||||
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 @@ struct powernow_pst_s {
|
||||
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 */
|
||||
|
@ -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 @@ cpu_rescan(device_t self, const char *ifattr, const int *locators)
|
||||
"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,
|
||||
|
@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.25 2011/02/23 11:43:23 jruoho Exp $")
|
||||
#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 @@ cpu_identify(struct cpu_info *ci)
|
||||
}
|
||||
#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();
|
||||
|
1000
sys/arch/x86/x86/powernow.c
Normal file
1000
sys/arch/x86/x86/powernow.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
||||
/* $NetBSD: powernow_common.c,v 1.11 2008/05/21 01:13:07 ad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 The NetBSD Foundation.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: powernow_common.c,v 1.11 2008/05/21 01:13:07 ad Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/device.h>
|
||||
|
||||
#include <x86/powernow.h>
|
||||
#include <x86/cpufunc.h>
|
||||
|
||||
int
|
||||
powernow_probe(struct cpu_info *ci)
|
||||
{
|
||||
uint32_t regs[4];
|
||||
|
||||
x86_cpuid(0x80000000, regs);
|
||||
|
||||
/* We need CPUID(0x80000007) */
|
||||
if (regs[0] < 0x80000007)
|
||||
return 0;
|
||||
x86_cpuid(0x80000007, regs);
|
||||
|
||||
/*
|
||||
* For now we're only interested in FID and VID for frequency scaling.
|
||||
*/
|
||||
|
||||
return (regs[3] & AMD_PN_FID_VID) == AMD_PN_FID_VID;
|
||||
}
|
@ -1,502 +0,0 @@
|
||||
/* $NetBSD: powernow_k8.c,v 1.28 2010/08/20 06:34:32 jruoho Exp $ */
|
||||
/* $OpenBSD: powernow-k8.c,v 1.8 2006/06/16 05:58:50 gwk Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004, 2006 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 <nfukuda@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.
|
||||
*/
|
||||
|
||||
/* AMD POWERNOW K8 driver */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: powernow_k8.c,v 1.28 2010/08/20 06:34:32 jruoho Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/once.h>
|
||||
#include <sys/xcall.h>
|
||||
|
||||
#include <x86/cpu_msr.h>
|
||||
#include <x86/powernow.h>
|
||||
|
||||
#include <dev/isa/isareg.h>
|
||||
|
||||
#include <machine/isa_machdep.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#ifdef _MODULE
|
||||
static struct sysctllog *sysctllog;
|
||||
#define SYSCTLLOG &sysctllog
|
||||
#else
|
||||
#define SYSCTLLOG NULL
|
||||
#endif
|
||||
|
||||
static struct powernow_cpu_state *k8pnow_current_state;
|
||||
static unsigned int cur_freq;
|
||||
static int powernow_node_target, powernow_node_current;
|
||||
static char *freq_names;
|
||||
static size_t freq_names_len;
|
||||
|
||||
static int k8pnow_sysctl_helper(SYSCTLFN_PROTO);
|
||||
static int k8pnow_decode_pst(struct powernow_cpu_state *, uint8_t *);
|
||||
static int k8pnow_states(struct powernow_cpu_state *, uint32_t, unsigned int,
|
||||
unsigned int);
|
||||
static int k8_powernow_setperf(unsigned int);
|
||||
static int k8_powernow_init_once(void);
|
||||
static void k8_powernow_init_main(void);
|
||||
|
||||
static uint64_t
|
||||
k8pnow_wr_fidvid(u_int fid, uint64_t vid, uint64_t ctrl)
|
||||
{
|
||||
struct msr_rw_info msr;
|
||||
uint64_t where, status;
|
||||
|
||||
msr.msr_read = false;
|
||||
msr.msr_value = (ctrl << 32) | (1ULL << 16) | (vid << 8) | fid;
|
||||
msr.msr_type = MSR_AMDK7_FIDVID_CTL;
|
||||
|
||||
where = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
|
||||
xc_wait(where);
|
||||
|
||||
do {
|
||||
status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
|
||||
} while (PN8_STA_PENDING(status));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
k8pnow_sysctl_helper(SYSCTLFN_ARGS)
|
||||
{
|
||||
struct sysctlnode node;
|
||||
int fq, oldfq, error;
|
||||
|
||||
node = *rnode;
|
||||
node.sysctl_data = &fq;
|
||||
|
||||
oldfq = 0;
|
||||
if (rnode->sysctl_num == powernow_node_target)
|
||||
fq = oldfq = cur_freq;
|
||||
else if (rnode->sysctl_num == powernow_node_current)
|
||||
fq = cur_freq;
|
||||
else
|
||||
return EOPNOTSUPP;
|
||||
|
||||
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
if (error || newp == NULL)
|
||||
return error;
|
||||
|
||||
/* support writing to ...frequency.target */
|
||||
if (rnode->sysctl_num == powernow_node_target && fq != oldfq) {
|
||||
if (k8_powernow_setperf(fq) == 0)
|
||||
cur_freq = fq;
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
k8_powernow_setperf(unsigned int freq)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t status;
|
||||
uint32_t val;
|
||||
int cfid, cvid, fid = 0, vid = 0;
|
||||
int rvo;
|
||||
struct powernow_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;
|
||||
|
||||
DPRINTF(("%s: cstate->n_states=%d\n", __func__, cstate->n_states));
|
||||
for (i = 0; i < cstate->n_states; i++) {
|
||||
if (cstate->state_table[i].freq >= freq) {
|
||||
DPRINTF(("%s: freq=%d\n", __func__, freq));
|
||||
fid = cstate->state_table[i].fid;
|
||||
vid = cstate->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 core voltage to requested VID if frequency is
|
||||
* going up.
|
||||
*/
|
||||
while (cvid > vid) {
|
||||
val = cvid - (1 << cstate->mvs);
|
||||
status = k8pnow_wr_fidvid(cfid, (val > 0) ? val : 0, 1ULL);
|
||||
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 */
|
||||
status = k8pnow_wr_fidvid(cfid, cvid - 1, 1ULL);
|
||||
cvid = PN8_STA_CVID(status);
|
||||
COUNT_OFF_VST(cstate->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 = k8pnow_wr_fidvid(val, cvid,
|
||||
(uint64_t)cstate->pll * 1000 / 5);
|
||||
cfid = PN8_STA_CFID(status);
|
||||
COUNT_OFF_IRT(cstate->irt);
|
||||
|
||||
vco_cfid = FID_TO_VCO_FID(cfid);
|
||||
}
|
||||
|
||||
status = k8pnow_wr_fidvid(fid, cvid,
|
||||
(uint64_t)cstate->pll * 1000 / 5);
|
||||
cfid = PN8_STA_CFID(status);
|
||||
COUNT_OFF_IRT(cstate->irt);
|
||||
}
|
||||
|
||||
/* Phase 3: change to requested voltage */
|
||||
if (cvid != vid) {
|
||||
status = k8pnow_wr_fidvid(cfid, vid, 1ULL);
|
||||
cvid = PN8_STA_CVID(status);
|
||||
COUNT_OFF_VST(cstate->vst);
|
||||
}
|
||||
|
||||
if (cfid == fid || cvid == vid)
|
||||
freq = 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.
|
||||
*/
|
||||
static int
|
||||
k8pnow_decode_pst(struct powernow_cpu_state *cstate, uint8_t *p)
|
||||
{
|
||||
int i, j, n;
|
||||
struct powernow_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 powernow_state));
|
||||
--j;
|
||||
}
|
||||
memcpy(&cstate->state_table[j], &state,
|
||||
sizeof(struct powernow_state));
|
||||
n++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
k8pnow_states(struct powernow_cpu_state *cstate, uint32_t cpusig,
|
||||
unsigned int fid, unsigned int vid)
|
||||
{
|
||||
struct powernow_psb_s *psb;
|
||||
struct powernow_pst_s *pst;
|
||||
uint8_t *p;
|
||||
int i;
|
||||
|
||||
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 = signature\n",
|
||||
__func__));
|
||||
return (k8pnow_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
|
||||
k8_powernow_init_once(void)
|
||||
{
|
||||
k8_powernow_init_main();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
k8_powernow_init(void)
|
||||
{
|
||||
int error;
|
||||
static ONCE_DECL(powernow_initialized);
|
||||
|
||||
error = RUN_ONCE(&powernow_initialized, k8_powernow_init_once);
|
||||
if (__predict_false(error != 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
k8_powernow_init_main(void)
|
||||
{
|
||||
uint64_t status;
|
||||
uint32_t maxfid, maxvid, i;
|
||||
const struct sysctlnode *freqnode, *node, *pnownode;
|
||||
struct powernow_cpu_state *cstate;
|
||||
const char *cpuname, *techname;
|
||||
size_t len;
|
||||
|
||||
freq_names_len = 0;
|
||||
cpuname = device_xname(curcpu()->ci_dev);
|
||||
|
||||
k8pnow_current_state = NULL;
|
||||
|
||||
cstate = malloc(sizeof(struct powernow_cpu_state), M_DEVBUF, M_NOWAIT);
|
||||
if (!cstate) {
|
||||
DPRINTF(("%s: cstate failed to malloc!\n", __func__));
|
||||
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!";
|
||||
else
|
||||
techname = "Cool`n'Quiet";
|
||||
|
||||
if (k8pnow_states(cstate, curcpu()->ci_signature, maxfid, maxvid)) {
|
||||
freq_names_len = cstate->n_states * (sizeof("9999 ")-1) + 1;
|
||||
freq_names = malloc(freq_names_len, M_SYSCTLDATA, M_WAITOK);
|
||||
freq_names[0] = '\0';
|
||||
len = 0;
|
||||
|
||||
if (cstate->n_states) {
|
||||
for (i = 0; i < cstate->n_states; i++) {
|
||||
DPRINTF(("%s: cstate->state_table.freq=%d\n",
|
||||
__func__, cstate->state_table[i].freq));
|
||||
DPRINTF(("%s: fid=%d vid=%d\n", __func__,
|
||||
cstate->state_table[i].fid,
|
||||
cstate->state_table[i].vid));
|
||||
char tmp[6];
|
||||
len += snprintf(tmp, sizeof(tmp), "%d%s",
|
||||
cstate->state_table[i].freq,
|
||||
i < cstate->n_states - 1 ? " " : "");
|
||||
DPRINTF(("%s: tmp=%s\n", __func__, tmp));
|
||||
(void)strlcat(freq_names, tmp, freq_names_len);
|
||||
}
|
||||
k8pnow_current_state = cstate;
|
||||
DPRINTF(("%s: freq_names=%s\n", __func__, freq_names));
|
||||
}
|
||||
} else {
|
||||
DPRINTF(("%s: returned 0!\n", __func__));
|
||||
}
|
||||
|
||||
if (k8pnow_current_state == NULL) {
|
||||
DPRINTF(("%s: k8pnow_current_state is NULL!\n", __func__));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Create sysctl machdep.powernow.frequency. */
|
||||
if (sysctl_createv(SYSCTLLOG, 0, NULL, &node,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_NODE, "machdep", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_MACHDEP, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &node, &pnownode,
|
||||
0,
|
||||
CTLTYPE_NODE, "powernow", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &pnownode, &freqnode,
|
||||
0,
|
||||
CTLTYPE_NODE, "frequency", NULL,
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "target", NULL,
|
||||
k8pnow_sysctl_helper, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
powernow_node_target = node->sysctl_num;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
0,
|
||||
CTLTYPE_INT, "current", NULL,
|
||||
k8pnow_sysctl_helper, 0, NULL, 0,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
powernow_node_current = node->sysctl_num;
|
||||
|
||||
if (sysctl_createv(SYSCTLLOG, 0, &freqnode, &node,
|
||||
0,
|
||||
CTLTYPE_STRING, "available", NULL,
|
||||
NULL, 0, freq_names, freq_names_len,
|
||||
CTL_CREATE, CTL_EOL) != 0)
|
||||
goto err;
|
||||
|
||||
cur_freq = cstate->state_table[cstate->n_states-1].freq;
|
||||
|
||||
aprint_normal("%s: AMD %s Technology %d MHz\n",
|
||||
cpuname, techname, cur_freq);
|
||||
aprint_normal("%s: available frequencies (MHz): %s\n",
|
||||
cpuname, freq_names);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
if (cstate)
|
||||
free(cstate, M_DEVBUF);
|
||||
if (freq_names)
|
||||
free(freq_names, M_SYSCTLDATA);
|
||||
}
|
||||
|
||||
void
|
||||
k8_powernow_destroy(void)
|
||||
{
|
||||
#ifdef _MODULE
|
||||
sysctl_teardown(SYSCTLLOG);
|
||||
|
||||
if (k8pnow_current_state)
|
||||
free(k8pnow_current_state, M_DEVBUF);
|
||||
if (freq_names)
|
||||
free(freq_names, M_SYSCTLDATA);
|
||||
#endif
|
||||
}
|
@ -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 @@ defflag opt_pcifixup.h PCI_ADDR_FIXUP PCI_BUS_FIXUP
|
||||
|
||||
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/des/arch/i386/des_cbc.S des
|
||||
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 @@ attach est at cpufeaturebus
|
||||
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
|
||||
#
|
||||
|
@ -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 @@ cpu_rescan(device_t self, const char *ifattr, const int *locators)
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user