1 /* $NetBSD: odcm.c,v 1.4 2014/03/27 18:22:56 christos Exp $ */
2 /* $OpenBSD: p4tcc.c,v 1.13 2006/12/20 17:50:40 gwk Exp $ */
3
4 /*
5 * Copyright (c) 2007 Juan Romero Pardines
6 * Copyright (c) 2003 Ted Unangst
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * On-Demand Clock Modulation driver, to modulate the clock duty cycle
33 * by software. Available on Pentium M and later models (feature TM).
34 *
35 * References:
36 * Intel Developer's manual v.3 #245472-012
37 *
38 * On some models, the cpu can hang if it's running at a slow speed.
39 * Workarounds included below.
40 */
41
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: odcm.c,v 1.4 2014/03/27 18:22:56 christos Exp $");
44
45 #include <sys/param.h>
46 #include <sys/device.h>
47 #include <sys/module.h>
48 #include <sys/kmem.h>
49 #include <sys/sysctl.h>
50 #include <sys/xcall.h>
51
52 #include <x86/cpuvar.h>
53 #include <x86/cpu_msr.h>
54 #include <x86/specialreg.h>
55
56 #define ODCM_ENABLE (1 << 4) /* Enable bit 4 */
57 #define ODCM_REGOFFSET 1
58 #define ODCM_MAXSTATES 8
59
60 static struct {
61 int level;
62 int reg;
63 int errata;
64 } state[] = {
65 { .level = 7, .reg = 0, .errata = 0 },
66 { .level = 6, .reg = 7, .errata = 0 },
67 { .level = 5, .reg = 6, .errata = 0 },
68 { .level = 4, .reg = 5, .errata = 0 },
69 { .level = 3, .reg = 4, .errata = 0 },
70 { .level = 2, .reg = 3, .errata = 0 },
71 { .level = 1, .reg = 2, .errata = 0 },
72 { .level = 0, .reg = 1, .errata = 0 }
73 };
74
75 struct odcm_softc {
76 device_t sc_dev;
77 struct sysctllog *sc_log;
78 char *sc_names;
79 size_t sc_names_len;
80 int sc_level;
81 int sc_target;
82 int sc_current;
83 };
84
85 static int odcm_match(device_t, cfdata_t, void *);
86 static void odcm_attach(device_t, device_t, void *);
87 static int odcm_detach(device_t, int);
88 static void odcm_quirks(void);
89 static bool odcm_init(device_t);
90 static bool odcm_sysctl(device_t);
91 static int odcm_state_get(void);
92 static void odcm_state_set(int);
93 static int odcm_sysctl_helper(SYSCTLFN_ARGS);
94
95 CFATTACH_DECL_NEW(odcm, sizeof(struct odcm_softc),
96 odcm_match, odcm_attach, odcm_detach, NULL);
97
98 static int
odcm_match(device_t parent,cfdata_t cf,void * aux)99 odcm_match(device_t parent, cfdata_t cf, void *aux)
100 {
101 const uint32_t odcm = CPUID_ACPI | CPUID_TM;
102 struct cpufeature_attach_args *cfaa = aux;
103 uint32_t regs[4];
104
105 if (strcmp(cfaa->name, "frequency") != 0)
106 return 0;
107
108 if (cpuid_level < 1)
109 return 0;
110 else {
111 x86_cpuid(1, regs);
112
113 return ((regs[3] & odcm) != odcm) ? 0 : 1;
114 }
115 }
116
117 static void
odcm_attach(device_t parent,device_t self,void * aux)118 odcm_attach(device_t parent, device_t self, void *aux)
119 {
120 struct odcm_softc *sc = device_private(self);
121
122 sc->sc_dev = self;
123 sc->sc_log = NULL;
124 sc->sc_names = NULL;
125
126 odcm_quirks();
127
128 if (odcm_init(self) != true) {
129 aprint_normal(": failed to initialize\n");
130 return;
131 }
132
133 aprint_naive("\n");
134 aprint_normal(": on-demand clock modulation (state %s)\n",
135 sc->sc_level == (ODCM_MAXSTATES - 1) ? "disabled" : "enabled");
136
137 (void)pmf_device_register(self, NULL, NULL);
138 }
139
140 static int
odcm_detach(device_t self,int flags)141 odcm_detach(device_t self, int flags)
142 {
143 struct odcm_softc *sc = device_private(self);
144
145 /*
146 * Make sure the CPU operates with
147 * 100 % duty cycle after we are done.
148 */
149 odcm_state_set(7);
150
151 if (sc->sc_log != NULL)
152 sysctl_teardown(&sc->sc_log);
153
154 if (sc->sc_names != NULL)
155 kmem_free(sc->sc_names, sc->sc_names_len);
156
157 pmf_device_deregister(self);
158
159 return 0;
160 }
161
162 static void
odcm_quirks(void)163 odcm_quirks(void)
164 {
165 uint32_t regs[4];
166
167 x86_cpuid(1, regs);
168
169 switch (CPUID_TO_STEPPING(regs[0])) {
170
171 case 0x22: /* errata O50 P44 and Z21 */
172 case 0x24:
173 case 0x25:
174 case 0x27:
175 case 0x29:
176 /* hang with 12.5 */
177 state[__arraycount(state) - 1].errata = 1;
178 break;
179
180 case 0x07: /* errata N44 and P18 */
181 case 0x0a:
182 case 0x12:
183 case 0x13:
184 /* hang at 12.5 and 25 */
185 state[__arraycount(state) - 1].errata = 1;
186 state[__arraycount(state) - 2].errata = 1;
187 break;
188 }
189 }
190
191 static bool
odcm_init(device_t self)192 odcm_init(device_t self)
193 {
194 struct odcm_softc *sc = device_private(self);
195 size_t i, len;
196
197 sc->sc_names_len = state[0].level * (sizeof("9999 ") - 1) + 1;
198 sc->sc_names = kmem_zalloc(sc->sc_names_len, KM_SLEEP);
199
200 if (sc->sc_names == NULL)
201 return false;
202
203 for (i = len = 0; i < __arraycount(state); i++) {
204
205 if (state[i].errata)
206 continue;
207
208 len += snprintf(sc->sc_names + len,
209 sc->sc_names_len - len, "%d%s", state[i].level,
210 i < __arraycount(state) ? " " : "");
211 if (len > sc->sc_names_len)
212 break;
213 }
214
215 /*
216 * Get the current value and create
217 * sysctl machdep.clockmod subtree.
218 */
219 sc->sc_level = odcm_state_get();
220
221 return odcm_sysctl(self);
222 }
223
224 static bool
odcm_sysctl(device_t self)225 odcm_sysctl(device_t self)
226 {
227 struct odcm_softc *sc = device_private(self);
228 const struct sysctlnode *node, *odcmnode;
229 int rv;
230
231 rv = sysctl_createv(&sc->sc_log, 0, NULL, &node,
232 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
233 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
234
235 if (rv != 0)
236 goto fail;
237
238 rv = sysctl_createv(&sc->sc_log, 0, &node, &odcmnode,
239 0, CTLTYPE_NODE, "clockmod", NULL,
240 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
241
242 if (rv != 0)
243 goto fail;
244
245 rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
246 CTLFLAG_READWRITE, CTLTYPE_INT, "target",
247 SYSCTL_DESCR("target duty cycle (0 = lowest, 7 highest)"),
248 odcm_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
249
250 if (rv != 0)
251 goto fail;
252
253 sc->sc_target = node->sysctl_num;
254
255 rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
256 0, CTLTYPE_INT, "current",
257 SYSCTL_DESCR("current duty cycle"),
258 odcm_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
259
260 if (rv != 0)
261 goto fail;
262
263 sc->sc_current = node->sysctl_num;
264
265 rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
266 0, CTLTYPE_STRING, "available",
267 SYSCTL_DESCR("list of duty cycles available"),
268 NULL, 0, sc->sc_names, sc->sc_names_len,
269 CTL_CREATE, CTL_EOL);
270
271 if (rv != 0)
272 goto fail;
273
274 return true;
275
276 fail:
277 sysctl_teardown(&sc->sc_log);
278 sc->sc_log = NULL;
279
280 return false;
281 }
282
283 static int
odcm_sysctl_helper(SYSCTLFN_ARGS)284 odcm_sysctl_helper(SYSCTLFN_ARGS)
285 {
286 struct sysctlnode node;
287 struct odcm_softc *sc;
288 int level, old, err;
289 size_t i;
290
291 node = *rnode;
292 sc = node.sysctl_data;
293
294 level = old = 0;
295 node.sysctl_data = &level;
296
297 if (rnode->sysctl_num == sc->sc_target)
298 level = old = sc->sc_level;
299 else if (rnode->sysctl_num == sc->sc_current)
300 level = odcm_state_get();
301 else
302 return EOPNOTSUPP;
303
304 err = sysctl_lookup(SYSCTLFN_CALL(&node));
305
306 if (err || newp == NULL)
307 return err;
308
309 /*
310 * Check for an invalid level.
311 */
312 for (i = 0; i < __arraycount(state); i++) {
313
314 if (level == state[i].level && !state[i].errata)
315 break;
316 }
317
318 if (i == __arraycount(state))
319 return EINVAL;
320
321 if (rnode->sysctl_num == sc->sc_target && level != old) {
322 odcm_state_set(level);
323 sc->sc_level = level;
324 }
325
326 return 0;
327 }
328
329 static int
odcm_state_get(void)330 odcm_state_get(void)
331 {
332 uint64_t msr;
333 size_t i;
334 int val;
335
336 msr = rdmsr(MSR_THERM_CONTROL);
337
338 if ((msr & ODCM_ENABLE) == 0)
339 return (ODCM_MAXSTATES - 1);
340
341 msr = (msr >> ODCM_REGOFFSET) & (ODCM_MAXSTATES - 1);
342
343 for (val = -1, i = 0; i < __arraycount(state); i++) {
344
345 KASSERT(msr < INT_MAX);
346
347 if ((int)msr == state[i].reg) {
348 val = state[i].level;
349 break;
350 }
351 }
352
353 KASSERT(val != -1);
354
355 return val;
356 }
357
358 static void
odcm_state_set(int level)359 odcm_state_set(int level)
360 {
361 struct msr_rw_info msr;
362 uint64_t xc;
363 size_t i;
364
365 for (i = 0; i < __arraycount(state); i++) {
366
367 if (level == state[i].level && !state[i].errata)
368 break;
369 }
370
371 KASSERT(i != __arraycount(state));
372
373 msr.msr_read = true;
374 msr.msr_type = MSR_THERM_CONTROL;
375 msr.msr_mask = 0x1e;
376
377 if (state[i].reg != 0) /* bit 0 reserved */
378 msr.msr_value = (state[i].reg << ODCM_REGOFFSET) | ODCM_ENABLE;
379 else
380 msr.msr_value = 0; /* max state */
381
382 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
383 xc_wait(xc);
384 }
385
386 MODULE(MODULE_CLASS_DRIVER, odcm, NULL);
387
388 #ifdef _MODULE
389 #include "ioconf.c"
390 #endif
391
392 static int
odcm_modcmd(modcmd_t cmd,void * aux)393 odcm_modcmd(modcmd_t cmd, void *aux)
394 {
395 int error = 0;
396
397 switch (cmd) {
398 case MODULE_CMD_INIT:
399 #ifdef _MODULE
400 error = config_init_component(cfdriver_ioconf_odcm,
401 cfattach_ioconf_odcm, cfdata_ioconf_odcm);
402 #endif
403 return error;
404 case MODULE_CMD_FINI:
405 #ifdef _MODULE
406 error = config_fini_component(cfdriver_ioconf_odcm,
407 cfattach_ioconf_odcm, cfdata_ioconf_odcm);
408 #endif
409 return error;
410 default:
411 return ENOTTY;
412 }
413 }
414