Add Transmeta Crusoe LongRun support.

Submitted by:	Tamotsu HATTORI <athlete@kta.att.ne.jp>
Reviewed by:	arch@ folks
MFC after:	1 week
This commit is contained in:
Mitsuru IWASAKI 2001-07-03 10:03:24 +00:00
parent ac731e6941
commit 6cee406625
4 changed files with 470 additions and 1 deletions

View File

@ -3,7 +3,7 @@
MAN= aic.4 alpm.4 apm.4 ar.4 asc.4 asr.4 \
cs.4 cx.4 cy.4 \
dgb.4 el.4 en.4 ep.4 ex.4 fe.4 gsc.4 \
ie.4 io.4 labpc.4 le.4 linux.4 lnc.4 matcd.4 mcd.4 \
ie.4 io.4 labpc.4 le.4 linux.4 lnc.4 longrun.4 matcd.4 mcd.4 \
meteor.4 mse.4 npx.4 \
pcf.4 perfmon.4 pnp.4 \
ray.4 rdp.4 sb.4 scd.4 \

View File

@ -0,0 +1,73 @@
.\" Copyright (c) 2001 Tamotsu HATTORI <athlete@kta.att.ne.jp>
.\" Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
.\" 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 AUTHOR 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 AUTHOR 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.
.\"
.\" $FreeBSD$
.Dd Jun 30, 2001
.Dt LONGRUN 4 i386
.Os
.Sh NAME
.Nm longrun
.Nd Transmeta(TM) Crusoe(TM) LongRun(TM) support
.Sh SYNOPSIS
LongRun support is a collection of power saving modes for the
Transmeta Crusoe chips, similar in scope to Intel's SpeedStep.
The following
.Xr sysctl 8
MIBs control the different CPU modes:
.Bl -tag -width "hw.crusoe.percentage integer no " -compact
.It Sy "Name Type Changeable Description
.It "hw.crusoe.longrun integer yes LongRun mode.
.Bl -tag -width "0: minimum frequency mode" -compact
.It "0: minimum frequency mode
.It "1: power-saving mode
.It "2: performance mode
.It "3: maximum frequency mode
.El
.It "hw.crusoe.frequency integer no Current frequency (MHz).
.It "hw.crusoe.voltage integer no Current voltage (mV).
.It "hw.crusoe.percentage integer no Processing performance (%).
.El
.Pp
.Sh EXAMPLES
Print the current status:
.Bd -literal -offset indent
% sysctl hw.crusoe
.Ed
.Pp
To set LongRun mode to performance oriented variable frequency mode
(less power savings):
.Bd -literal -offset indent
# sysctl -w hw.crusoe.longrun=2
.Ed
.Pp
.Sh AUTHORS
.An -nosplit
LongRun support and this manual page were written by
.An Tamotsu HATTORI Aq athlete@kta.att.ne.jp
and
.An Mitsuru IWASAKI Aq iwasaki@FreeBSD.org .
.Sh HISTORY
The Transmeta(TM) Crusoe(TM) LongRun(TM) support first appeared in
.Fx 5.0 .

View File

@ -2,6 +2,8 @@
* Copyright (c) 1992 Terrence R. Lambert.
* Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
* Copyright (c) 1997 KATO Takenori.
* Copyright (c) 2001 Tamotsu Hattori.
* Copyright (c) 2001 Mitsuru IWASAKI.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@ -77,6 +79,7 @@ static void print_AMD_features(u_int *regs);
static void print_AMD_info(u_int amd_maxregs);
static void print_AMD_assoc(int i);
static void print_transmeta_info(void);
static void setup_tmx86_longrun(void);
static void do_cpuid(u_int ax, u_int *p);
u_int cyrix_did; /* Device ID of Cyrix CPU */
@ -621,6 +624,11 @@ printcpuinfo(void)
printf("\n");
#endif
if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
strcmp(cpu_vendor, "TransmetaCPU") == 0) {
setup_tmx86_longrun();
}
if (!bootverbose)
return;
@ -1026,6 +1034,189 @@ print_AMD_features(u_int *regs)
);
}
/*
* Transmeta Crusoe LongRun Support by Tamotsu Hattori.
*/
#define MSR_TMx86_LONGRUN 0x80868010
#define MSR_TMx86_LONGRUN_FLAGS 0x80868011
#define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
#define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
#define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
#define LONGRUN_MODE_MINFREQUENCY 0x00
#define LONGRUN_MODE_ECONOMY 0x01
#define LONGRUN_MODE_PERFORMANCE 0x02
#define LONGRUN_MODE_MAXFREQUENCY 0x03
#define LONGRUN_MODE_UNKNOWN 0x04
#define LONGRUN_MODE_MAX 0x04
union msrinfo {
u_int64_t msr;
u_int32_t regs[2];
};
u_int32_t longrun_modes[LONGRUN_MODE_MAX][3] = {
/* MSR low, MSR high, flags bit0 */
{ 0, 0, 0}, /* LONGRUN_MODE_MINFREQUENCY */
{ 0, 100, 0}, /* LONGRUN_MODE_ECONOMY */
{ 0, 100, 1}, /* LONGRUN_MODE_PERFORMANCE */
{ 100, 100, 1}, /* LONGRUN_MODE_MAXFREQUENCY */
};
static u_int
tmx86_get_longrun_mode(void)
{
u_long eflags;
union msrinfo msrinfo;
u_int low, high, flags, mode;
eflags = read_eflags();
disable_intr();
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
low = LONGRUN_MODE_MASK(msrinfo.regs[0]);
high = LONGRUN_MODE_MASK(msrinfo.regs[1]);
flags = rdmsr(MSR_TMx86_LONGRUN_FLAGS) & 0x01;
for (mode = 0; mode < LONGRUN_MODE_MAX; mode++) {
if (low == longrun_modes[mode][0] &&
high == longrun_modes[mode][1] &&
flags == longrun_modes[mode][2]) {
goto out;
}
}
mode = LONGRUN_MODE_UNKNOWN;
out:
write_eflags(eflags);
return (mode);
}
static u_int
tmx86_get_longrun_status(u_int * frequency, u_int * voltage, u_int * percentage)
{
u_long eflags;
u_int regs[4];
eflags = read_eflags();
disable_intr();
do_cpuid(0x80860007, regs);
*frequency = regs[0];
*voltage = regs[1];
*percentage = regs[2];
write_eflags(eflags);
return (1);
}
static u_int
tmx86_set_longrun_mode(u_int mode)
{
u_long eflags;
union msrinfo msrinfo;
if (mode >= LONGRUN_MODE_UNKNOWN) {
return (0);
}
eflags = read_eflags();
disable_intr();
/* Write LongRun mode values to Model Specific Register. */
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0],
longrun_modes[mode][0]);
msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1],
longrun_modes[mode][1]);
wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
/* Write LongRun mode flags to Model Specific Register. */
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | longrun_modes[mode][2];
wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
write_eflags(eflags);
return (1);
}
static u_int crusoe_longrun;
static u_int crusoe_frequency;
static u_int crusoe_voltage;
static u_int crusoe_percentage;
static struct sysctl_ctx_list crusoe_sysctl_ctx;
static struct sysctl_oid *crusoe_sysctl_tree;
static int
tmx86_longrun_sysctl(SYSCTL_HANDLER_ARGS)
{
u_int mode;
int error;
crusoe_longrun = tmx86_get_longrun_mode();
mode = crusoe_longrun;
error = sysctl_handle_int(oidp, &mode, 0, req);
if (error || !req->newptr) {
return (error);
}
if (mode >= LONGRUN_MODE_UNKNOWN) {
error = EINVAL;
return (error);
}
if (crusoe_longrun != mode) {
crusoe_longrun = mode;
tmx86_set_longrun_mode(crusoe_longrun);
}
return (error);
}
static int
tmx86_status_sysctl(SYSCTL_HANDLER_ARGS)
{
u_int val;
int error;
tmx86_get_longrun_status(&crusoe_frequency,
&crusoe_voltage, &crusoe_percentage);
val = *(u_int *)oidp->oid_arg1;
error = sysctl_handle_int(oidp, &val, 0, req);
return (error);
}
static void
setup_tmx86_longrun(void)
{
static int done = 0;
if (done)
return;
done++;
sysctl_ctx_init(&crusoe_sysctl_ctx);
crusoe_sysctl_tree = SYSCTL_ADD_NODE(&crusoe_sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
"crusoe", CTLFLAG_RD, 0,
"Transmeta Crusoe LongRun support");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "longrun", CTLTYPE_INT | CTLFLAG_RW,
&crusoe_longrun, 0, tmx86_longrun_sysctl, "I",
"LongRun mode [0-3]");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "frequency", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_frequency, 0, tmx86_status_sysctl, "I",
"Current frequency (MHz)");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "voltage", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_voltage, 0, tmx86_status_sysctl, "I",
"Current voltage (mV)");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "percentage", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_percentage, 0, tmx86_status_sysctl, "I",
"Processing performance (%)");
}
static void
print_transmeta_info()
{
@ -1059,4 +1250,11 @@ print_transmeta_info()
info[64] = 0;
printf(" %s\n", info);
}
crusoe_longrun = tmx86_get_longrun_mode();
tmx86_get_longrun_status(&crusoe_frequency,
&crusoe_voltage, &crusoe_percentage);
printf(" LongRun mode: %d <%dMHz %dmV %d%%>\n", crusoe_longrun,
crusoe_frequency, crusoe_voltage, crusoe_percentage);
}

View File

@ -2,6 +2,8 @@
* Copyright (c) 1992 Terrence R. Lambert.
* Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
* Copyright (c) 1997 KATO Takenori.
* Copyright (c) 2001 Tamotsu Hattori.
* Copyright (c) 2001 Mitsuru IWASAKI.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@ -77,6 +79,7 @@ static void print_AMD_features(u_int *regs);
static void print_AMD_info(u_int amd_maxregs);
static void print_AMD_assoc(int i);
static void print_transmeta_info(void);
static void setup_tmx86_longrun(void);
static void do_cpuid(u_int ax, u_int *p);
u_int cyrix_did; /* Device ID of Cyrix CPU */
@ -621,6 +624,11 @@ printcpuinfo(void)
printf("\n");
#endif
if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
strcmp(cpu_vendor, "TransmetaCPU") == 0) {
setup_tmx86_longrun();
}
if (!bootverbose)
return;
@ -1026,6 +1034,189 @@ print_AMD_features(u_int *regs)
);
}
/*
* Transmeta Crusoe LongRun Support by Tamotsu Hattori.
*/
#define MSR_TMx86_LONGRUN 0x80868010
#define MSR_TMx86_LONGRUN_FLAGS 0x80868011
#define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
#define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
#define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
#define LONGRUN_MODE_MINFREQUENCY 0x00
#define LONGRUN_MODE_ECONOMY 0x01
#define LONGRUN_MODE_PERFORMANCE 0x02
#define LONGRUN_MODE_MAXFREQUENCY 0x03
#define LONGRUN_MODE_UNKNOWN 0x04
#define LONGRUN_MODE_MAX 0x04
union msrinfo {
u_int64_t msr;
u_int32_t regs[2];
};
u_int32_t longrun_modes[LONGRUN_MODE_MAX][3] = {
/* MSR low, MSR high, flags bit0 */
{ 0, 0, 0}, /* LONGRUN_MODE_MINFREQUENCY */
{ 0, 100, 0}, /* LONGRUN_MODE_ECONOMY */
{ 0, 100, 1}, /* LONGRUN_MODE_PERFORMANCE */
{ 100, 100, 1}, /* LONGRUN_MODE_MAXFREQUENCY */
};
static u_int
tmx86_get_longrun_mode(void)
{
u_long eflags;
union msrinfo msrinfo;
u_int low, high, flags, mode;
eflags = read_eflags();
disable_intr();
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
low = LONGRUN_MODE_MASK(msrinfo.regs[0]);
high = LONGRUN_MODE_MASK(msrinfo.regs[1]);
flags = rdmsr(MSR_TMx86_LONGRUN_FLAGS) & 0x01;
for (mode = 0; mode < LONGRUN_MODE_MAX; mode++) {
if (low == longrun_modes[mode][0] &&
high == longrun_modes[mode][1] &&
flags == longrun_modes[mode][2]) {
goto out;
}
}
mode = LONGRUN_MODE_UNKNOWN;
out:
write_eflags(eflags);
return (mode);
}
static u_int
tmx86_get_longrun_status(u_int * frequency, u_int * voltage, u_int * percentage)
{
u_long eflags;
u_int regs[4];
eflags = read_eflags();
disable_intr();
do_cpuid(0x80860007, regs);
*frequency = regs[0];
*voltage = regs[1];
*percentage = regs[2];
write_eflags(eflags);
return (1);
}
static u_int
tmx86_set_longrun_mode(u_int mode)
{
u_long eflags;
union msrinfo msrinfo;
if (mode >= LONGRUN_MODE_UNKNOWN) {
return (0);
}
eflags = read_eflags();
disable_intr();
/* Write LongRun mode values to Model Specific Register. */
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0],
longrun_modes[mode][0]);
msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1],
longrun_modes[mode][1]);
wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
/* Write LongRun mode flags to Model Specific Register. */
msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | longrun_modes[mode][2];
wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
write_eflags(eflags);
return (1);
}
static u_int crusoe_longrun;
static u_int crusoe_frequency;
static u_int crusoe_voltage;
static u_int crusoe_percentage;
static struct sysctl_ctx_list crusoe_sysctl_ctx;
static struct sysctl_oid *crusoe_sysctl_tree;
static int
tmx86_longrun_sysctl(SYSCTL_HANDLER_ARGS)
{
u_int mode;
int error;
crusoe_longrun = tmx86_get_longrun_mode();
mode = crusoe_longrun;
error = sysctl_handle_int(oidp, &mode, 0, req);
if (error || !req->newptr) {
return (error);
}
if (mode >= LONGRUN_MODE_UNKNOWN) {
error = EINVAL;
return (error);
}
if (crusoe_longrun != mode) {
crusoe_longrun = mode;
tmx86_set_longrun_mode(crusoe_longrun);
}
return (error);
}
static int
tmx86_status_sysctl(SYSCTL_HANDLER_ARGS)
{
u_int val;
int error;
tmx86_get_longrun_status(&crusoe_frequency,
&crusoe_voltage, &crusoe_percentage);
val = *(u_int *)oidp->oid_arg1;
error = sysctl_handle_int(oidp, &val, 0, req);
return (error);
}
static void
setup_tmx86_longrun(void)
{
static int done = 0;
if (done)
return;
done++;
sysctl_ctx_init(&crusoe_sysctl_ctx);
crusoe_sysctl_tree = SYSCTL_ADD_NODE(&crusoe_sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
"crusoe", CTLFLAG_RD, 0,
"Transmeta Crusoe LongRun support");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "longrun", CTLTYPE_INT | CTLFLAG_RW,
&crusoe_longrun, 0, tmx86_longrun_sysctl, "I",
"LongRun mode [0-3]");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "frequency", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_frequency, 0, tmx86_status_sysctl, "I",
"Current frequency (MHz)");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "voltage", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_voltage, 0, tmx86_status_sysctl, "I",
"Current voltage (mV)");
SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
OID_AUTO, "percentage", CTLTYPE_INT | CTLFLAG_RD,
&crusoe_percentage, 0, tmx86_status_sysctl, "I",
"Processing performance (%)");
}
static void
print_transmeta_info()
{
@ -1059,4 +1250,11 @@ print_transmeta_info()
info[64] = 0;
printf(" %s\n", info);
}
crusoe_longrun = tmx86_get_longrun_mode();
tmx86_get_longrun_status(&crusoe_frequency,
&crusoe_voltage, &crusoe_percentage);
printf(" LongRun mode: %d <%dMHz %dmV %d%%>\n", crusoe_longrun,
crusoe_frequency, crusoe_voltage, crusoe_percentage);
}