xref: /openbsd-src/sys/arch/i386/i386/p4tcc.c (revision 7f58a11f6cf13dbd32877952ad2ecc2790ae3977)
1 /*	$OpenBSD: p4tcc.c,v 1.19 2014/09/14 14:17:23 jsg Exp $ */
2 /*
3  * Copyright (c) 2003 Ted Unangst
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 /*
28  * Restrict power consumption by using thermal control circuit.
29  * This operates independently of speedstep.
30  * Found on Pentium 4 and later models (feature TM).
31  *
32  * References:
33  * Intel Developer's manual v.3 #245472-012
34  *
35  * On some models, the cpu can hang if it's running at a slow speed.
36  * Workarounds included below.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sysctl.h>
42 
43 #include <machine/cpu.h>
44 #include <machine/cpufunc.h>
45 #include <machine/specialreg.h>
46 
47 static struct {
48 	u_short level;
49 	u_short reg;
50 } tcc[] = {
51 	{ 88, 0 },
52 	{ 75, 7 },
53 	{ 63, 6 },
54 	{ 50, 5 },
55 	{ 38, 4 },
56 	{ 25, 3 },
57 	{ 13, 2 },
58 	{ 0, 1 }
59 };
60 
61 #define TCC_LEVELS sizeof(tcc) / sizeof(tcc[0])
62 
63 extern int setperf_prio;
64 int p4tcc_level;
65 
66 int p4tcc_cpuspeed(int *);
67 
68 void
p4tcc_init(int family,int step)69 p4tcc_init(int family, int step)
70 {
71 	if (setperf_prio > 1)
72 		return;
73 
74 	switch (family) {
75 	case 0xf:	/* Pentium 4 */
76 		switch (step) {
77 		case 0x22:	/* errata O50 P44 and Z21 */
78 		case 0x24:
79 		case 0x25:
80 		case 0x27:
81 		case 0x29:
82 			/* hang with 12.5 */
83 			tcc[TCC_LEVELS - 1].reg = 2;
84 			break;
85 		case 0x07:	/* errata N44 and P18 */
86 		case 0x0a:
87 		case 0x12:
88 		case 0x13:
89 			/* hang at 12.5 and 25 */
90 			tcc[TCC_LEVELS - 1].reg = 3;
91 			tcc[TCC_LEVELS - 2].reg = 3;
92 			break;
93 		}
94 		break;
95 	}
96 
97 	p4tcc_level = tcc[0].level;
98 	cpu_setperf = p4tcc_setperf;
99 	cpu_cpuspeed = p4tcc_cpuspeed;
100 	setperf_prio = 1;
101 }
102 
103 int
p4tcc_cpuspeed(int * speed)104 p4tcc_cpuspeed(int *speed)
105 {
106 	*speed = cpuspeed * (p4tcc_level + 12) / 100;
107 
108 	return 0;
109 }
110 
111 void
p4tcc_setperf(int level)112 p4tcc_setperf(int level)
113 {
114 	int i;
115 	uint64_t msreg, vet;
116 
117 	for (i = 0; i < TCC_LEVELS; i++) {
118 		if (level >= tcc[i].level)
119 			break;
120 	}
121 	if (i == TCC_LEVELS)
122 		i = TCC_LEVELS - 1;
123 
124 	msreg = rdmsr(MSR_THERM_CONTROL);
125 	msreg &= ~0x1e; /* bit 0 reserved */
126 	if (tcc[i].reg != 0) /* enable it */
127 		msreg |= tcc[i].reg << 1 | 1 << 4;
128 	wrmsr(MSR_THERM_CONTROL, msreg);
129 	vet = rdmsr(MSR_THERM_CONTROL);
130 
131 	if ((vet & 0x1e) != (msreg & 0x1e))
132 		printf("p4_tcc: cpu did not honor request\n");
133 	else
134 		p4tcc_level = tcc[i].level;
135 }
136