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