From owner-FreeBSD-users-jp@jp.FreeBSD.org Mon Nov  3 07:53:58 2008
Received: (from daemon@localhost)
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) id mA2Mrw305947;
	Mon, 3 Nov 2008 07:53:58 +0900 (JST)
	(envelope-from owner-FreeBSD-users-jp@jp.FreeBSD.org)
Received: from po-out-1718.google.com (po-out-1718.google.com [72.14.252.154])
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) with ESMTP/inet id mA2MrvJ05942
	for <FreeBSD-users-jp@jp.freebsd.org>; Mon, 3 Nov 2008 07:53:57 +0900 (JST)
	(envelope-from annona2@gmail.com)
Received: by po-out-1718.google.com with SMTP id b23so9932796poe.0
        for <FreeBSD-users-jp@jp.freebsd.org>; Sun, 02 Nov 2008 14:53:56 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:received:message-id:date:from
         :to:subject:user-agent:mime-version:content-type;
        bh=g7xHDBUT5GPqe0sYlJBwxbxw2mqZMsEqJQ/Dm6G2kgE=;
        b=bRx0aabc2L+HUc8gZUXMRuuWqVjkO7bGFu8UvX0fm6DivI57GpgyTtf3SZx6rIFVVZ
         yEemNWqU9UtsgxFc67CHAeTyST1PCLosQfsO1KkwdiMm/jl+mlfbwXf6M58IEEpZ/tRB
         NorGUwhopbJjZLcB3SgkPgPyIO/WtPA3CVJYo=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=message-id:date:from:to:subject:user-agent:mime-version
         :content-type;
        b=qnq7/ASndLnHs2ZMe+Aq1YQYP90AqtIBWUX9Ya4NY5xJNI09s+U4gukVpQKk1uhQYE
         dypXQPUfJuylDhgbmtDytpdXdBMO39InRUMD2xZLm+M9IKs/bUBHaeQFXa51//cpZ+B1
         lmBUxjUKk7wR0aCcuB7ZiZSr9Kx617mod2kgs=
Received: by 10.110.52.1 with SMTP id z1mr10673708tiz.55.1225666434819;
        Sun, 02 Nov 2008 14:53:54 -0800 (PST)
Received: from softbank219001162114.bbtec.net (softbank219001162114.bbtec.net [219.1.162.114])
        by mx.google.com with ESMTPS id u8sm14536044tia.8.2008.11.02.14.53.51
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 02 Nov 2008 14:53:54 -0800 (PST)
Received: from softbank219001162114.bbtec.net (localhost [127.0.0.1])
	by localhost (8.14.3/8.14.3) with ESMTP id mA2MpLwh001847
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Mon, 3 Nov 2008 07:51:21 +0900 (JST)
	(envelope-from annona2@gmail.com)
Message-Id: <200811022251.mA2MpLwh001847@localhost>
From: annona2@gmail.com
To: FreeBSD-users-jp@jp.FreeBSD.org
User-Agent: Wanderlust/2.15.5 (Almost Unreal) SEMI/1.14.6 (Maruoka)
 FLIM/1.14.8 (=?ISO-8859-4?Q?Shij=F2?=) APEL/10.7 Emacs/22.2
 (i386-portbld-freebsd7.1) MULE/5.0 (SAKAKI)
MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka")
Content-Type: text/plain; charset=ISO-2022-JP
Reply-To: FreeBSD-users-jp@jp.FreeBSD.org
Precedence: list
Date: Mon, 03 Nov 2008 07:51:21 +0900
X-Sequence: FreeBSD-users-jp 91885
Subject: [FreeBSD-users-jp 91885] Phenom =?ISO-2022-JP?B?GyRCJEobKEI=?=
 =?ISO-2022-JP?B?GyRCJEkkThsoQg==?= cpufreq
Sender: owner-FreeBSD-users-jp@jp.FreeBSD.org
X-Originator: annona2@gmail.com
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+060209


$B$O$8$a$^$7$F$G$O$J$$$N$G$9$,!"(B
$B$O$8$a$^$7$F!#HxDT$H?=$7$^$9!#(B

Phenom/opteron{1,2,8}3XX$B$J(Bcpufreq$B$r:n$C$F$_$^$7$?!#(B
$B$^$@&B%P!<%8%g%s$G$9$,!#(B

$B$3$s$J46$8$G$9!#(B
$B%^%6!<%\!<%I$O(BBIOSTAR TF8200A2+$B$G$9!#(B
# dmesg$B$N(Bcpu$B$NItJ,(B
CPU: AMD Phenom(tm) 9850 Quad-Core Processor (2500.01-MHz 686-class CPU)
# uname -a$B$NH4$-$@$7(B
FreeBSD 7.1-PRERELEASE #0 Thu Oct  2 21:20:49 JST 2008 gen@:/tmp/sys/TF8200S i386
# kldload cpufreq
hwpstate0: <Cool`n'Quiet 2.0> on cpu0
hwpstate0: SVI mode
hwpstate0: you have 2 P-state.
hwpstate0: freq=2500MHz volts=1300mV
hwpstate0: freq=1250MHz volts=1050mV
hwpstate0: Now P0-state.
hwpstate1: <Cool`n'Quiet 2.0> on cpu1
hwpstate1: SVI mode
hwpstate1: you have 2 P-state.
hwpstate1: freq=2500MHz volts=1300mV
hwpstate1: freq=1250MHz volts=1050mV
hwpstate1: Now P0-state.
hwpstate2: <Cool`n'Quiet 2.0> on cpu2
hwpstate2: SVI mode
hwpstate2: you have 2 P-state.
hwpstate2: freq=2500MHz volts=1300mV
hwpstate2: freq=1250MHz volts=1050mV
hwpstate2: Now P0-state.
hwpstate3: <Cool`n'Quiet 2.0> on cpu3
hwpstate3: SVI mode
hwpstate3: you have 2 P-state.
hwpstate3: freq=2500MHz volts=1300mV
hwpstate3: freq=1250MHz volts=1050mV
hwpstate3: Now P0-state.
# sysctl dev.cpu.0.freq_levels 
dev.cpu.0.freq_levels: 2500/-1 1250/-1
# sysctl dev.cpu.0.freq
dev.cpu.0.freq: 2500
# sysctl dev.cpu.0.freq=1250
dev.cpu.0.freq: 2500 -> 1250
# dmesg
hwpstate0: goto P1-state
hwpstate0: Now P1-state.
hwpstate1: goto P1-state
hwpstate1: Now P1-state.
hwpstate2: goto P1-state
hwpstate2: Now P1-state.
hwpstate3: goto P1-state
hwpstate3: Now P1-state.
# kldunload cpufreq
hwpstate0: Now P0-state.
hwpstate0: detached
hwpstate1: Now P0-state.
hwpstate1: detached
hwpstate2: Now P0-state.
hwpstate2: detached
hwpstate3: Now P0-state.
hwpstate3: detached
# sysctl dev.cpu.0.freq
dev.cpu.0.freq: 1250
(???$B$^$@&B%P!<%8%g%s$G$9!#(B)
# kldload cpufreq
$B$G85$KLa$j$^$9!#(B

current mailing list$B$KEj9F$7$F$b(B
$B$J$s$H$$$&$+!";d$N1Q8l$,$R$I$$$N$+$=$l$H$b!"(B
$B0JA0$N(Bpstate.c$B$,$R$I$+$C$?$N$+!"$=$l$H$b$+$J$j4V$,$"$$$?$+$i$J$N$+(B
$B$H$$$&$+$s$8$J$b$N$G$9$+$i!"$3$A$i$K$bEj9F$5$;$F$$$?$@$-$^$9!#(B
$B0JA0$K(Bcurrent$B%a!<%j%s%0%j%9%H$KEj9F$7$?$i(Bkldunload$B$G$-$J$$(B
$B$H$+%U%j!<%:$9$k$H$+$G$7$?$,!#(B
$B%Y%m%K%+$5$s$N=j$G$O$&$^$/$$$C$?$N$G$9$,!"(Bcghosts$B$5$s$N=j$G$O(B
$B$&$^$/$$$+$J$$$_$?$$$G$7$?!#(BPHK$B$5$s$N=j$G$O$I$&$J$N$+$o$+$j$^$;$s!#(B
$B:#2s$N(Bcpufreq$B$O%"%/%m%P%A%C%/$J=j$,$J$$$N$GBg>fIW$@$H;W$$$^$9!#(B
$B0JA0$N(Bpstate.c$B$O(BBIOS$B$,$d$k$Y$-$H$3$m$r(Bwrmsr$B$r$D$+$C$F(B
$B6/0z$K$d$C$F$^$7$?!#$G$9$,(Bwindows$B$G$$$&=j$N(B
crystal cpuid$B$N$h$&$J$b$N$@$+$i$$$$$+$J$H$O;W$C$F$$$?$N$G$9$,(B
$B9M$($F$_$k$H(B400MHz$B$^$G2<$2$i$l$?$N$G$9$,CY$9$.$G$9!#(B
$B$=$3$G(B#debug.cpufreq.lowest=1200$B$H$$$&$N$r(B/boot/loader.conf$B$K(B
$B$$$l$F$$$?$N$G$9$,!"(BBIOS$B$,:n@.$7$?(Bhardware pstate$B$O(B
$B;d$N=j$G$O(B1250MHz$B$H(B2500MHz$B$G$9!#$3$l$G==J,$@$H;W$$D>$7(B
$BBE6($7$^$7$?!#(B

$B$=$$$&$o$1$G(BBIOS$B$,:n@.$7$?(B Hardware P-state $B$H$$$&(BP-state$B$r;H$C$F(B
$B$=$l$rA+0\$5$;$k$@$1$N%b%8%e!<%k$G$9!#(B
$B%=!<%9$rFI$a$P(B300$B9T$/$i$$$G<jB3$-E*$J$H$3$m$r=|$/$H(B
$BH>J,$/$i$$$G$9!#(B

$B;n$7$F$_$F$/$@$5$$!#:#EY$N$O(Bkldunload $B$G$-$^$9!#(B
$B$^$@&B%P!<%8%g%s$J$N$G(Bdebug message $B$,$G$^$9$,!"(B
$B%=!<%9Cf$N(Bhwpstate_verbose=0$B$H$9$l$P$G$J$/$J$j$^$9!#(B
$B$^$?%3%a%s%H$b$"$j$^$9!#(B

current$B$N(Bamd64$B$G$b$?$a$7$F$$$k$N$G(Bamd64$B$G$bBg>fIW$@$H;W$$$^$9!#(B
$B$J$K$V$s$O$8$a$F$N%+!<%M%k%b%8%e!<%k$J$N$G$$$?$i$J$$$H$3$m(B
$B$3$&$7$?$[$&$,$$$$$H$3$m$J$I;XE&$7$F$/$@$5$k$H(B
$B$&$l$7$$$G$9!#(B
$B$h$m$7$/$*4j$$$7$^$9!#(B
#$B?MCl$r$*4j$$$7$F$$$k$h$&$G$b$7$o$1$"$j$^$;$s$,!"(B
#$B<+J,$N4D6-$G$O$9$/$J$/$H$bBg>fIW$G$9!#(B

$BHxDT(B <anonna2@gmail.com $B$"$N2F(B!>

P.S. $B0J2<%=!<%9$G$9!#(Bfile$BL>$O(Bhwpstate.c$B$J$N$G$9$,!#(B
/sys/module/cpufreq/Makefile$B$N(BSRCS=$B$K(Bhwpstate.c$B$rDI2C$7$F!"(B
/sys/i386/cpufre/$B$K0J2<$N%U%!%$%k(Bhwpstate.c$B$G$*$$$F$/$@$5$$!#(B
kerenel$B$K$O(Bcpufreq$B$,I8=`$G$D$$$F$$$k$N$G(B
$B$=$l$r=|$$$?%+!<%M%k$r$D$/$i$J$$$H;n$;$J$$$H;W$$$^$9!#(B
/sys/module/cpuferq$B$G(Bmake && make install$B$9$k$H;H$($k$h$&$K$J$j$^$9!#(B
=====================================================
/**
 * Reference:
 *  Rev 3.06  March 26, 2008 - BIOS and Kernel Developer's Guide(BKDG)
 *  for AMD Family 10h Processors
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <dev/pci/pcivar.h>
#include <machine/md_var.h>

#include <contrib/dev/acpica/acpi.h>
#include <dev/acpica/acpivar.h>

#include "acpi_if.h"
#include "cpufreq_if.h"

#define MSR_AMD10H_LIMIT    0xc0010061
#define MSR_AMD10H_CONTROL  0xc0010062
#define MSR_AMD10H_STATUS   0xc0010063
#define MSR_AMD10H_CONFIG   0xc0010064
#define AMD10H_PVI_MODE     1
#define AMD10H_SVI_MODE     0
#define AMD10H_MAX_STATES   16

/* for MSR_AMD10H_LIMIT C001_0061 */
#define AMD10H_GET_PSTATE_MAX_VAL(msr)      (((msr) >> 4) & 0xF)
/* for MSR_AMD10H_CONFIG C001_0064:68 */
#define MSR_AMD10H_CUR_VID(msr)             (((msr) >> 9) & 0x3F)
#define MSR_AMD10H_CUR_DID(msr)             (((msr) >> 6) & 0x07)
#define MSR_AMD10H_CUR_FID(msr)             ((msr) & 0x3F)

/**
 * setting this to 0 can hush up verbose messages.
 */
static int hwpstate_verbose = 1;

struct hwpstate_setting {
	int freq;		/* CPU clock in Mhz or 100ths of a percent. */
	int volts;		/* Voltage in mV. */
	int power;		/* Power consumed in mW. */
	int lat;		/* Transition latency in us. */
	int pstate_id;
	device_t dev;		/* Driver providing this setting. */
};

struct hwpstate_softc {
	device_t dev;
	struct hwpstate_setting hwpstate_settings[AMD10H_MAX_STATES];
	int cfnum;
	int voltage_mode;	/* for AMD10H_PVI_MODE / AMD10H_SVI_MODE */
	int curpstate;
};

static void hwpstate_identify(driver_t * driver, device_t parent);
static int hwpstate_probe(device_t dev);
static int hwpstate_attach(device_t dev);
static int hwpstate_detach(device_t dev);
static int hwpstate_set(device_t dev, const struct cf_setting *cf);
static int hwpstate_get(device_t dev, struct cf_setting *cf);
static int hwpstate_settings(device_t dev, struct cf_setting *sets, int *count);
static int hwpstate_type(device_t dev, int *type);
static int hwpstate_shutdown(device_t dev);
static int hwpstate_features(driver_t * driver, u_int * features);

static device_method_t hwpstate_methods[] = {
	/* Device interface */
	DEVMETHOD(device_identify, hwpstate_identify),
	DEVMETHOD(device_probe, hwpstate_probe),
	DEVMETHOD(device_attach, hwpstate_attach),
	DEVMETHOD(device_detach, hwpstate_detach),
	DEVMETHOD(device_shutdown, hwpstate_shutdown),

	/* cpufreq interface */
	DEVMETHOD(cpufreq_drv_set, hwpstate_set),
	DEVMETHOD(cpufreq_drv_get, hwpstate_get),
	DEVMETHOD(cpufreq_drv_settings, hwpstate_settings),
	DEVMETHOD(cpufreq_drv_type, hwpstate_type),

	/* ACPI interface */
	DEVMETHOD(acpi_get_features, hwpstate_features),

	{0, 0}
};

static devclass_t hwpstate_devclass;
static driver_t hwpstate_driver = {
	"hwpstate",
	hwpstate_methods,
	sizeof(struct hwpstate_softc),
};
DRIVER_MODULE(hwpstate, cpu, hwpstate_driver, hwpstate_devclass, 0, 0);

static void
hwpstate_goto_pstate(device_t dev,int pstate)
{
	struct hwpstate_softc *sc;
	uint64_t msr;
	int i;
	sc = device_get_softc(dev);
	sc->curpstate = pstate;
	wrmsr(MSR_AMD10H_CONTROL, pstate);
	for(i=0;i<1000;i++){
		msr=rdmsr(MSR_AMD10H_STATUS);
		if(msr==pstate){
			break;
		}
		DELAY(100);
	}
	msr=rdmsr(MSR_AMD10H_STATUS);
	if(hwpstate_verbose)
		device_printf(dev,"Now P%d-state.\n",(int)msr);
	return;
}

static int
hwpstate_set(device_t dev, const struct cf_setting *cf)
{
	struct hwpstate_softc *sc;
	struct hwpstate_setting *set;
	int i;
	if (cf == NULL)
		return (EINVAL);
	sc = device_get_softc(dev);
	set = sc->hwpstate_settings;
	for (i = 0; i < sc->cfnum; i++)
		if (cf->freq == set[i].freq)
			break;
	if (i == sc->cfnum)
		return EINVAL;
	if(hwpstate_verbose)
		device_printf(dev,"goto P%d-state\n",set[i].pstate_id);
	sc->curpstate = set[i].pstate_id;
	hwpstate_goto_pstate(dev,set[i].pstate_id);
	return (0);
}

static int
hwpstate_get(device_t dev, struct cf_setting *cf)
{
	struct hwpstate_softc *sc;
	struct hwpstate_setting set;
	sc = device_get_softc(dev);
	if (cf == NULL)
		return (EINVAL);
	set = sc->hwpstate_settings[sc->curpstate];
	cf->freq = set.freq;
	cf->volts = set.volts;
	cf->power = CPUFREQ_VAL_UNKNOWN;
	cf->lat = 16;
	cf->dev = dev;
	return (0);
}

static int
hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
{
	struct hwpstate_softc *sc;
	struct hwpstate_setting set;
	int i;
	if (sets == NULL || count == NULL)
		return (EINVAL);
	sc = device_get_softc(dev);
	if (*count < sc->cfnum)
		return (E2BIG);
	for (i = 0; i < sc->cfnum; i++, sets++) {
		set = sc->hwpstate_settings[i];
		sets->freq = set.freq;
		sets->volts = set.volts;
		sets->power = set.power;
		sets->lat = set.lat;
		sets->dev = set.dev;
	}
	*count = sc->cfnum;
	return (0);
}

static int
hwpstate_type(device_t dev, int *type)
{

	if (type == NULL)
		return (EINVAL);
	*type = CPUFREQ_TYPE_ABSOLUTE;
	return (0);
}

static int
hwpstate_is_capable(void)
{
	u_int regs[4];
	if (strcmp(cpu_vendor, "AuthenticAMD") != 0 ||
	    cpu_exthigh < 0x80000007)
		return (FALSE);
	do_cpuid(0x80000007, regs);
	if (regs[3] & 0x80) {	/* HwPstate Enable bit */
		return (TRUE);
	}
	return (FALSE);
}

static void
hwpstate_identify(driver_t * driver, device_t parent)
{
	device_t child;
	if (device_find_child(parent, "hwpstate", -1) != NULL) {
		return;
	}
	if ((child = BUS_ADD_CHILD(parent, 10, "hwpstate", -1)) == NULL)
		device_printf(parent, "hwpstate: add child failed\n");
}

static int
hwpstate_probe(device_t dev)
{
	struct hwpstate_softc *sc;
	device_t perf_dev;
	uint64_t msr;
	int error, type;
	if (resource_disabled("hwpstate", 0))
		return (ENXIO);

	/* this had not to be in hwpstate_identify() */
	if (hwpstate_is_capable() == FALSE) {
		return (ENXIO);
	}
	perf_dev = device_find_child(device_get_parent(dev), "acpi_perf", -1);
	if (perf_dev && device_is_attached(perf_dev)) {
		error = CPUFREQ_DRV_TYPE(perf_dev, &type);
		if (error == 0 && (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
			return (ENXIO);
	}
	sc = device_get_softc(dev);
	switch (cpu_id) {
	case 0x100f2A:		/* family 10h rev.DR-BA */
	case 0x100f22:		/* family 10h rev.DR-B2 */
	case 0x100f23:		/* family 10h rev.DR-B3 */
		break;
	default:
		return (ENXIO);
	}
	msr = rdmsr(MSR_AMD10H_LIMIT);
	sc->cfnum = AMD10H_GET_PSTATE_MAX_VAL(msr);
	if (sc->cfnum == 0) {
		device_printf(dev, "hardware-pstate is not supported by the bios.\n");
		return ENXIO;
	}
	device_set_desc(dev, "Cool`n'Quiet 2.0");
	return (0);
}

static int
hwpstate_attach(device_t dev)
{
	struct hwpstate_softc *sc;
	struct hwpstate_setting *set;
	device_t F3;
	uint64_t msr;
	uint32_t cfg;
	int i, vid, did, fid;
	sc = device_get_softc(dev);

	/**
	 * following 24 means the 1st cpu. 25-31 instead of 24 is MP system.
	 * I don't have MP system . But only for reading from 1st cpu.
	 * so if the same 2*cpu , 4*cpu ,or 8*cpu , this can work , I think.
	 */
	F3 = pci_find_bsf(0, 24, 3);
	cfg = pci_read_config(F3, 0xA0, 4);
	if (cfg & 0x10) {	/* PVI mode */
		if (hwpstate_verbose)
			device_printf(dev, "PVI mode\n");
		sc->voltage_mode = AMD10H_PVI_MODE;
	} else {		/* SVI mode */
		if (hwpstate_verbose)
			device_printf(dev, "SVI mode\n");
		sc->voltage_mode = AMD10H_SVI_MODE;
	}
	msr = rdmsr(MSR_AMD10H_LIMIT);
	sc->cfnum = 1 + AMD10H_GET_PSTATE_MAX_VAL(msr);
	if (hwpstate_verbose)
		device_printf(dev, "you have %d P-state.\n", sc->cfnum);
	set = sc->hwpstate_settings;
	for (i = 0; i < sc->cfnum; i++, set++) {
		msr = rdmsr(MSR_AMD10H_CONFIG + i);
		if ((msr & 0x8000000000000000)) {
			vid = MSR_AMD10H_CUR_VID(msr);
			did = MSR_AMD10H_CUR_DID(msr);
			fid = MSR_AMD10H_CUR_FID(msr);
			set->freq = 100 * (fid + 0x10) / (1 << did);
			if (sc->voltage_mode == AMD10H_PVI_MODE) {
				/* 2.4.1.6.2 Parallel VID Encodings */
				if (vid >= 0x20)
					set->volts = (7625 - 125 * (vid - 0x20)) / 10;
				else
					set->volts = 1550 - 25 * vid;
			} else {
				/* 2.4.1.6.3 Serial VID Encodings */
				if (vid >= 0x7F)
					set->volts = 0;
				else
					set->volts = (15500 - 125 * vid) / 10;
			}
			if (hwpstate_verbose)
				device_printf(dev, "freq=%dMHz volts=%dmV\n", set->freq, set->volts);
			set->pstate_id = i;
			set->power = CPUFREQ_VAL_UNKNOWN;
			set->lat = 16;
			set->dev = dev;
		}
	}
	cpufreq_register(dev);
	hwpstate_goto_pstate(dev,0);
	return (0);
}

static int
hwpstate_detach(device_t dev)
{

	hwpstate_goto_pstate(dev,0);
	return (cpufreq_unregister(dev));
}

static int
hwpstate_shutdown(device_t dev)
{

	hwpstate_goto_pstate(dev,0);
	return (0);
}

static int
hwpstate_features(driver_t * driver, u_int * features)
{

	*features = ACPI_CAP_PERF_MSRS;
	return (0);
}
