xref: /freebsd/sys/dev/amdtemp/amdtemp.c (revision 8ef24a0d4b28fe230e20637f56869cc4148cd2ca)
1 /*-
2  * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
3  * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
4  * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Driver for the AMD CPU on-die thermal sensors.
31  * Initially based on the k8temp Linux driver.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/conf.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/sysctl.h>
43 #include <sys/systm.h>
44 
45 #include <machine/cpufunc.h>
46 #include <machine/md_var.h>
47 #include <machine/specialreg.h>
48 
49 #include <dev/pci/pcivar.h>
50 #include <x86/pci_cfgreg.h>
51 
52 typedef enum {
53 	CORE0_SENSOR0,
54 	CORE0_SENSOR1,
55 	CORE1_SENSOR0,
56 	CORE1_SENSOR1,
57 	CORE0,
58 	CORE1
59 } amdsensor_t;
60 
61 struct amdtemp_softc {
62 	device_t	sc_dev;
63 	int		sc_ncores;
64 	int		sc_ntemps;
65 	int		sc_flags;
66 #define	AMDTEMP_FLAG_CS_SWAP	0x01	/* ThermSenseCoreSel is inverted. */
67 #define	AMDTEMP_FLAG_CT_10BIT	0x02	/* CurTmp is 10-bit wide. */
68 #define	AMDTEMP_FLAG_ALT_OFFSET	0x04	/* CurTmp starts at -28C. */
69 	int32_t		sc_offset;
70 	int32_t		(*sc_gettemp)(device_t, amdsensor_t);
71 	struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
72 	struct intr_config_hook sc_ich;
73 };
74 
75 #define	VENDORID_AMD		0x1022
76 #define	DEVICEID_AMD_MISC0F	0x1103
77 #define	DEVICEID_AMD_MISC10	0x1203
78 #define	DEVICEID_AMD_MISC11	0x1303
79 #define	DEVICEID_AMD_MISC12	0x1403
80 #define	DEVICEID_AMD_MISC14	0x1703
81 #define	DEVICEID_AMD_MISC15	0x1603
82 #define	DEVICEID_AMD_MISC16	0x1533
83 #define	DEVICEID_AMD_MISC16_M30H	0x1583
84 #define	DEVICEID_AMD_MISC17	0x141d
85 
86 static struct amdtemp_product {
87 	uint16_t	amdtemp_vendorid;
88 	uint16_t	amdtemp_deviceid;
89 } amdtemp_products[] = {
90 	{ VENDORID_AMD,	DEVICEID_AMD_MISC0F },
91 	{ VENDORID_AMD,	DEVICEID_AMD_MISC10 },
92 	{ VENDORID_AMD,	DEVICEID_AMD_MISC11 },
93 	{ VENDORID_AMD,	DEVICEID_AMD_MISC12 },
94 	{ VENDORID_AMD,	DEVICEID_AMD_MISC14 },
95 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15 },
96 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16 },
97 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16_M30H },
98 	{ VENDORID_AMD,	DEVICEID_AMD_MISC17 },
99 	{ 0, 0 }
100 };
101 
102 /*
103  * Reported Temperature Control Register
104  */
105 #define	AMDTEMP_REPTMP_CTRL	0xa4
106 
107 /*
108  * Thermaltrip Status Register (Family 0Fh only)
109  */
110 #define	AMDTEMP_THERMTP_STAT	0xe4
111 #define	AMDTEMP_TTSR_SELCORE	0x04
112 #define	AMDTEMP_TTSR_SELSENSOR	0x40
113 
114 /*
115  * DRAM Configuration High Register
116  */
117 #define	AMDTEMP_DRAM_CONF_HIGH	0x94	/* Function 2 */
118 #define	AMDTEMP_DRAM_MODE_DDR3	0x0100
119 
120 /*
121  * CPU Family/Model Register
122  */
123 #define	AMDTEMP_CPUID		0xfc
124 
125 /*
126  * Device methods.
127  */
128 static void 	amdtemp_identify(driver_t *driver, device_t parent);
129 static int	amdtemp_probe(device_t dev);
130 static int	amdtemp_attach(device_t dev);
131 static void	amdtemp_intrhook(void *arg);
132 static int	amdtemp_detach(device_t dev);
133 static int 	amdtemp_match(device_t dev);
134 static int32_t	amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
135 static int32_t	amdtemp_gettemp(device_t dev, amdsensor_t sensor);
136 static int	amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
137 
138 static device_method_t amdtemp_methods[] = {
139 	/* Device interface */
140 	DEVMETHOD(device_identify,	amdtemp_identify),
141 	DEVMETHOD(device_probe,		amdtemp_probe),
142 	DEVMETHOD(device_attach,	amdtemp_attach),
143 	DEVMETHOD(device_detach,	amdtemp_detach),
144 
145 	DEVMETHOD_END
146 };
147 
148 static driver_t amdtemp_driver = {
149 	"amdtemp",
150 	amdtemp_methods,
151 	sizeof(struct amdtemp_softc),
152 };
153 
154 static devclass_t amdtemp_devclass;
155 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
156 
157 static int
158 amdtemp_match(device_t dev)
159 {
160 	int i;
161 	uint16_t vendor, devid;
162 
163 	vendor = pci_get_vendor(dev);
164 	devid = pci_get_device(dev);
165 
166 	for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
167 		if (vendor == amdtemp_products[i].amdtemp_vendorid &&
168 		    devid == amdtemp_products[i].amdtemp_deviceid)
169 			return (1);
170 	}
171 
172 	return (0);
173 }
174 
175 static void
176 amdtemp_identify(driver_t *driver, device_t parent)
177 {
178 	device_t child;
179 
180 	/* Make sure we're not being doubly invoked. */
181 	if (device_find_child(parent, "amdtemp", -1) != NULL)
182 		return;
183 
184 	if (amdtemp_match(parent)) {
185 		child = device_add_child(parent, "amdtemp", -1);
186 		if (child == NULL)
187 			device_printf(parent, "add amdtemp child failed\n");
188 	}
189 }
190 
191 static int
192 amdtemp_probe(device_t dev)
193 {
194 	uint32_t family, model;
195 
196 	if (resource_disabled("amdtemp", 0))
197 		return (ENXIO);
198 
199 	family = CPUID_TO_FAMILY(cpu_id);
200 	model = CPUID_TO_MODEL(cpu_id);
201 
202 	switch (family) {
203 	case 0x0f:
204 		if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
205 		    (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
206 			return (ENXIO);
207 		break;
208 	case 0x10:
209 	case 0x11:
210 	case 0x12:
211 	case 0x14:
212 	case 0x15:
213 	case 0x16:
214 		break;
215 	default:
216 		return (ENXIO);
217 	}
218 	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
219 
220 	return (BUS_PROBE_GENERIC);
221 }
222 
223 static int
224 amdtemp_attach(device_t dev)
225 {
226 	char tn[32];
227 	u_int regs[4];
228 	struct amdtemp_softc *sc = device_get_softc(dev);
229 	struct sysctl_ctx_list *sysctlctx;
230 	struct sysctl_oid *sysctlnode;
231 	uint32_t cpuid, family, model;
232 	u_int bid;
233 	int erratum319, unit;
234 
235 	erratum319 = 0;
236 
237 	/*
238 	 * CPUID Register is available from Revision F.
239 	 */
240 	cpuid = cpu_id;
241 	family = CPUID_TO_FAMILY(cpuid);
242 	model = CPUID_TO_MODEL(cpuid);
243 	if (family != 0x0f || model >= 0x40) {
244 		cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4);
245 		family = CPUID_TO_FAMILY(cpuid);
246 		model = CPUID_TO_MODEL(cpuid);
247 	}
248 
249 	switch (family) {
250 	case 0x0f:
251 		/*
252 		 * Thermaltrip Status Register
253 		 *
254 		 * - ThermSenseCoreSel
255 		 *
256 		 * Revision F & G:	0 - Core1, 1 - Core0
257 		 * Other:		0 - Core0, 1 - Core1
258 		 *
259 		 * - CurTmp
260 		 *
261 		 * Revision G:		bits 23-14
262 		 * Other:		bits 23-16
263 		 *
264 		 * XXX According to the BKDG, CurTmp, ThermSenseSel and
265 		 * ThermSenseCoreSel bits were introduced in Revision F
266 		 * but CurTmp seems working fine as early as Revision C.
267 		 * However, it is not clear whether ThermSenseSel and/or
268 		 * ThermSenseCoreSel work in undocumented cases as well.
269 		 * In fact, the Linux driver suggests it may not work but
270 		 * we just assume it does until we find otherwise.
271 		 *
272 		 * XXX According to Linux, CurTmp starts at -28C on
273 		 * Socket AM2 Revision G processors, which is not
274 		 * documented anywhere.
275 		 */
276 		if (model >= 0x40)
277 			sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
278 		if (model >= 0x60 && model != 0xc1) {
279 			do_cpuid(0x80000001, regs);
280 			bid = (regs[1] >> 9) & 0x1f;
281 			switch (model) {
282 			case 0x68: /* Socket S1g1 */
283 			case 0x6c:
284 			case 0x7c:
285 				break;
286 			case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
287 				if (bid != 0x0b && bid != 0x0c)
288 					sc->sc_flags |=
289 					    AMDTEMP_FLAG_ALT_OFFSET;
290 				break;
291 			case 0x6f: /* Socket AM2 and ASB1 (1 core) */
292 			case 0x7f:
293 				if (bid != 0x07 && bid != 0x09 &&
294 				    bid != 0x0c)
295 					sc->sc_flags |=
296 					    AMDTEMP_FLAG_ALT_OFFSET;
297 				break;
298 			default:
299 				sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET;
300 			}
301 			sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
302 		}
303 
304 		/*
305 		 * There are two sensors per core.
306 		 */
307 		sc->sc_ntemps = 2;
308 
309 		sc->sc_gettemp = amdtemp_gettemp0f;
310 		break;
311 	case 0x10:
312 		/*
313 		 * Erratum 319 Inaccurate Temperature Measurement
314 		 *
315 		 * http://support.amd.com/us/Processor_TechDocs/41322.pdf
316 		 */
317 		do_cpuid(0x80000001, regs);
318 		switch ((regs[1] >> 28) & 0xf) {
319 		case 0:	/* Socket F */
320 			erratum319 = 1;
321 			break;
322 		case 1:	/* Socket AM2+ or AM3 */
323 			if ((pci_cfgregread(pci_get_bus(dev),
324 			    pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) &
325 			    AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 ||
326 			    (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3))
327 				break;
328 			/* XXX 00100F42h (RB-C2) exists in both formats. */
329 			erratum319 = 1;
330 			break;
331 		}
332 		/* FALLTHROUGH */
333 	case 0x11:
334 	case 0x12:
335 	case 0x14:
336 	case 0x15:
337 	case 0x16:
338 		/*
339 		 * There is only one sensor per package.
340 		 */
341 		sc->sc_ntemps = 1;
342 
343 		sc->sc_gettemp = amdtemp_gettemp;
344 		break;
345 	}
346 
347 	/* Find number of cores per package. */
348 	sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
349 	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
350 	if (sc->sc_ncores > MAXCPU)
351 		return (ENXIO);
352 
353 	if (erratum319)
354 		device_printf(dev,
355 		    "Erratum 319: temperature measurement may be inaccurate\n");
356 	if (bootverbose)
357 		device_printf(dev, "Found %d cores and %d sensors.\n",
358 		    sc->sc_ncores,
359 		    sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
360 
361 	/*
362 	 * dev.amdtemp.N tree.
363 	 */
364 	unit = device_get_unit(dev);
365 	snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit);
366 	TUNABLE_INT_FETCH(tn, &sc->sc_offset);
367 
368 	sysctlctx = device_get_sysctl_ctx(dev);
369 	SYSCTL_ADD_INT(sysctlctx,
370 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
371 	    "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0,
372 	    "Temperature sensor offset");
373 	sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
374 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
375 	    "core0", CTLFLAG_RD, 0, "Core 0");
376 
377 	SYSCTL_ADD_PROC(sysctlctx,
378 	    SYSCTL_CHILDREN(sysctlnode),
379 	    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
380 	    dev, CORE0_SENSOR0, amdtemp_sysctl, "IK",
381 	    "Core 0 / Sensor 0 temperature");
382 
383 	if (sc->sc_ntemps > 1) {
384 		SYSCTL_ADD_PROC(sysctlctx,
385 		    SYSCTL_CHILDREN(sysctlnode),
386 		    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
387 		    dev, CORE0_SENSOR1, amdtemp_sysctl, "IK",
388 		    "Core 0 / Sensor 1 temperature");
389 
390 		if (sc->sc_ncores > 1) {
391 			sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
392 			    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
393 			    OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1");
394 
395 			SYSCTL_ADD_PROC(sysctlctx,
396 			    SYSCTL_CHILDREN(sysctlnode),
397 			    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
398 			    dev, CORE1_SENSOR0, amdtemp_sysctl, "IK",
399 			    "Core 1 / Sensor 0 temperature");
400 
401 			SYSCTL_ADD_PROC(sysctlctx,
402 			    SYSCTL_CHILDREN(sysctlnode),
403 			    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
404 			    dev, CORE1_SENSOR1, amdtemp_sysctl, "IK",
405 			    "Core 1 / Sensor 1 temperature");
406 		}
407 	}
408 
409 	/*
410 	 * Try to create dev.cpu sysctl entries and setup intrhook function.
411 	 * This is needed because the cpu driver may be loaded late on boot,
412 	 * after us.
413 	 */
414 	amdtemp_intrhook(dev);
415 	sc->sc_ich.ich_func = amdtemp_intrhook;
416 	sc->sc_ich.ich_arg = dev;
417 	if (config_intrhook_establish(&sc->sc_ich) != 0) {
418 		device_printf(dev, "config_intrhook_establish failed!\n");
419 		return (ENXIO);
420 	}
421 
422 	return (0);
423 }
424 
425 void
426 amdtemp_intrhook(void *arg)
427 {
428 	struct amdtemp_softc *sc;
429 	struct sysctl_ctx_list *sysctlctx;
430 	device_t dev = (device_t)arg;
431 	device_t acpi, cpu, nexus;
432 	amdsensor_t sensor;
433 	int i;
434 
435 	sc = device_get_softc(dev);
436 
437 	/*
438 	 * dev.cpu.N.temperature.
439 	 */
440 	nexus = device_find_child(root_bus, "nexus", 0);
441 	acpi = device_find_child(nexus, "acpi", 0);
442 
443 	for (i = 0; i < sc->sc_ncores; i++) {
444 		if (sc->sc_sysctl_cpu[i] != NULL)
445 			continue;
446 		cpu = device_find_child(acpi, "cpu",
447 		    device_get_unit(dev) * sc->sc_ncores + i);
448 		if (cpu != NULL) {
449 			sysctlctx = device_get_sysctl_ctx(cpu);
450 
451 			sensor = sc->sc_ntemps > 1 ?
452 			    (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0;
453 			sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
454 			    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
455 			    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
456 			    dev, sensor, amdtemp_sysctl, "IK",
457 			    "Current temparature");
458 		}
459 	}
460 	if (sc->sc_ich.ich_arg != NULL)
461 		config_intrhook_disestablish(&sc->sc_ich);
462 }
463 
464 int
465 amdtemp_detach(device_t dev)
466 {
467 	struct amdtemp_softc *sc = device_get_softc(dev);
468 	int i;
469 
470 	for (i = 0; i < sc->sc_ncores; i++)
471 		if (sc->sc_sysctl_cpu[i] != NULL)
472 			sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
473 
474 	/* NewBus removes the dev.amdtemp.N tree by itself. */
475 
476 	return (0);
477 }
478 
479 static int
480 amdtemp_sysctl(SYSCTL_HANDLER_ARGS)
481 {
482 	device_t dev = (device_t)arg1;
483 	struct amdtemp_softc *sc = device_get_softc(dev);
484 	amdsensor_t sensor = (amdsensor_t)arg2;
485 	int32_t auxtemp[2], temp;
486 	int error;
487 
488 	switch (sensor) {
489 	case CORE0:
490 		auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0);
491 		auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1);
492 		temp = imax(auxtemp[0], auxtemp[1]);
493 		break;
494 	case CORE1:
495 		auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0);
496 		auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1);
497 		temp = imax(auxtemp[0], auxtemp[1]);
498 		break;
499 	default:
500 		temp = sc->sc_gettemp(dev, sensor);
501 		break;
502 	}
503 	error = sysctl_handle_int(oidp, &temp, 0, req);
504 
505 	return (error);
506 }
507 
508 #define	AMDTEMP_ZERO_C_TO_K	2732
509 
510 static int32_t
511 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
512 {
513 	struct amdtemp_softc *sc = device_get_softc(dev);
514 	uint32_t mask, offset, temp;
515 
516 	/* Set Sensor/Core selector. */
517 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
518 	temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR);
519 	switch (sensor) {
520 	case CORE0_SENSOR1:
521 		temp |= AMDTEMP_TTSR_SELSENSOR;
522 		/* FALLTHROUGH */
523 	case CORE0_SENSOR0:
524 	case CORE0:
525 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
526 			temp |= AMDTEMP_TTSR_SELCORE;
527 		break;
528 	case CORE1_SENSOR1:
529 		temp |= AMDTEMP_TTSR_SELSENSOR;
530 		/* FALLTHROUGH */
531 	case CORE1_SENSOR0:
532 	case CORE1:
533 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
534 			temp |= AMDTEMP_TTSR_SELCORE;
535 		break;
536 	}
537 	pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1);
538 
539 	mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
540 	offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49;
541 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
542 	temp = ((temp >> 14) & mask) * 5 / 2;
543 	temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10;
544 
545 	return (temp);
546 }
547 
548 static int32_t
549 amdtemp_gettemp(device_t dev, amdsensor_t sensor)
550 {
551 	struct amdtemp_softc *sc = device_get_softc(dev);
552 	uint32_t temp;
553 
554 	temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
555 	temp = ((temp >> 21) & 0x7ff) * 5 / 4;
556 	temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10;
557 
558 	return (temp);
559 }
560