xref: /freebsd/sys/dev/amdtemp/amdtemp.c (revision da3086df1863e9aed45eb14e265c306f8bb27d80)
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 #include <dev/amdsmn/amdsmn.h>
53 
54 typedef enum {
55 	CORE0_SENSOR0,
56 	CORE0_SENSOR1,
57 	CORE1_SENSOR0,
58 	CORE1_SENSOR1,
59 	CORE0,
60 	CORE1
61 } amdsensor_t;
62 
63 struct amdtemp_softc {
64 	int		sc_ncores;
65 	int		sc_ntemps;
66 	int		sc_flags;
67 #define	AMDTEMP_FLAG_CS_SWAP	0x01	/* ThermSenseCoreSel is inverted. */
68 #define	AMDTEMP_FLAG_CT_10BIT	0x02	/* CurTmp is 10-bit wide. */
69 #define	AMDTEMP_FLAG_ALT_OFFSET	0x04	/* CurTmp starts at -28C. */
70 	int32_t		sc_offset;
71 	int32_t		(*sc_gettemp)(device_t, amdsensor_t);
72 	struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
73 	struct intr_config_hook sc_ich;
74 	device_t	sc_smn;
75 };
76 
77 #define	VENDORID_AMD		0x1022
78 #define	DEVICEID_AMD_MISC0F	0x1103
79 #define	DEVICEID_AMD_MISC10	0x1203
80 #define	DEVICEID_AMD_MISC11	0x1303
81 #define	DEVICEID_AMD_MISC12	0x1403
82 #define	DEVICEID_AMD_MISC14	0x1703
83 #define	DEVICEID_AMD_MISC15	0x1603
84 #define	DEVICEID_AMD_MISC16	0x1533
85 #define	DEVICEID_AMD_MISC16_M30H	0x1583
86 #define	DEVICEID_AMD_MISC17	0x141d
87 #define	DEVICEID_AMD_HOSTB17H	0x1450
88 
89 static struct amdtemp_product {
90 	uint16_t	amdtemp_vendorid;
91 	uint16_t	amdtemp_deviceid;
92 } amdtemp_products[] = {
93 	{ VENDORID_AMD,	DEVICEID_AMD_MISC0F },
94 	{ VENDORID_AMD,	DEVICEID_AMD_MISC10 },
95 	{ VENDORID_AMD,	DEVICEID_AMD_MISC11 },
96 	{ VENDORID_AMD,	DEVICEID_AMD_MISC12 },
97 	{ VENDORID_AMD,	DEVICEID_AMD_MISC14 },
98 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15 },
99 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16 },
100 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16_M30H },
101 	{ VENDORID_AMD,	DEVICEID_AMD_MISC17 },
102 	{ VENDORID_AMD,	DEVICEID_AMD_HOSTB17H },
103 	{ 0, 0 }
104 };
105 
106 /*
107  * Reported Temperature Control Register
108  */
109 #define	AMDTEMP_REPTMP_CTRL	0xa4
110 
111 /*
112  * Reported Temperature, Family 17h
113  */
114 #define	AMDTEMP_17H_CUR_TMP	0x59800
115 
116 /*
117  * Thermaltrip Status Register (Family 0Fh only)
118  */
119 #define	AMDTEMP_THERMTP_STAT	0xe4
120 #define	AMDTEMP_TTSR_SELCORE	0x04
121 #define	AMDTEMP_TTSR_SELSENSOR	0x40
122 
123 /*
124  * DRAM Configuration High Register
125  */
126 #define	AMDTEMP_DRAM_CONF_HIGH	0x94	/* Function 2 */
127 #define	AMDTEMP_DRAM_MODE_DDR3	0x0100
128 
129 /*
130  * CPU Family/Model Register
131  */
132 #define	AMDTEMP_CPUID		0xfc
133 
134 /*
135  * Device methods.
136  */
137 static void 	amdtemp_identify(driver_t *driver, device_t parent);
138 static int	amdtemp_probe(device_t dev);
139 static int	amdtemp_attach(device_t dev);
140 static void	amdtemp_intrhook(void *arg);
141 static int	amdtemp_detach(device_t dev);
142 static int 	amdtemp_match(device_t dev);
143 static int32_t	amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
144 static int32_t	amdtemp_gettemp(device_t dev, amdsensor_t sensor);
145 static int32_t	amdtemp_gettemp17h(device_t dev, amdsensor_t sensor);
146 static int	amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
147 
148 static device_method_t amdtemp_methods[] = {
149 	/* Device interface */
150 	DEVMETHOD(device_identify,	amdtemp_identify),
151 	DEVMETHOD(device_probe,		amdtemp_probe),
152 	DEVMETHOD(device_attach,	amdtemp_attach),
153 	DEVMETHOD(device_detach,	amdtemp_detach),
154 
155 	DEVMETHOD_END
156 };
157 
158 static driver_t amdtemp_driver = {
159 	"amdtemp",
160 	amdtemp_methods,
161 	sizeof(struct amdtemp_softc),
162 };
163 
164 static devclass_t amdtemp_devclass;
165 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
166 MODULE_VERSION(amdtemp, 1);
167 MODULE_DEPEND(amdtemp, amdsmn, 1, 1, 1);
168 
169 static int
170 amdtemp_match(device_t dev)
171 {
172 	int i;
173 	uint16_t vendor, devid;
174 
175 	vendor = pci_get_vendor(dev);
176 	devid = pci_get_device(dev);
177 
178 	for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
179 		if (vendor == amdtemp_products[i].amdtemp_vendorid &&
180 		    devid == amdtemp_products[i].amdtemp_deviceid)
181 			return (1);
182 	}
183 
184 	return (0);
185 }
186 
187 static void
188 amdtemp_identify(driver_t *driver, device_t parent)
189 {
190 	device_t child;
191 
192 	/* Make sure we're not being doubly invoked. */
193 	if (device_find_child(parent, "amdtemp", -1) != NULL)
194 		return;
195 
196 	if (amdtemp_match(parent)) {
197 		child = device_add_child(parent, "amdtemp", -1);
198 		if (child == NULL)
199 			device_printf(parent, "add amdtemp child failed\n");
200 	}
201 }
202 
203 static int
204 amdtemp_probe(device_t dev)
205 {
206 	uint32_t family, model;
207 
208 	if (resource_disabled("amdtemp", 0))
209 		return (ENXIO);
210 	if (!amdtemp_match(device_get_parent(dev)))
211 		return (ENXIO);
212 
213 	family = CPUID_TO_FAMILY(cpu_id);
214 	model = CPUID_TO_MODEL(cpu_id);
215 
216 	switch (family) {
217 	case 0x0f:
218 		if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
219 		    (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
220 			return (ENXIO);
221 		break;
222 	case 0x10:
223 	case 0x11:
224 	case 0x12:
225 	case 0x14:
226 	case 0x15:
227 	case 0x16:
228 	case 0x17:
229 		break;
230 	default:
231 		return (ENXIO);
232 	}
233 	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
234 
235 	return (BUS_PROBE_GENERIC);
236 }
237 
238 static int
239 amdtemp_attach(device_t dev)
240 {
241 	char tn[32];
242 	u_int regs[4];
243 	struct amdtemp_softc *sc = device_get_softc(dev);
244 	struct sysctl_ctx_list *sysctlctx;
245 	struct sysctl_oid *sysctlnode;
246 	uint32_t cpuid, family, model;
247 	u_int bid;
248 	int erratum319, unit;
249 
250 	erratum319 = 0;
251 
252 	/*
253 	 * CPUID Register is available from Revision F.
254 	 */
255 	cpuid = cpu_id;
256 	family = CPUID_TO_FAMILY(cpuid);
257 	model = CPUID_TO_MODEL(cpuid);
258 	if ((family != 0x0f || model >= 0x40) && family != 0x17) {
259 		cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4);
260 		family = CPUID_TO_FAMILY(cpuid);
261 		model = CPUID_TO_MODEL(cpuid);
262 	}
263 
264 	switch (family) {
265 	case 0x0f:
266 		/*
267 		 * Thermaltrip Status Register
268 		 *
269 		 * - ThermSenseCoreSel
270 		 *
271 		 * Revision F & G:	0 - Core1, 1 - Core0
272 		 * Other:		0 - Core0, 1 - Core1
273 		 *
274 		 * - CurTmp
275 		 *
276 		 * Revision G:		bits 23-14
277 		 * Other:		bits 23-16
278 		 *
279 		 * XXX According to the BKDG, CurTmp, ThermSenseSel and
280 		 * ThermSenseCoreSel bits were introduced in Revision F
281 		 * but CurTmp seems working fine as early as Revision C.
282 		 * However, it is not clear whether ThermSenseSel and/or
283 		 * ThermSenseCoreSel work in undocumented cases as well.
284 		 * In fact, the Linux driver suggests it may not work but
285 		 * we just assume it does until we find otherwise.
286 		 *
287 		 * XXX According to Linux, CurTmp starts at -28C on
288 		 * Socket AM2 Revision G processors, which is not
289 		 * documented anywhere.
290 		 */
291 		if (model >= 0x40)
292 			sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
293 		if (model >= 0x60 && model != 0xc1) {
294 			do_cpuid(0x80000001, regs);
295 			bid = (regs[1] >> 9) & 0x1f;
296 			switch (model) {
297 			case 0x68: /* Socket S1g1 */
298 			case 0x6c:
299 			case 0x7c:
300 				break;
301 			case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
302 				if (bid != 0x0b && bid != 0x0c)
303 					sc->sc_flags |=
304 					    AMDTEMP_FLAG_ALT_OFFSET;
305 				break;
306 			case 0x6f: /* Socket AM2 and ASB1 (1 core) */
307 			case 0x7f:
308 				if (bid != 0x07 && bid != 0x09 &&
309 				    bid != 0x0c)
310 					sc->sc_flags |=
311 					    AMDTEMP_FLAG_ALT_OFFSET;
312 				break;
313 			default:
314 				sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET;
315 			}
316 			sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
317 		}
318 
319 		/*
320 		 * There are two sensors per core.
321 		 */
322 		sc->sc_ntemps = 2;
323 
324 		sc->sc_gettemp = amdtemp_gettemp0f;
325 		break;
326 	case 0x10:
327 		/*
328 		 * Erratum 319 Inaccurate Temperature Measurement
329 		 *
330 		 * http://support.amd.com/us/Processor_TechDocs/41322.pdf
331 		 */
332 		do_cpuid(0x80000001, regs);
333 		switch ((regs[1] >> 28) & 0xf) {
334 		case 0:	/* Socket F */
335 			erratum319 = 1;
336 			break;
337 		case 1:	/* Socket AM2+ or AM3 */
338 			if ((pci_cfgregread(pci_get_bus(dev),
339 			    pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) &
340 			    AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 ||
341 			    (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3))
342 				break;
343 			/* XXX 00100F42h (RB-C2) exists in both formats. */
344 			erratum319 = 1;
345 			break;
346 		}
347 		/* FALLTHROUGH */
348 	case 0x11:
349 	case 0x12:
350 	case 0x14:
351 	case 0x15:
352 	case 0x16:
353 		/*
354 		 * There is only one sensor per package.
355 		 */
356 		sc->sc_ntemps = 1;
357 
358 		sc->sc_gettemp = amdtemp_gettemp;
359 		break;
360 	case 0x17:
361 		sc->sc_ntemps = 1;
362 		sc->sc_gettemp = amdtemp_gettemp17h;
363 		sc->sc_smn = device_find_child(
364 		    device_get_parent(dev), "amdsmn", -1);
365 		if (sc->sc_smn == NULL) {
366 			if (bootverbose)
367 				device_printf(dev, "No SMN device found\n");
368 			return (ENXIO);
369 		}
370 		break;
371 	}
372 
373 	/* Find number of cores per package. */
374 	sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
375 	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
376 	if (sc->sc_ncores > MAXCPU)
377 		return (ENXIO);
378 
379 	if (erratum319)
380 		device_printf(dev,
381 		    "Erratum 319: temperature measurement may be inaccurate\n");
382 	if (bootverbose)
383 		device_printf(dev, "Found %d cores and %d sensors.\n",
384 		    sc->sc_ncores,
385 		    sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
386 
387 	/*
388 	 * dev.amdtemp.N tree.
389 	 */
390 	unit = device_get_unit(dev);
391 	snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit);
392 	TUNABLE_INT_FETCH(tn, &sc->sc_offset);
393 
394 	sysctlctx = device_get_sysctl_ctx(dev);
395 	SYSCTL_ADD_INT(sysctlctx,
396 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
397 	    "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0,
398 	    "Temperature sensor offset");
399 	sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
400 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
401 	    "core0", CTLFLAG_RD, 0, "Core 0");
402 
403 	SYSCTL_ADD_PROC(sysctlctx,
404 	    SYSCTL_CHILDREN(sysctlnode),
405 	    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
406 	    dev, CORE0_SENSOR0, amdtemp_sysctl, "IK",
407 	    "Core 0 / Sensor 0 temperature");
408 
409 	if (sc->sc_ntemps > 1) {
410 		SYSCTL_ADD_PROC(sysctlctx,
411 		    SYSCTL_CHILDREN(sysctlnode),
412 		    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
413 		    dev, CORE0_SENSOR1, amdtemp_sysctl, "IK",
414 		    "Core 0 / Sensor 1 temperature");
415 
416 		if (sc->sc_ncores > 1) {
417 			sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
418 			    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
419 			    OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1");
420 
421 			SYSCTL_ADD_PROC(sysctlctx,
422 			    SYSCTL_CHILDREN(sysctlnode),
423 			    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
424 			    dev, CORE1_SENSOR0, amdtemp_sysctl, "IK",
425 			    "Core 1 / Sensor 0 temperature");
426 
427 			SYSCTL_ADD_PROC(sysctlctx,
428 			    SYSCTL_CHILDREN(sysctlnode),
429 			    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
430 			    dev, CORE1_SENSOR1, amdtemp_sysctl, "IK",
431 			    "Core 1 / Sensor 1 temperature");
432 		}
433 	}
434 
435 	/*
436 	 * Try to create dev.cpu sysctl entries and setup intrhook function.
437 	 * This is needed because the cpu driver may be loaded late on boot,
438 	 * after us.
439 	 */
440 	amdtemp_intrhook(dev);
441 	sc->sc_ich.ich_func = amdtemp_intrhook;
442 	sc->sc_ich.ich_arg = dev;
443 	if (config_intrhook_establish(&sc->sc_ich) != 0) {
444 		device_printf(dev, "config_intrhook_establish failed!\n");
445 		return (ENXIO);
446 	}
447 
448 	return (0);
449 }
450 
451 void
452 amdtemp_intrhook(void *arg)
453 {
454 	struct amdtemp_softc *sc;
455 	struct sysctl_ctx_list *sysctlctx;
456 	device_t dev = (device_t)arg;
457 	device_t acpi, cpu, nexus;
458 	amdsensor_t sensor;
459 	int i;
460 
461 	sc = device_get_softc(dev);
462 
463 	/*
464 	 * dev.cpu.N.temperature.
465 	 */
466 	nexus = device_find_child(root_bus, "nexus", 0);
467 	acpi = device_find_child(nexus, "acpi", 0);
468 
469 	for (i = 0; i < sc->sc_ncores; i++) {
470 		if (sc->sc_sysctl_cpu[i] != NULL)
471 			continue;
472 		cpu = device_find_child(acpi, "cpu",
473 		    device_get_unit(dev) * sc->sc_ncores + i);
474 		if (cpu != NULL) {
475 			sysctlctx = device_get_sysctl_ctx(cpu);
476 
477 			sensor = sc->sc_ntemps > 1 ?
478 			    (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0;
479 			sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
480 			    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
481 			    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
482 			    dev, sensor, amdtemp_sysctl, "IK",
483 			    "Current temparature");
484 		}
485 	}
486 	if (sc->sc_ich.ich_arg != NULL)
487 		config_intrhook_disestablish(&sc->sc_ich);
488 }
489 
490 int
491 amdtemp_detach(device_t dev)
492 {
493 	struct amdtemp_softc *sc = device_get_softc(dev);
494 	int i;
495 
496 	for (i = 0; i < sc->sc_ncores; i++)
497 		if (sc->sc_sysctl_cpu[i] != NULL)
498 			sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
499 
500 	/* NewBus removes the dev.amdtemp.N tree by itself. */
501 
502 	return (0);
503 }
504 
505 static int
506 amdtemp_sysctl(SYSCTL_HANDLER_ARGS)
507 {
508 	device_t dev = (device_t)arg1;
509 	struct amdtemp_softc *sc = device_get_softc(dev);
510 	amdsensor_t sensor = (amdsensor_t)arg2;
511 	int32_t auxtemp[2], temp;
512 	int error;
513 
514 	switch (sensor) {
515 	case CORE0:
516 		auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0);
517 		auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1);
518 		temp = imax(auxtemp[0], auxtemp[1]);
519 		break;
520 	case CORE1:
521 		auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0);
522 		auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1);
523 		temp = imax(auxtemp[0], auxtemp[1]);
524 		break;
525 	default:
526 		temp = sc->sc_gettemp(dev, sensor);
527 		break;
528 	}
529 	error = sysctl_handle_int(oidp, &temp, 0, req);
530 
531 	return (error);
532 }
533 
534 #define	AMDTEMP_ZERO_C_TO_K	2731
535 
536 static int32_t
537 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
538 {
539 	struct amdtemp_softc *sc = device_get_softc(dev);
540 	uint32_t mask, offset, temp;
541 
542 	/* Set Sensor/Core selector. */
543 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
544 	temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR);
545 	switch (sensor) {
546 	case CORE0_SENSOR1:
547 		temp |= AMDTEMP_TTSR_SELSENSOR;
548 		/* FALLTHROUGH */
549 	case CORE0_SENSOR0:
550 	case CORE0:
551 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
552 			temp |= AMDTEMP_TTSR_SELCORE;
553 		break;
554 	case CORE1_SENSOR1:
555 		temp |= AMDTEMP_TTSR_SELSENSOR;
556 		/* FALLTHROUGH */
557 	case CORE1_SENSOR0:
558 	case CORE1:
559 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
560 			temp |= AMDTEMP_TTSR_SELCORE;
561 		break;
562 	}
563 	pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1);
564 
565 	mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
566 	offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49;
567 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
568 	temp = ((temp >> 14) & mask) * 5 / 2;
569 	temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10;
570 
571 	return (temp);
572 }
573 
574 static int32_t
575 amdtemp_gettemp(device_t dev, amdsensor_t sensor)
576 {
577 	struct amdtemp_softc *sc = device_get_softc(dev);
578 	uint32_t temp;
579 
580 	temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
581 	temp = ((temp >> 21) & 0x7ff) * 5 / 4;
582 	temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10;
583 
584 	return (temp);
585 }
586 
587 static int32_t
588 amdtemp_gettemp17h(device_t dev, amdsensor_t sensor)
589 {
590 	struct amdtemp_softc *sc = device_get_softc(dev);
591 	uint32_t temp;
592 	int error;
593 
594 	error = amdsmn_read(sc->sc_smn, AMDTEMP_17H_CUR_TMP, &temp);
595 	KASSERT(error == 0, ("amdsmn_read"));
596 
597 	temp = ((temp >> 21) & 0x7ff) * 5 / 4;
598 	temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10;
599 
600 	return (temp);
601 }
602