xref: /netbsd/sys/arch/x86/x86/odcm.c (revision d65a6a67)
1 /*	$NetBSD: odcm.c,v 1.5 2017/06/01 02:45:08 chs 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.5 2017/06/01 02:45:08 chs 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 	for (i = len = 0; i < __arraycount(state); i++) {
201 
202 		if (state[i].errata)
203 			continue;
204 
205 		len += snprintf(sc->sc_names + len,
206 		    sc->sc_names_len - len, "%d%s", state[i].level,
207 		    i < __arraycount(state) ? " " : "");
208 		if (len > sc->sc_names_len)
209 			break;
210 	}
211 
212 	/*
213 	 * Get the current value and create
214 	 * sysctl machdep.clockmod subtree.
215 	 */
216 	sc->sc_level = odcm_state_get();
217 
218 	return odcm_sysctl(self);
219 }
220 
221 static bool
odcm_sysctl(device_t self)222 odcm_sysctl(device_t self)
223 {
224 	struct odcm_softc *sc = device_private(self);
225 	const struct sysctlnode *node, *odcmnode;
226 	int rv;
227 
228 	rv = sysctl_createv(&sc->sc_log, 0, NULL, &node,
229 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
230 	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
231 
232 	if (rv != 0)
233 		goto fail;
234 
235 	rv = sysctl_createv(&sc->sc_log, 0, &node, &odcmnode,
236 	    0, CTLTYPE_NODE, "clockmod", NULL,
237 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
238 
239 	if (rv != 0)
240 		goto fail;
241 
242 	rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
243 	    CTLFLAG_READWRITE, CTLTYPE_INT, "target",
244 	    SYSCTL_DESCR("target duty cycle (0 = lowest, 7 highest)"),
245 	    odcm_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
246 
247 	if (rv != 0)
248 		goto fail;
249 
250 	sc->sc_target = node->sysctl_num;
251 
252 	rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
253 	    0, CTLTYPE_INT, "current",
254 	    SYSCTL_DESCR("current duty cycle"),
255 	    odcm_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
256 
257 	if (rv != 0)
258 		goto fail;
259 
260 	sc->sc_current = node->sysctl_num;
261 
262 	rv = sysctl_createv(&sc->sc_log, 0, &odcmnode, &node,
263 	    0, CTLTYPE_STRING, "available",
264 	    SYSCTL_DESCR("list of duty cycles available"),
265 	    NULL, 0, sc->sc_names, sc->sc_names_len,
266 	    CTL_CREATE, CTL_EOL);
267 
268 	if (rv != 0)
269 		goto fail;
270 
271 	return true;
272 
273 fail:
274 	sysctl_teardown(&sc->sc_log);
275 	sc->sc_log = NULL;
276 
277 	return false;
278 }
279 
280 static int
odcm_sysctl_helper(SYSCTLFN_ARGS)281 odcm_sysctl_helper(SYSCTLFN_ARGS)
282 {
283 	struct sysctlnode node;
284 	struct odcm_softc *sc;
285 	int level, old, err;
286 	size_t i;
287 
288 	node = *rnode;
289 	sc = node.sysctl_data;
290 
291 	level = old = 0;
292 	node.sysctl_data = &level;
293 
294 	if (rnode->sysctl_num == sc->sc_target)
295 		level = old = sc->sc_level;
296 	else if (rnode->sysctl_num == sc->sc_current)
297 		level = odcm_state_get();
298 	else
299 		return EOPNOTSUPP;
300 
301 	err = sysctl_lookup(SYSCTLFN_CALL(&node));
302 
303 	if (err || newp == NULL)
304 		return err;
305 
306 	/*
307 	 * Check for an invalid level.
308 	 */
309 	for (i = 0; i < __arraycount(state); i++) {
310 
311 		if (level == state[i].level && !state[i].errata)
312 			break;
313 	}
314 
315 	if (i == __arraycount(state))
316 		return EINVAL;
317 
318 	if (rnode->sysctl_num == sc->sc_target && level != old) {
319 		odcm_state_set(level);
320 		sc->sc_level = level;
321 	}
322 
323 	return 0;
324 }
325 
326 static int
odcm_state_get(void)327 odcm_state_get(void)
328 {
329 	uint64_t msr;
330 	size_t i;
331 	int val;
332 
333 	msr = rdmsr(MSR_THERM_CONTROL);
334 
335 	if ((msr & ODCM_ENABLE) == 0)
336 		return (ODCM_MAXSTATES - 1);
337 
338 	msr = (msr >> ODCM_REGOFFSET) & (ODCM_MAXSTATES - 1);
339 
340 	for (val = -1, i = 0; i < __arraycount(state); i++) {
341 
342 		KASSERT(msr < INT_MAX);
343 
344 		if ((int)msr == state[i].reg) {
345 			val = state[i].level;
346 			break;
347 		}
348 	}
349 
350 	KASSERT(val != -1);
351 
352 	return val;
353 }
354 
355 static void
odcm_state_set(int level)356 odcm_state_set(int level)
357 {
358 	struct msr_rw_info msr;
359 	uint64_t xc;
360 	size_t i;
361 
362 	for (i = 0; i < __arraycount(state); i++) {
363 
364 		if (level == state[i].level && !state[i].errata)
365 			break;
366 	}
367 
368 	KASSERT(i != __arraycount(state));
369 
370 	msr.msr_read = true;
371 	msr.msr_type = MSR_THERM_CONTROL;
372 	msr.msr_mask = 0x1e;
373 
374 	if (state[i].reg != 0)	/* bit 0 reserved */
375 		msr.msr_value = (state[i].reg << ODCM_REGOFFSET) | ODCM_ENABLE;
376 	else
377 		msr.msr_value = 0; /* max state */
378 
379 	xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
380 	xc_wait(xc);
381 }
382 
383 MODULE(MODULE_CLASS_DRIVER, odcm, NULL);
384 
385 #ifdef _MODULE
386 #include "ioconf.c"
387 #endif
388 
389 static int
odcm_modcmd(modcmd_t cmd,void * aux)390 odcm_modcmd(modcmd_t cmd, void *aux)
391 {
392 	int error = 0;
393 
394 	switch (cmd) {
395 	case MODULE_CMD_INIT:
396 #ifdef _MODULE
397 		error = config_init_component(cfdriver_ioconf_odcm,
398 		    cfattach_ioconf_odcm, cfdata_ioconf_odcm);
399 #endif
400 		return error;
401 	case MODULE_CMD_FINI:
402 #ifdef _MODULE
403 		error = config_fini_component(cfdriver_ioconf_odcm,
404 		    cfattach_ioconf_odcm, cfdata_ioconf_odcm);
405 #endif
406 		return error;
407 	default:
408 		return ENOTTY;
409 	}
410 }
411