From 8649f63ce3d8b1d0c505b196a678e290d4594a2d Mon Sep 17 00:00:00 2001
From: iwasaki <iwasaki@FreeBSD.org>
Date: Tue, 3 Jul 2001 10:03:24 +0000
Subject: [PATCH] Add Transmeta Crusoe LongRun support.

Submitted by:	Tamotsu HATTORI <athlete@kta.att.ne.jp>
Reviewed by:	arch@ folks
MFC after:	1 week
---
 share/man/man4/man4.i386/Makefile  |   2 +-
 share/man/man4/man4.i386/longrun.4 |  73 +++++++++++
 sys/amd64/amd64/identcpu.c         | 198 +++++++++++++++++++++++++++++
 sys/i386/i386/identcpu.c           | 198 +++++++++++++++++++++++++++++
 4 files changed, 470 insertions(+), 1 deletion(-)
 create mode 100644 share/man/man4/man4.i386/longrun.4

diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile
index 82a17b5ae8ee..5046a103098e 100644
--- a/share/man/man4/man4.i386/Makefile
+++ b/share/man/man4/man4.i386/Makefile
@@ -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 \
diff --git a/share/man/man4/man4.i386/longrun.4 b/share/man/man4/man4.i386/longrun.4
new file mode 100644
index 000000000000..ee418eecef8e
--- /dev/null
+++ b/share/man/man4/man4.i386/longrun.4
@@ -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 .
diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c
index 4a609241ec7e..485d94285ce0 100644
--- a/sys/amd64/amd64/identcpu.c
+++ b/sys/amd64/amd64/identcpu.c
@@ -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);
 }
+
diff --git a/sys/i386/i386/identcpu.c b/sys/i386/i386/identcpu.c
index 4a609241ec7e..485d94285ce0 100644
--- a/sys/i386/i386/identcpu.c
+++ b/sys/i386/i386/identcpu.c
@@ -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);
 }
+