xref: /dragonfly/sys/dev/powermng/amdtemp/amdtemp.c (revision 23be8282)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
5  * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
6  * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org>
7  * All rights reserved.
8  * Copyright (c) 2017-2020 Conrad Meyer <cem@FreeBSD.org>. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD: head/sys/dev/amdtemp/amdtemp.c 361011 2020-05-13 18:07:37Z kevans $
32  */
33 
34 /*
35  * Driver for the AMD CPU on-die thermal sensors.
36  * Initially based on the k8temp Linux driver.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/sysctl.h>
45 #include <sys/systm.h>
46 
47 #include <machine/cpufunc.h>
48 #include <machine/md_var.h>
49 #include <machine/specialreg.h>
50 
51 #include <bus/pci/pcivar.h>
52 #include <bus/pci/pci_cfgreg.h>
53 
54 #include <dev/powermng/amdsmn/amdsmn.h>
55 
56 typedef enum {
57 	CORE0_SENSOR0,
58 	CORE0_SENSOR1,
59 	CORE1_SENSOR0,
60 	CORE1_SENSOR1,
61 	CORE0,
62 	CORE1,
63 	CCD1,
64 	CCD_BASE = CCD1,
65 	CCD2,
66 	CCD3,
67 	CCD4,
68 	CCD5,
69 	CCD6,
70 	CCD7,
71 	CCD8,
72 	CCD_MAX = CCD8,
73 	NUM_CCDS = CCD_MAX - CCD_BASE + 1,
74 } amdsensor_t;
75 
76 struct amdtemp_softc {
77 	int		sc_ncores;
78 	int		sc_ntemps;
79 	int		sc_flags;
80 #define	AMDTEMP_FLAG_CS_SWAP	0x01	/* ThermSenseCoreSel is inverted. */
81 #define	AMDTEMP_FLAG_CT_10BIT	0x02	/* CurTmp is 10-bit wide. */
82 #define	AMDTEMP_FLAG_ALT_OFFSET	0x04	/* CurTmp starts at -28C. */
83 	int32_t		sc_offset;
84 	int32_t		(*sc_gettemp)(device_t, amdsensor_t);
85 	struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
86 	struct intr_config_hook sc_ich;
87 	device_t	sc_smn;
88 };
89 
90 /*
91  * N.B. The numbers in macro names below are significant and represent CPU
92  * family and model numbers.  Do not make up fictitious family or model numbers
93  * when adding support for new devices.
94  */
95 #define	VENDORID_AMD		0x1022
96 #define	DEVICEID_AMD_MISC0F	0x1103
97 #define	DEVICEID_AMD_MISC10	0x1203
98 #define	DEVICEID_AMD_MISC11	0x1303
99 #define	DEVICEID_AMD_MISC14	0x1703
100 #define	DEVICEID_AMD_MISC15	0x1603
101 #define	DEVICEID_AMD_MISC15_M10H	0x1403
102 #define	DEVICEID_AMD_MISC15_M30H	0x141d
103 #define	DEVICEID_AMD_MISC15_M60H_ROOT	0x1576
104 #define	DEVICEID_AMD_MISC16	0x1533
105 #define	DEVICEID_AMD_MISC16_M30H	0x1583
106 #define	DEVICEID_AMD_HOSTB17H_ROOT	0x1450
107 #define	DEVICEID_AMD_HOSTB17H_M10H_ROOT	0x15d0
108 #define	DEVICEID_AMD_HOSTB17H_M30H_ROOT	0x1480	/* Also M70h. */
109 
110 static const struct amdtemp_product {
111 	uint16_t	amdtemp_vendorid;
112 	uint16_t	amdtemp_deviceid;
113 	/*
114 	 * 0xFC register is only valid on the D18F3 PCI device; SMN temp
115 	 * drivers do not attach to that device.
116 	 */
117 	bool		amdtemp_has_cpuid;
118 } amdtemp_products[] = {
119 	{ VENDORID_AMD,	DEVICEID_AMD_MISC0F, true },
120 	{ VENDORID_AMD,	DEVICEID_AMD_MISC10, true },
121 	{ VENDORID_AMD,	DEVICEID_AMD_MISC11, true },
122 	{ VENDORID_AMD,	DEVICEID_AMD_MISC14, true },
123 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15, true },
124 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15_M10H, true },
125 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15_M30H, true },
126 	{ VENDORID_AMD,	DEVICEID_AMD_MISC15_M60H_ROOT, false },
127 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16, true },
128 	{ VENDORID_AMD,	DEVICEID_AMD_MISC16_M30H, true },
129 	{ VENDORID_AMD,	DEVICEID_AMD_HOSTB17H_ROOT, false },
130 	{ VENDORID_AMD,	DEVICEID_AMD_HOSTB17H_M10H_ROOT, false },
131 	{ VENDORID_AMD,	DEVICEID_AMD_HOSTB17H_M30H_ROOT, false },
132 };
133 
134 /*
135  * Reported Temperature Control Register, family 0Fh-15h (some models), 16h.
136  */
137 #define	AMDTEMP_REPTMP_CTRL	0xa4
138 
139 #define	AMDTEMP_REPTMP10H_CURTMP_MASK	0x7ff
140 #define	AMDTEMP_REPTMP10H_CURTMP_SHIFT	21
141 #define	AMDTEMP_REPTMP10H_TJSEL_MASK	0x3
142 #define	AMDTEMP_REPTMP10H_TJSEL_SHIFT	16
143 
144 /*
145  * Reported Temperature, Family 15h, M60+
146  *
147  * Same register bit definitions as other Family 15h CPUs, but access is
148  * indirect via SMN, like Family 17h.
149  */
150 #define	AMDTEMP_15H_M60H_REPTMP_CTRL	0xd8200ca4
151 
152 /*
153  * Reported Temperature, Family 17h
154  *
155  * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register
156  * provide the current temp.  bit 19, when clear, means the temp is reported in
157  * a range 0.."225C" (probable typo for 255C), and when set changes the range
158  * to -49..206C.
159  */
160 #define	AMDTEMP_17H_CUR_TMP		0x59800
161 #define	AMDTEMP_17H_CUR_TMP_RANGE_SEL	(1u << 19)
162 /*
163  * The following register set was discovered experimentally by Ondrej Čerman
164  * and collaborators, but is not (yet) documented in a PPR/OSRR (other than
165  * the M70H PPR SMN memory map showing [0x59800, +0x314] as allocated to
166  * SMU::THM).  It seems plausible and the Linux sensor folks have adopted it.
167  */
168 #define	AMDTEMP_17H_CCD_TMP_BASE	0x59954
169 #define	AMDTEMP_17H_CCD_TMP_VALID	(1u << 11)
170 
171 /*
172  * AMD temperature range adjustment, in deciKelvins (i.e., 49.0 Celsius).
173  */
174 #define	AMDTEMP_CURTMP_RANGE_ADJUST	490
175 
176 /*
177  * Thermaltrip Status Register (Family 0Fh only)
178  */
179 #define	AMDTEMP_THERMTP_STAT	0xe4
180 #define	AMDTEMP_TTSR_SELCORE	0x04
181 #define	AMDTEMP_TTSR_SELSENSOR	0x40
182 
183 /*
184  * DRAM Configuration High Register
185  */
186 #define	AMDTEMP_DRAM_CONF_HIGH	0x94	/* Function 2 */
187 #define	AMDTEMP_DRAM_MODE_DDR3	0x0100
188 
189 /*
190  * CPU Family/Model Register
191  */
192 #define	AMDTEMP_CPUID		0xfc
193 
194 /*
195  * Device methods.
196  */
197 static void 	amdtemp_identify(driver_t *driver, device_t parent);
198 static int	amdtemp_probe(device_t dev);
199 static int	amdtemp_attach(device_t dev);
200 static void	amdtemp_intrhook(void *arg);
201 static int	amdtemp_detach(device_t dev);
202 static int32_t	amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
203 static int32_t	amdtemp_gettemp(device_t dev, amdsensor_t sensor);
204 static int32_t	amdtemp_gettemp15hm60h(device_t dev, amdsensor_t sensor);
205 static int32_t	amdtemp_gettemp17h(device_t dev, amdsensor_t sensor);
206 static void	amdtemp_probe_ccd_sensors17h(device_t dev, uint32_t model);
207 static int	amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
208 
209 static device_method_t amdtemp_methods[] = {
210 	/* Device interface */
211 	DEVMETHOD(device_identify,	amdtemp_identify),
212 	DEVMETHOD(device_probe,		amdtemp_probe),
213 	DEVMETHOD(device_attach,	amdtemp_attach),
214 	DEVMETHOD(device_detach,	amdtemp_detach),
215 
216 	DEVMETHOD_END
217 };
218 
219 static driver_t amdtemp_driver = {
220 	"amdtemp",
221 	amdtemp_methods,
222 	sizeof(struct amdtemp_softc),
223 };
224 
225 static devclass_t amdtemp_devclass;
226 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
227 MODULE_VERSION(amdtemp, 1);
228 MODULE_DEPEND(amdtemp, amdsmn, 1, 1, 1);
229 #if !defined(__DragonFly__)
230 MODULE_PNP_INFO("U16:vendor;U16:device", pci, amdtemp, amdtemp_products,
231     nitems(amdtemp_products));
232 #endif
233 
234 static bool
235 amdtemp_match(device_t dev, const struct amdtemp_product **product_out)
236 {
237 	int i;
238 	uint16_t vendor, devid;
239 
240 	vendor = pci_get_vendor(dev);
241 	devid = pci_get_device(dev);
242 
243 	for (i = 0; i < nitems(amdtemp_products); i++) {
244 		if (vendor == amdtemp_products[i].amdtemp_vendorid &&
245 		    devid == amdtemp_products[i].amdtemp_deviceid) {
246 			if (product_out != NULL)
247 				*product_out = &amdtemp_products[i];
248 			return (true);
249 		}
250 	}
251 	return (false);
252 }
253 
254 static void
255 amdtemp_identify(driver_t *driver, device_t parent)
256 {
257 	device_t child;
258 
259 	/* Make sure we're not being doubly invoked. */
260 	if (device_find_child(parent, "amdtemp", -1) != NULL)
261 		return;
262 
263 	if (amdtemp_match(parent, NULL)) {
264 		child = device_add_child(parent, "amdtemp", -1);
265 		if (child == NULL)
266 			device_printf(parent, "add amdtemp child failed\n");
267 	}
268 }
269 
270 static int
271 amdtemp_probe(device_t dev)
272 {
273 	uint32_t family, model;
274 
275 	if (resource_disabled("amdtemp", 0))
276 		return (ENXIO);
277 	if (!amdtemp_match(device_get_parent(dev), NULL))
278 		return (ENXIO);
279 
280 	family = CPUID_TO_FAMILY(cpu_id);
281 	model = CPUID_TO_MODEL(cpu_id);
282 
283 	switch (family) {
284 	case 0x0f:
285 		if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
286 		    (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
287 			return (ENXIO);
288 		break;
289 	case 0x10:
290 	case 0x11:
291 	case 0x12:
292 	case 0x14:
293 	case 0x15:
294 	case 0x16:
295 	case 0x17:
296 		break;
297 	default:
298 		return (ENXIO);
299 	}
300 	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
301 
302 	return (BUS_PROBE_GENERIC);
303 }
304 
305 static int
306 amdtemp_attach(device_t dev)
307 {
308 	char tn[32];
309 	u_int regs[4];
310 	const struct amdtemp_product *product;
311 	struct amdtemp_softc *sc;
312 	struct sysctl_ctx_list *sysctlctx;
313 	struct sysctl_oid *sysctlnode;
314 	uint32_t cpuid, family, model;
315 	u_int bid;
316 	int erratum319, unit;
317 	bool needsmn;
318 
319 	sc = device_get_softc(dev);
320 	erratum319 = 0;
321 	needsmn = false;
322 
323 	if (!amdtemp_match(device_get_parent(dev), &product))
324 		return (ENXIO);
325 
326 	cpuid = cpu_id;
327 	family = CPUID_TO_FAMILY(cpuid);
328 	model = CPUID_TO_MODEL(cpuid);
329 
330 	/*
331 	 * This checks for the byzantine condition of running a heterogenous
332 	 * revision multi-socket system where the attach thread is potentially
333 	 * probing a remote socket's PCI device.
334 	 *
335 	 * Currently, such scenarios are unsupported on models using the SMN
336 	 * (because on those models, amdtemp(4) attaches to a different PCI
337 	 * device than the one that contains AMDTEMP_CPUID).
338 	 *
339 	 * The ancient 0x0F family of devices only supports this register from
340 	 * models 40h+.
341 	 */
342 	if (product->amdtemp_has_cpuid && (family > 0x0f ||
343 	    (family == 0x0f && model >= 0x40))) {
344 		cpuid = pci_read_config(device_get_parent(dev), AMDTEMP_CPUID,
345 		    4);
346 		family = CPUID_TO_FAMILY(cpuid);
347 		model = CPUID_TO_MODEL(cpuid);
348 	}
349 
350 	switch (family) {
351 	case 0x0f:
352 		/*
353 		 * Thermaltrip Status Register
354 		 *
355 		 * - ThermSenseCoreSel
356 		 *
357 		 * Revision F & G:	0 - Core1, 1 - Core0
358 		 * Other:		0 - Core0, 1 - Core1
359 		 *
360 		 * - CurTmp
361 		 *
362 		 * Revision G:		bits 23-14
363 		 * Other:		bits 23-16
364 		 *
365 		 * XXX According to the BKDG, CurTmp, ThermSenseSel and
366 		 * ThermSenseCoreSel bits were introduced in Revision F
367 		 * but CurTmp seems working fine as early as Revision C.
368 		 * However, it is not clear whether ThermSenseSel and/or
369 		 * ThermSenseCoreSel work in undocumented cases as well.
370 		 * In fact, the Linux driver suggests it may not work but
371 		 * we just assume it does until we find otherwise.
372 		 *
373 		 * XXX According to Linux, CurTmp starts at -28C on
374 		 * Socket AM2 Revision G processors, which is not
375 		 * documented anywhere.
376 		 */
377 		if (model >= 0x40)
378 			sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
379 		if (model >= 0x60 && model != 0xc1) {
380 			do_cpuid(0x80000001, regs);
381 			bid = (regs[1] >> 9) & 0x1f;
382 			switch (model) {
383 			case 0x68: /* Socket S1g1 */
384 			case 0x6c:
385 			case 0x7c:
386 				break;
387 			case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
388 				if (bid != 0x0b && bid != 0x0c)
389 					sc->sc_flags |=
390 					    AMDTEMP_FLAG_ALT_OFFSET;
391 				break;
392 			case 0x6f: /* Socket AM2 and ASB1 (1 core) */
393 			case 0x7f:
394 				if (bid != 0x07 && bid != 0x09 &&
395 				    bid != 0x0c)
396 					sc->sc_flags |=
397 					    AMDTEMP_FLAG_ALT_OFFSET;
398 				break;
399 			default:
400 				sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET;
401 			}
402 			sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
403 		}
404 
405 		/*
406 		 * There are two sensors per core.
407 		 */
408 		sc->sc_ntemps = 2;
409 
410 		sc->sc_gettemp = amdtemp_gettemp0f;
411 		break;
412 	case 0x10:
413 		/*
414 		 * Erratum 319 Inaccurate Temperature Measurement
415 		 *
416 		 * http://support.amd.com/us/Processor_TechDocs/41322.pdf
417 		 */
418 		do_cpuid(0x80000001, regs);
419 		switch ((regs[1] >> 28) & 0xf) {
420 		case 0:	/* Socket F */
421 			erratum319 = 1;
422 			break;
423 		case 1:	/* Socket AM2+ or AM3 */
424 			if ((pci_cfgregread(pci_get_bus(dev),
425 			    pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) &
426 			    AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 ||
427 			    (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3))
428 				break;
429 			/* XXX 00100F42h (RB-C2) exists in both formats. */
430 			erratum319 = 1;
431 			break;
432 		}
433 		/* FALLTHROUGH */
434 	case 0x11:
435 	case 0x12:
436 	case 0x14:
437 	case 0x15:
438 	case 0x16:
439 		sc->sc_ntemps = 1;
440 		/*
441 		 * Some later (60h+) models of family 15h use a similar SMN
442 		 * network as family 17h.  (However, the register index differs
443 		 * from 17h and the decoding matches other 10h-15h models,
444 		 * which differ from 17h.)
445 		 */
446 		if (family == 0x15 && model >= 0x60) {
447 			sc->sc_gettemp = amdtemp_gettemp15hm60h;
448 			needsmn = true;
449 		} else
450 			sc->sc_gettemp = amdtemp_gettemp;
451 		break;
452 	case 0x17:
453 		sc->sc_ntemps = 1;
454 		sc->sc_gettemp = amdtemp_gettemp17h;
455 		needsmn = true;
456 		break;
457 	default:
458 		device_printf(dev, "Bogus family 0x%x\n", family);
459 		return (ENXIO);
460 	}
461 
462 	if (needsmn) {
463 		sc->sc_smn = device_find_child(
464 		    device_get_parent(dev), "amdsmn", -1);
465 		if (sc->sc_smn == NULL) {
466 			if (bootverbose)
467 				device_printf(dev, "No SMN device found\n");
468 			return (ENXIO);
469 		}
470 	}
471 
472 	/* Find number of cores per package. */
473 	sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
474 	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
475 	if (sc->sc_ncores > MAXCPU)
476 		return (ENXIO);
477 
478 	if (erratum319)
479 		device_printf(dev,
480 		    "Erratum 319: temperature measurement may be inaccurate\n");
481 	if (bootverbose)
482 		device_printf(dev, "Found %d cores and %d sensors.\n",
483 		    sc->sc_ncores,
484 		    sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
485 
486 	/*
487 	 * dev.amdtemp.N tree.
488 	 */
489 	unit = device_get_unit(dev);
490 	ksnprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit);
491 	TUNABLE_INT_FETCH(tn, &sc->sc_offset);
492 
493 	sysctlctx = device_get_sysctl_ctx(dev);
494 	SYSCTL_ADD_INT(sysctlctx,
495 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
496 	    "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0,
497 	    "Temperature sensor offset");
498 	sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
499 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
500 	    "core0", CTLFLAG_RD, 0, "Core 0");
501 
502 	SYSCTL_ADD_PROC(sysctlctx,
503 	    SYSCTL_CHILDREN(sysctlnode),
504 	    OID_AUTO, "sensor0",
505 	    CTLTYPE_INT | CTLFLAG_RD,
506 	    dev, CORE0_SENSOR0, amdtemp_sysctl, "IK",
507 	    "Core 0 / Sensor 0 temperature");
508 
509 	if (family == 0x17)
510 		amdtemp_probe_ccd_sensors17h(dev, model);
511 	else if (sc->sc_ntemps > 1) {
512 		SYSCTL_ADD_PROC(sysctlctx,
513 		    SYSCTL_CHILDREN(sysctlnode),
514 		    OID_AUTO, "sensor1",
515 		    CTLTYPE_INT | CTLFLAG_RD,
516 		    dev, CORE0_SENSOR1, amdtemp_sysctl, "IK",
517 		    "Core 0 / Sensor 1 temperature");
518 
519 		if (sc->sc_ncores > 1) {
520 			sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
521 			    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
522 			    OID_AUTO, "core1", CTLFLAG_RD,
523 			    0, "Core 1");
524 
525 			SYSCTL_ADD_PROC(sysctlctx,
526 			    SYSCTL_CHILDREN(sysctlnode),
527 			    OID_AUTO, "sensor0",
528 			    CTLTYPE_INT | CTLFLAG_RD,
529 			    dev, CORE1_SENSOR0, amdtemp_sysctl, "IK",
530 			    "Core 1 / Sensor 0 temperature");
531 
532 			SYSCTL_ADD_PROC(sysctlctx,
533 			    SYSCTL_CHILDREN(sysctlnode),
534 			    OID_AUTO, "sensor1",
535 			    CTLTYPE_INT | CTLFLAG_RD,
536 			    dev, CORE1_SENSOR1, amdtemp_sysctl, "IK",
537 			    "Core 1 / Sensor 1 temperature");
538 		}
539 	}
540 
541 	/*
542 	 * Try to create dev.cpu sysctl entries and setup intrhook function.
543 	 * This is needed because the cpu driver may be loaded late on boot,
544 	 * after us.
545 	 */
546 	amdtemp_intrhook(dev);
547 	sc->sc_ich.ich_func = amdtemp_intrhook;
548 	sc->sc_ich.ich_arg = dev;
549 	if (config_intrhook_establish(&sc->sc_ich) != 0) {
550 		device_printf(dev, "config_intrhook_establish failed!\n");
551 		return (ENXIO);
552 	}
553 
554 	return (0);
555 }
556 
557 void
558 amdtemp_intrhook(void *arg)
559 {
560 	struct amdtemp_softc *sc;
561 	struct sysctl_ctx_list *sysctlctx;
562 	device_t dev = (device_t)arg;
563 	device_t acpi, cpu, nexus;
564 	amdsensor_t sensor;
565 	int i;
566 
567 	sc = device_get_softc(dev);
568 
569 	/*
570 	 * dev.cpu.N.temperature.
571 	 */
572 	nexus = device_find_child(root_bus, "nexus", 0);
573 	acpi = device_find_child(nexus, "acpi", 0);
574 
575 	for (i = 0; i < sc->sc_ncores; i++) {
576 		if (sc->sc_sysctl_cpu[i] != NULL)
577 			continue;
578 		cpu = device_find_child(acpi, "cpu",
579 		    device_get_unit(dev) * sc->sc_ncores + i);
580 		if (cpu != NULL) {
581 			sysctlctx = device_get_sysctl_ctx(cpu);
582 
583 			sensor = sc->sc_ntemps > 1 ?
584 			    (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0;
585 			sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
586 			    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
587 			    OID_AUTO, "temperature",
588 			    CTLTYPE_INT | CTLFLAG_RD,
589 			    dev, sensor, amdtemp_sysctl, "IK",
590 			    "Current temparature");
591 		}
592 	}
593 	if (sc->sc_ich.ich_arg != NULL)
594 		config_intrhook_disestablish(&sc->sc_ich);
595 }
596 
597 int
598 amdtemp_detach(device_t dev)
599 {
600 	struct amdtemp_softc *sc = device_get_softc(dev);
601 	int i;
602 
603 	for (i = 0; i < sc->sc_ncores; i++)
604 		if (sc->sc_sysctl_cpu[i] != NULL)
605 			sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
606 
607 	/* NewBus removes the dev.amdtemp.N tree by itself. */
608 
609 	return (0);
610 }
611 
612 static int
613 amdtemp_sysctl(SYSCTL_HANDLER_ARGS)
614 {
615 	device_t dev = (device_t)arg1;
616 	struct amdtemp_softc *sc = device_get_softc(dev);
617 	amdsensor_t sensor = (amdsensor_t)arg2;
618 	int32_t auxtemp[2], temp;
619 	int error;
620 
621 	switch (sensor) {
622 	case CORE0:
623 		auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0);
624 		auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1);
625 		temp = imax(auxtemp[0], auxtemp[1]);
626 		break;
627 	case CORE1:
628 		auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0);
629 		auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1);
630 		temp = imax(auxtemp[0], auxtemp[1]);
631 		break;
632 	default:
633 		temp = sc->sc_gettemp(dev, sensor);
634 		break;
635 	}
636 	error = sysctl_handle_int(oidp, &temp, 0, req);
637 
638 	return (error);
639 }
640 
641 #define	AMDTEMP_ZERO_C_TO_K	2731
642 
643 static int32_t
644 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
645 {
646 	struct amdtemp_softc *sc = device_get_softc(dev);
647 	uint32_t mask, offset, temp;
648 
649 	/* Set Sensor/Core selector. */
650 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
651 	temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR);
652 	switch (sensor) {
653 	case CORE0_SENSOR1:
654 		temp |= AMDTEMP_TTSR_SELSENSOR;
655 		/* FALLTHROUGH */
656 	case CORE0_SENSOR0:
657 	case CORE0:
658 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
659 			temp |= AMDTEMP_TTSR_SELCORE;
660 		break;
661 	case CORE1_SENSOR1:
662 		temp |= AMDTEMP_TTSR_SELSENSOR;
663 		/* FALLTHROUGH */
664 	case CORE1_SENSOR0:
665 	case CORE1:
666 		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
667 			temp |= AMDTEMP_TTSR_SELCORE;
668 		break;
669 	default:
670 		__assert_unreachable();
671 	}
672 	pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1);
673 
674 	mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
675 	offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49;
676 	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
677 	temp = ((temp >> 14) & mask) * 5 / 2;
678 	temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10;
679 
680 	return (temp);
681 }
682 
683 static uint32_t
684 amdtemp_decode_fam10h_to_17h(int32_t sc_offset, uint32_t val, bool minus49)
685 {
686 	uint32_t temp;
687 
688 	/* Convert raw register subfield units (0.125C) to units of 0.1C. */
689 	temp = (val & AMDTEMP_REPTMP10H_CURTMP_MASK) * 5 / 4;
690 
691 	if (minus49)
692 		temp -= AMDTEMP_CURTMP_RANGE_ADJUST;
693 
694 	temp += AMDTEMP_ZERO_C_TO_K + sc_offset * 10;
695 	return (temp);
696 }
697 
698 static uint32_t
699 amdtemp_decode_fam10h_to_16h(int32_t sc_offset, uint32_t val)
700 {
701 	bool minus49;
702 
703 	/*
704 	 * On Family 15h and higher, if CurTmpTjSel is 11b, the range is
705 	 * adjusted down by 49.0 degrees Celsius.  (This adjustment is not
706 	 * documented in BKDGs prior to family 15h model 00h.)
707 	 */
708 	minus49 = (CPUID_TO_FAMILY(cpu_id) >= 0x15 &&
709 	    ((val >> AMDTEMP_REPTMP10H_TJSEL_SHIFT) &
710 	    AMDTEMP_REPTMP10H_TJSEL_MASK) == 0x3);
711 
712 	return (amdtemp_decode_fam10h_to_17h(sc_offset,
713 	    val >> AMDTEMP_REPTMP10H_CURTMP_SHIFT, minus49));
714 }
715 
716 static uint32_t
717 amdtemp_decode_fam17h_tctl(int32_t sc_offset, uint32_t val)
718 {
719 	bool minus49;
720 
721 	minus49 = ((val & AMDTEMP_17H_CUR_TMP_RANGE_SEL) != 0);
722 	return (amdtemp_decode_fam10h_to_17h(sc_offset,
723 	    val >> AMDTEMP_REPTMP10H_CURTMP_SHIFT, minus49));
724 }
725 
726 static int32_t
727 amdtemp_gettemp(device_t dev, amdsensor_t sensor)
728 {
729 	struct amdtemp_softc *sc = device_get_softc(dev);
730 	uint32_t temp;
731 
732 	temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
733 	return (amdtemp_decode_fam10h_to_16h(sc->sc_offset, temp));
734 }
735 
736 static int32_t
737 amdtemp_gettemp15hm60h(device_t dev, amdsensor_t sensor)
738 {
739 	struct amdtemp_softc *sc = device_get_softc(dev);
740 	uint32_t val;
741 	int error;
742 
743 	error = amdsmn_read(sc->sc_smn, AMDTEMP_15H_M60H_REPTMP_CTRL, &val);
744 	KASSERT(error == 0, ("amdsmn_read"));
745 	return (amdtemp_decode_fam10h_to_16h(sc->sc_offset, val));
746 }
747 
748 static int32_t
749 amdtemp_gettemp17h(device_t dev, amdsensor_t sensor)
750 {
751 	struct amdtemp_softc *sc = device_get_softc(dev);
752 	uint32_t val;
753 	int error;
754 
755 	switch (sensor) {
756 	case CORE0_SENSOR0:
757 		/* Tctl */
758 		error = amdsmn_read(sc->sc_smn, AMDTEMP_17H_CUR_TMP, &val);
759 		KASSERT(error == 0, ("amdsmn_read"));
760 		return (amdtemp_decode_fam17h_tctl(sc->sc_offset, val));
761 	case CCD_BASE ... CCD_MAX:
762 		/* Tccd<N> */
763 		error = amdsmn_read(sc->sc_smn, AMDTEMP_17H_CCD_TMP_BASE +
764 		    (((int)sensor - CCD_BASE) * sizeof(val)), &val);
765 		KASSERT(error == 0, ("amdsmn_read2"));
766 		KASSERT((val & AMDTEMP_17H_CCD_TMP_VALID) != 0,
767 		    ("sensor %d: not valid", (int)sensor));
768 		return (amdtemp_decode_fam10h_to_17h(sc->sc_offset, val, true));
769 	default:
770 		__assert_unreachable();
771 	}
772 }
773 
774 static void
775 amdtemp_probe_ccd_sensors17h(device_t dev, uint32_t model)
776 {
777 	char sensor_name[16], sensor_descr[32];
778 	struct amdtemp_softc *sc;
779 	uint32_t maxreg, i, val;
780 	int error;
781 
782 	switch (model) {
783 	case 0x00 ... 0x1f: /* Zen1, Zen+ */
784 		maxreg = 4;
785 		break;
786 	case 0x30 ... 0x3f: /* Zen2 TR/Epyc */
787 	case 0x70 ... 0x7f: /* Zen2 Ryzen */
788 		maxreg = 8;
789 		_Static_assert((int)NUM_CCDS >= 8, "");
790 		break;
791 	default:
792 		device_printf(dev,
793 		    "Unrecognized Family 17h Model: %02xh\n", model);
794 		return;
795 	}
796 
797 	sc = device_get_softc(dev);
798 	for (i = 0; i < maxreg; i++) {
799 		error = amdsmn_read(sc->sc_smn, AMDTEMP_17H_CCD_TMP_BASE +
800 		    (i * sizeof(val)), &val);
801 		if (error != 0)
802 			continue;
803 		if ((val & AMDTEMP_17H_CCD_TMP_VALID) == 0)
804 			continue;
805 
806 		ksnprintf(sensor_name, sizeof(sensor_name), "ccd%u", i);
807 		ksnprintf(sensor_descr, sizeof(sensor_descr),
808 		    "CCD %u temperature (Tccd%u)", i, i);
809 
810 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
811 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
812 		    sensor_name, CTLTYPE_INT | CTLFLAG_RD,
813 		    dev, CCD_BASE + i, amdtemp_sysctl, "IK", sensor_descr);
814 	}
815 }
816