1 /* $OpenBSD: p4tcc.c,v 1.14 2007/08/03 20:36:02 deraadt 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/sysctl.h>
41
42 #include <machine/cpu.h>
43 #include <machine/cpufunc.h>
44 #include <machine/specialreg.h>
45
46 static struct {
47 u_short level;
48 u_short reg;
49 } tcc[] = {
50 { 88, 0 },
51 { 75, 7 },
52 { 63, 6 },
53 { 50, 5 },
54 { 38, 4 },
55 { 25, 3 },
56 { 13, 2 },
57 { 0, 1 }
58 };
59
60 #define TCC_LEVELS sizeof(tcc) / sizeof(tcc[0])
61
62 extern int setperf_prio;
63 int p4tcc_level;
64
65 int p4tcc_cpuspeed(int *);
66
67 void
68 p4tcc_init(int family, int step)
69 {
70 if (setperf_prio > 1)
71 return;
72
73 switch (family) {
74 case 0xf: /* Pentium 4 */
75 switch (step) {
76 case 0x22: /* errata O50 P44 and Z21 */
77 case 0x24:
78 case 0x25:
79 case 0x27:
80 case 0x29:
81 /* hang with 12.5 */
82 tcc[TCC_LEVELS - 1].reg = 2;
83 break;
84 case 0x07: /* errata N44 and P18 */
85 case 0x0a:
86 case 0x12:
87 case 0x13:
88 /* hang at 12.5 and 25 */
89 tcc[TCC_LEVELS - 1].reg = 3;
90 tcc[TCC_LEVELS - 2].reg = 3;
91 break;
92 }
93 break;
94 }
95
96 p4tcc_level = tcc[0].level;
97 cpu_setperf = p4tcc_setperf;
98 cpu_cpuspeed = p4tcc_cpuspeed;
99 setperf_prio = 1;
100 }
101
102 int
103 p4tcc_cpuspeed(int *speed)
104 {
105 *speed = cpuspeed * (p4tcc_level + 12) / 100;
106
107 return 0;
108 }
109
110 void
111 p4tcc_setperf(int level)
112 {
113 int i;
114 uint64_t msreg, vet;
115
116 for (i = 0; i < TCC_LEVELS; i++) {
117 if (level >= tcc[i].level)
118 break;
119 }
120
121 msreg = rdmsr(MSR_THERM_CONTROL);
122 msreg &= ~0x1e; /* bit 0 reserved */
123 if (tcc[i].reg != 0) /* enable it */
124 msreg |= tcc[i].reg << 1 | 1 << 4;
125 wrmsr(MSR_THERM_CONTROL, msreg);
126 vet = rdmsr(MSR_THERM_CONTROL);
127
128 if ((vet & 0x1e) != (msreg & 0x1e))
129 printf("p4_tcc: cpu did not honor request\n");
130 else
131 p4tcc_level = tcc[i].level;
132 }