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