From 7045833f245f98ae7fbee3190961ebf89af4d769 Mon Sep 17 00:00:00 2001 From: Jeroen Ruigrok/asmodai Date: Tue, 27 Jul 2004 10:55:57 +0000 Subject: [PATCH] Actually add the main file for Pentium 4 Thermal Control Circuit support. Obtained from: FreeBSD(from OpenBSD) Submitted by: Johannes Hofmann Reminded by: YONETANI Tomokazu OK'd by: dillon Feeling like an idiot: asmodai --- sys/i386/i386/p4tcc.c | 251 +++++++++++++++++++++++++++++++++ sys/platform/pc32/i386/p4tcc.c | 251 +++++++++++++++++++++++++++++++++ 2 files changed, 502 insertions(+) create mode 100644 sys/i386/i386/p4tcc.c create mode 100644 sys/platform/pc32/i386/p4tcc.c diff --git a/sys/i386/i386/p4tcc.c b/sys/i386/i386/p4tcc.c new file mode 100644 index 0000000000..9d9ebaab30 --- /dev/null +++ b/sys/i386/i386/p4tcc.c @@ -0,0 +1,251 @@ +/* $OpenBSD: p4tcc.c,v 1.1 2003/12/20 18:23:18 tedu Exp $ */ +/* + * Copyright (c) 2003 Ted Unangst + * Copyright (c) 2004 Maxim Sobolev + * 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 ``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. + */ +/* + * Restrict power consumption by using thermal control circuit. + * This operates independently of speedstep. + * Found on Pentium 4 and later models (feature TM). + * + * References: + * Intel Developer's manual v.3 #245472-012 + * + * On some models, the cpu can hang if it's running at a slow speed. + * Workarounds included below. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/i386/i386/p4tcc.c,v 1.3.2.1 2004/03/03 15:24:15 sobomax Exp $ + * $DragonFly: src/sys/i386/i386/Attic/p4tcc.c,v 1.1 2004/07/27 10:55:57 asmodai Exp $ + */ + +#include + +#include "opt_cpu.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static u_int p4tcc_percentage; +static u_int p4tcc_economy; +static u_int p4tcc_performance; +static struct sysctl_ctx_list p4tcc_sysctl_ctx; +static struct sysctl_oid *p4tcc_sysctl_tree; + +static struct { + u_short level; + u_short rlevel; + u_short reg; +} tcc[] = { + { 88, 100, 0 }, + { 75, 88, 7 }, + { 63, 75, 6 }, + { 50, 63, 5 }, + { 38, 50, 4 }, + { 25, 38, 3 }, + { 13, 25, 2 }, + { 0, 13, 1 } +}; + +#define TCC_LEVELS sizeof(tcc) / sizeof(tcc[0]) + +static u_short +p4tcc_getperf(void) +{ + u_int64_t msreg; + int i; + + msreg = rdmsr(MSR_THERM_CONTROL); + msreg = (msreg >> 1) & 0x07; + for (i = 0; i < TCC_LEVELS; i++) { + if (msreg == tcc[i].reg) + break; + } + + return (tcc[i].rlevel); +} + +static void +p4tcc_setperf(u_int percentage) +{ + int i; + u_int64_t msreg; + + if (percentage > tcc[0].rlevel) + percentage = tcc[0].rlevel; + for (i = 0; i < TCC_LEVELS - 1; i++) { + if (percentage > tcc[i].level) + break; + } + + msreg = rdmsr(MSR_THERM_CONTROL); + msreg &= ~0x1e; /* bit 0 reserved */ + if (tcc[i].reg != 0) + msreg |= tcc[i].reg << 1 | 1 << 4; + wrmsr(MSR_THERM_CONTROL, msreg); +} + +static int +p4tcc_perf_sysctl(SYSCTL_HANDLER_ARGS) +{ + u_int percentage; + int error; + + p4tcc_percentage = p4tcc_getperf(); + percentage = p4tcc_percentage; + error = sysctl_handle_int(oidp, &percentage, 0, req); + if (error || !req->newptr) { + return (error); + } + if (p4tcc_percentage != percentage) { + p4tcc_setperf(percentage); + } + + return (error); +} + +static void +p4tcc_power_profile(void *arg) +{ + int state; + u_int new; + + state = power_profile_get_state(); + if (state != POWER_PROFILE_PERFORMANCE && + state != POWER_PROFILE_ECONOMY) { + return; + } + + switch (state) { + case POWER_PROFILE_PERFORMANCE: + new = p4tcc_performance; + break; + case POWER_PROFILE_ECONOMY: + new = p4tcc_economy; + break; + default: + new = p4tcc_getperf(); + break; + } + + if (p4tcc_getperf() != new) { + p4tcc_setperf(new); + } +} + +static int +p4tcc_profile_sysctl(SYSCTL_HANDLER_ARGS) +{ + u_int32_t *argp; + u_int32_t arg; + int error; + + argp = (u_int32_t *)oidp->oid_arg1; + arg = *argp; + error = sysctl_handle_int(oidp, &arg, 0, req); + + /* error or no new value */ + if ((error != 0) || (req->newptr == NULL)) + return (error); + + /* range check */ + if (arg > tcc[0].rlevel) + arg = tcc[0].rlevel; + + /* set new value and possibly switch */ + *argp = arg; + + p4tcc_power_profile(NULL); + + *argp = p4tcc_getperf(); + + return (0); +} + +static void +setup_p4tcc(void *dummy __unused) +{ + + if ((cpu_feature & (CPUID_ACPI | CPUID_TM)) != + (CPUID_ACPI | CPUID_TM)) + return; + + switch (cpu_id & 0xf) { + case 0x22: /* errata O50 P44 and Z21 */ + case 0x24: + case 0x25: + case 0x27: + case 0x29: + /* hang with 12.5 */ + tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2]; + break; + case 0x07: /* errata N44 and P18 */ + case 0x0a: + case 0x12: + case 0x13: + /* hang at 12.5 and 25 */ + tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2] = tcc[TCC_LEVELS - 3]; + break; + default: + break; + } + + p4tcc_economy = tcc[TCC_LEVELS - 1].rlevel; + p4tcc_performance = tcc[0].rlevel; + + p4tcc_percentage = p4tcc_getperf(); + printf("Pentium 4 TCC support enabled, current performance %u%%\n", + p4tcc_percentage); + + sysctl_ctx_init(&p4tcc_sysctl_ctx); + p4tcc_sysctl_tree = SYSCTL_ADD_NODE(&p4tcc_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "p4tcc", CTLFLAG_RD, 0, + "Pentium 4 Thermal Control Circuitry support"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf", CTLTYPE_INT | CTLFLAG_RW, + &p4tcc_percentage, 0, p4tcc_perf_sysctl, "I", + "CPU performance in % of maximum"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf_performance", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW, + &p4tcc_performance, 0, p4tcc_profile_sysctl, "I", + "CPU performance in % of maximum in Performance mode"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf_economy", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW, + &p4tcc_economy, 0, p4tcc_profile_sysctl, "I", + "CPU performance in % of maximum in Economy mode"); + + /* register performance profile change handler */ + EVENTHANDLER_REGISTER(power_profile_change, p4tcc_power_profile, NULL, 0); +} +SYSINIT(setup_p4tcc, SI_SUB_CPU, SI_ORDER_ANY, setup_p4tcc, NULL); diff --git a/sys/platform/pc32/i386/p4tcc.c b/sys/platform/pc32/i386/p4tcc.c new file mode 100644 index 0000000000..05c475a9fd --- /dev/null +++ b/sys/platform/pc32/i386/p4tcc.c @@ -0,0 +1,251 @@ +/* $OpenBSD: p4tcc.c,v 1.1 2003/12/20 18:23:18 tedu Exp $ */ +/* + * Copyright (c) 2003 Ted Unangst + * Copyright (c) 2004 Maxim Sobolev + * 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 ``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. + */ +/* + * Restrict power consumption by using thermal control circuit. + * This operates independently of speedstep. + * Found on Pentium 4 and later models (feature TM). + * + * References: + * Intel Developer's manual v.3 #245472-012 + * + * On some models, the cpu can hang if it's running at a slow speed. + * Workarounds included below. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/i386/i386/p4tcc.c,v 1.3.2.1 2004/03/03 15:24:15 sobomax Exp $ + * $DragonFly: src/sys/platform/pc32/i386/p4tcc.c,v 1.1 2004/07/27 10:55:57 asmodai Exp $ + */ + +#include + +#include "opt_cpu.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static u_int p4tcc_percentage; +static u_int p4tcc_economy; +static u_int p4tcc_performance; +static struct sysctl_ctx_list p4tcc_sysctl_ctx; +static struct sysctl_oid *p4tcc_sysctl_tree; + +static struct { + u_short level; + u_short rlevel; + u_short reg; +} tcc[] = { + { 88, 100, 0 }, + { 75, 88, 7 }, + { 63, 75, 6 }, + { 50, 63, 5 }, + { 38, 50, 4 }, + { 25, 38, 3 }, + { 13, 25, 2 }, + { 0, 13, 1 } +}; + +#define TCC_LEVELS sizeof(tcc) / sizeof(tcc[0]) + +static u_short +p4tcc_getperf(void) +{ + u_int64_t msreg; + int i; + + msreg = rdmsr(MSR_THERM_CONTROL); + msreg = (msreg >> 1) & 0x07; + for (i = 0; i < TCC_LEVELS; i++) { + if (msreg == tcc[i].reg) + break; + } + + return (tcc[i].rlevel); +} + +static void +p4tcc_setperf(u_int percentage) +{ + int i; + u_int64_t msreg; + + if (percentage > tcc[0].rlevel) + percentage = tcc[0].rlevel; + for (i = 0; i < TCC_LEVELS - 1; i++) { + if (percentage > tcc[i].level) + break; + } + + msreg = rdmsr(MSR_THERM_CONTROL); + msreg &= ~0x1e; /* bit 0 reserved */ + if (tcc[i].reg != 0) + msreg |= tcc[i].reg << 1 | 1 << 4; + wrmsr(MSR_THERM_CONTROL, msreg); +} + +static int +p4tcc_perf_sysctl(SYSCTL_HANDLER_ARGS) +{ + u_int percentage; + int error; + + p4tcc_percentage = p4tcc_getperf(); + percentage = p4tcc_percentage; + error = sysctl_handle_int(oidp, &percentage, 0, req); + if (error || !req->newptr) { + return (error); + } + if (p4tcc_percentage != percentage) { + p4tcc_setperf(percentage); + } + + return (error); +} + +static void +p4tcc_power_profile(void *arg) +{ + int state; + u_int new; + + state = power_profile_get_state(); + if (state != POWER_PROFILE_PERFORMANCE && + state != POWER_PROFILE_ECONOMY) { + return; + } + + switch (state) { + case POWER_PROFILE_PERFORMANCE: + new = p4tcc_performance; + break; + case POWER_PROFILE_ECONOMY: + new = p4tcc_economy; + break; + default: + new = p4tcc_getperf(); + break; + } + + if (p4tcc_getperf() != new) { + p4tcc_setperf(new); + } +} + +static int +p4tcc_profile_sysctl(SYSCTL_HANDLER_ARGS) +{ + u_int32_t *argp; + u_int32_t arg; + int error; + + argp = (u_int32_t *)oidp->oid_arg1; + arg = *argp; + error = sysctl_handle_int(oidp, &arg, 0, req); + + /* error or no new value */ + if ((error != 0) || (req->newptr == NULL)) + return (error); + + /* range check */ + if (arg > tcc[0].rlevel) + arg = tcc[0].rlevel; + + /* set new value and possibly switch */ + *argp = arg; + + p4tcc_power_profile(NULL); + + *argp = p4tcc_getperf(); + + return (0); +} + +static void +setup_p4tcc(void *dummy __unused) +{ + + if ((cpu_feature & (CPUID_ACPI | CPUID_TM)) != + (CPUID_ACPI | CPUID_TM)) + return; + + switch (cpu_id & 0xf) { + case 0x22: /* errata O50 P44 and Z21 */ + case 0x24: + case 0x25: + case 0x27: + case 0x29: + /* hang with 12.5 */ + tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2]; + break; + case 0x07: /* errata N44 and P18 */ + case 0x0a: + case 0x12: + case 0x13: + /* hang at 12.5 and 25 */ + tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2] = tcc[TCC_LEVELS - 3]; + break; + default: + break; + } + + p4tcc_economy = tcc[TCC_LEVELS - 1].rlevel; + p4tcc_performance = tcc[0].rlevel; + + p4tcc_percentage = p4tcc_getperf(); + printf("Pentium 4 TCC support enabled, current performance %u%%\n", + p4tcc_percentage); + + sysctl_ctx_init(&p4tcc_sysctl_ctx); + p4tcc_sysctl_tree = SYSCTL_ADD_NODE(&p4tcc_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "p4tcc", CTLFLAG_RD, 0, + "Pentium 4 Thermal Control Circuitry support"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf", CTLTYPE_INT | CTLFLAG_RW, + &p4tcc_percentage, 0, p4tcc_perf_sysctl, "I", + "CPU performance in % of maximum"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf_performance", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW, + &p4tcc_performance, 0, p4tcc_profile_sysctl, "I", + "CPU performance in % of maximum in Performance mode"); + SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx, + SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO, + "cpuperf_economy", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW, + &p4tcc_economy, 0, p4tcc_profile_sysctl, "I", + "CPU performance in % of maximum in Economy mode"); + + /* register performance profile change handler */ + EVENTHANDLER_REGISTER(power_profile_change, p4tcc_power_profile, NULL, 0); +} +SYSINIT(setup_p4tcc, SI_SUB_CPU, SI_ORDER_ANY, setup_p4tcc, NULL); -- 2.41.0