Home | History | Annotate | Line # | Download | only in x86
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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