amdtemp.c revision 273383
1178151Srpaulo/*-
2189769Srpaulo * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
3189769Srpaulo * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
4232090Sjkim * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org>
5178151Srpaulo * All rights reserved.
6178151Srpaulo *
7178151Srpaulo * Redistribution and use in source and binary forms, with or without
8178151Srpaulo * modification, are permitted provided that the following conditions
9178151Srpaulo * are met:
10178151Srpaulo * 1. Redistributions of source code must retain the above copyright
11178151Srpaulo *    notice, this list of conditions and the following disclaimer.
12178151Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
13178151Srpaulo *    notice, this list of conditions and the following disclaimer in the
14178151Srpaulo *    documentation and/or other materials provided with the distribution.
15178151Srpaulo *
16178151Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17178151Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18178151Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19178151Srpaulo * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20178151Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21178151Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22178151Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23178151Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24178151Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25178151Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26178151Srpaulo * POSSIBILITY OF SUCH DAMAGE.
27178151Srpaulo */
28178151Srpaulo
29178151Srpaulo/*
30232090Sjkim * Driver for the AMD CPU on-die thermal sensors.
31197102Sjkim * Initially based on the k8temp Linux driver.
32178151Srpaulo */
33178151Srpaulo
34178151Srpaulo#include <sys/cdefs.h>
35178151Srpaulo__FBSDID("$FreeBSD: stable/10/sys/dev/amdtemp/amdtemp.c 273383 2014-10-21 13:07:36Z brueffer $");
36178151Srpaulo
37178151Srpaulo#include <sys/param.h>
38178151Srpaulo#include <sys/bus.h>
39178151Srpaulo#include <sys/conf.h>
40178151Srpaulo#include <sys/kernel.h>
41197102Sjkim#include <sys/module.h>
42178151Srpaulo#include <sys/sysctl.h>
43197102Sjkim#include <sys/systm.h>
44178151Srpaulo
45197205Sjkim#include <machine/cpufunc.h>
46197102Sjkim#include <machine/md_var.h>
47178151Srpaulo#include <machine/specialreg.h>
48178151Srpaulo
49178151Srpaulo#include <dev/pci/pcivar.h>
50232090Sjkim#include <x86/pci_cfgreg.h>
51178151Srpaulo
52189769Srpaulotypedef enum {
53232090Sjkim	CORE0_SENSOR0,
54232090Sjkim	CORE0_SENSOR1,
55232090Sjkim	CORE1_SENSOR0,
56232090Sjkim	CORE1_SENSOR1,
57189769Srpaulo	CORE0,
58189769Srpaulo	CORE1
59189769Srpaulo} amdsensor_t;
60189769Srpaulo
61189769Srpaulostruct amdtemp_softc {
62178151Srpaulo	device_t	sc_dev;
63197102Sjkim	int		sc_ncores;
64178151Srpaulo	int		sc_ntemps;
65197205Sjkim	int		sc_flags;
66232090Sjkim#define	AMDTEMP_FLAG_CS_SWAP	0x01	/* ThermSenseCoreSel is inverted. */
67232090Sjkim#define	AMDTEMP_FLAG_CT_10BIT	0x02	/* CurTmp is 10-bit wide. */
68232090Sjkim#define	AMDTEMP_FLAG_ALT_OFFSET	0x04	/* CurTmp starts at -28C. */
69232090Sjkim	int32_t		sc_offset;
70197102Sjkim	int32_t		(*sc_gettemp)(device_t, amdsensor_t);
71197102Sjkim	struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
72180312Srpaulo	struct intr_config_hook sc_ich;
73178151Srpaulo};
74178151Srpaulo
75197102Sjkim#define	VENDORID_AMD		0x1022
76197102Sjkim#define	DEVICEID_AMD_MISC0F	0x1103
77197102Sjkim#define	DEVICEID_AMD_MISC10	0x1203
78197102Sjkim#define	DEVICEID_AMD_MISC11	0x1303
79254924Sjmg#define	DEVICEID_AMD_MISC12	0x1403
80232090Sjkim#define	DEVICEID_AMD_MISC14	0x1703
81232090Sjkim#define	DEVICEID_AMD_MISC15	0x1603
82263869Sbrueffer#define	DEVICEID_AMD_MISC16	0x1533
83273383Sbrueffer#define	DEVICEID_AMD_MISC17	0x141d
84178151Srpaulo
85189769Srpaulostatic struct amdtemp_product {
86189769Srpaulo	uint16_t	amdtemp_vendorid;
87189769Srpaulo	uint16_t	amdtemp_deviceid;
88189769Srpaulo} amdtemp_products[] = {
89189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC0F },
90189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC10 },
91189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC11 },
92254924Sjmg	{ VENDORID_AMD,	DEVICEID_AMD_MISC12 },
93232090Sjkim	{ VENDORID_AMD,	DEVICEID_AMD_MISC14 },
94232090Sjkim	{ VENDORID_AMD,	DEVICEID_AMD_MISC15 },
95263869Sbrueffer	{ VENDORID_AMD,	DEVICEID_AMD_MISC16 },
96273383Sbrueffer	{ VENDORID_AMD,	DEVICEID_AMD_MISC17 },
97178151Srpaulo	{ 0, 0 }
98178151Srpaulo};
99178151Srpaulo
100178151Srpaulo/*
101232090Sjkim * Reported Temperature Control Register
102178151Srpaulo */
103197102Sjkim#define	AMDTEMP_REPTMP_CTRL	0xa4
104178151Srpaulo
105189769Srpaulo/*
106232090Sjkim * Thermaltrip Status Register (Family 0Fh only)
107189769Srpaulo */
108197102Sjkim#define	AMDTEMP_THERMTP_STAT	0xe4
109232090Sjkim#define	AMDTEMP_TTSR_SELCORE	0x04
110232090Sjkim#define	AMDTEMP_TTSR_SELSENSOR	0x40
111178151Srpaulo
112197102Sjkim/*
113232090Sjkim * DRAM Configuration High Register
114232090Sjkim */
115232090Sjkim#define	AMDTEMP_DRAM_CONF_HIGH	0x94	/* Function 2 */
116232090Sjkim#define	AMDTEMP_DRAM_MODE_DDR3	0x0100
117232090Sjkim
118232090Sjkim/*
119197102Sjkim * CPU Family/Model Register
120197102Sjkim */
121197102Sjkim#define	AMDTEMP_CPUID		0xfc
122178151Srpaulo
123178151Srpaulo/*
124178151Srpaulo * Device methods.
125178151Srpaulo */
126189769Srpaulostatic void 	amdtemp_identify(driver_t *driver, device_t parent);
127189769Srpaulostatic int	amdtemp_probe(device_t dev);
128189769Srpaulostatic int	amdtemp_attach(device_t dev);
129189769Srpaulostatic void	amdtemp_intrhook(void *arg);
130189769Srpaulostatic int	amdtemp_detach(device_t dev);
131189769Srpaulostatic int 	amdtemp_match(device_t dev);
132189769Srpaulostatic int32_t	amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
133189769Srpaulostatic int32_t	amdtemp_gettemp(device_t dev, amdsensor_t sensor);
134189769Srpaulostatic int	amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
135178151Srpaulo
136189769Srpaulostatic device_method_t amdtemp_methods[] = {
137178151Srpaulo	/* Device interface */
138189769Srpaulo	DEVMETHOD(device_identify,	amdtemp_identify),
139189769Srpaulo	DEVMETHOD(device_probe,		amdtemp_probe),
140189769Srpaulo	DEVMETHOD(device_attach,	amdtemp_attach),
141189769Srpaulo	DEVMETHOD(device_detach,	amdtemp_detach),
142178151Srpaulo
143246128Ssbz	DEVMETHOD_END
144178151Srpaulo};
145178151Srpaulo
146189769Srpaulostatic driver_t amdtemp_driver = {
147189769Srpaulo	"amdtemp",
148189769Srpaulo	amdtemp_methods,
149189769Srpaulo	sizeof(struct amdtemp_softc),
150178151Srpaulo};
151178151Srpaulo
152189769Srpaulostatic devclass_t amdtemp_devclass;
153189769SrpauloDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
154178151Srpaulo
155178151Srpaulostatic int
156189769Srpauloamdtemp_match(device_t dev)
157178151Srpaulo{
158178151Srpaulo	int i;
159178151Srpaulo	uint16_t vendor, devid;
160197102Sjkim
161197102Sjkim	vendor = pci_get_vendor(dev);
162178151Srpaulo	devid = pci_get_device(dev);
163178151Srpaulo
164189769Srpaulo	for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
165189769Srpaulo		if (vendor == amdtemp_products[i].amdtemp_vendorid &&
166189769Srpaulo		    devid == amdtemp_products[i].amdtemp_deviceid)
167178151Srpaulo			return (1);
168178151Srpaulo	}
169178151Srpaulo
170178151Srpaulo	return (0);
171178151Srpaulo}
172178151Srpaulo
173178151Srpaulostatic void
174189769Srpauloamdtemp_identify(driver_t *driver, device_t parent)
175178151Srpaulo{
176178151Srpaulo	device_t child;
177178151Srpaulo
178178151Srpaulo	/* Make sure we're not being doubly invoked. */
179189769Srpaulo	if (device_find_child(parent, "amdtemp", -1) != NULL)
180178151Srpaulo		return;
181197102Sjkim
182189769Srpaulo	if (amdtemp_match(parent)) {
183189769Srpaulo		child = device_add_child(parent, "amdtemp", -1);
184178151Srpaulo		if (child == NULL)
185189769Srpaulo			device_printf(parent, "add amdtemp child failed\n");
186178151Srpaulo	}
187178151Srpaulo}
188178151Srpaulo
189178151Srpaulostatic int
190189769Srpauloamdtemp_probe(device_t dev)
191178151Srpaulo{
192197205Sjkim	uint32_t family, model;
193197102Sjkim
194241885Seadler	if (resource_disabled("amdtemp", 0))
195241885Seadler		return (ENXIO);
196241885Seadler
197197205Sjkim	family = CPUID_TO_FAMILY(cpu_id);
198197205Sjkim	model = CPUID_TO_MODEL(cpu_id);
199197102Sjkim
200197102Sjkim	switch (family) {
201197102Sjkim	case 0x0f:
202197205Sjkim		if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
203197205Sjkim		    (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
204197102Sjkim			return (ENXIO);
205197102Sjkim		break;
206197102Sjkim	case 0x10:
207197102Sjkim	case 0x11:
208232090Sjkim	case 0x12:
209232090Sjkim	case 0x14:
210232090Sjkim	case 0x15:
211263869Sbrueffer	case 0x16:
212197102Sjkim		break;
213197102Sjkim	default:
214178151Srpaulo		return (ENXIO);
215178151Srpaulo	}
216197102Sjkim	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
217197102Sjkim
218178151Srpaulo	return (BUS_PROBE_GENERIC);
219178151Srpaulo}
220178151Srpaulo
221178151Srpaulostatic int
222189769Srpauloamdtemp_attach(device_t dev)
223178151Srpaulo{
224232090Sjkim	char tn[32];
225232090Sjkim	u_int regs[4];
226189769Srpaulo	struct amdtemp_softc *sc = device_get_softc(dev);
227178151Srpaulo	struct sysctl_ctx_list *sysctlctx;
228178151Srpaulo	struct sysctl_oid *sysctlnode;
229197102Sjkim	uint32_t cpuid, family, model;
230232090Sjkim	u_int bid;
231232090Sjkim	int erratum319, unit;
232178151Srpaulo
233232090Sjkim	erratum319 = 0;
234180312Srpaulo
235197205Sjkim	/*
236197205Sjkim	 * CPUID Register is available from Revision F.
237197205Sjkim	 */
238232090Sjkim	cpuid = cpu_id;
239232090Sjkim	family = CPUID_TO_FAMILY(cpuid);
240232090Sjkim	model = CPUID_TO_MODEL(cpuid);
241197205Sjkim	if (family != 0x0f || model >= 0x40) {
242197205Sjkim		cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4);
243197205Sjkim		family = CPUID_TO_FAMILY(cpuid);
244197205Sjkim		model = CPUID_TO_MODEL(cpuid);
245197205Sjkim	}
246197205Sjkim
247197102Sjkim	switch (family) {
248197102Sjkim	case 0x0f:
249197102Sjkim		/*
250197205Sjkim		 * Thermaltrip Status Register
251197102Sjkim		 *
252197205Sjkim		 * - ThermSenseCoreSel
253197205Sjkim		 *
254197205Sjkim		 * Revision F & G:	0 - Core1, 1 - Core0
255197205Sjkim		 * Other:		0 - Core0, 1 - Core1
256197205Sjkim		 *
257197205Sjkim		 * - CurTmp
258197205Sjkim		 *
259197102Sjkim		 * Revision G:		bits 23-14
260197205Sjkim		 * Other:		bits 23-16
261197102Sjkim		 *
262197205Sjkim		 * XXX According to the BKDG, CurTmp, ThermSenseSel and
263197205Sjkim		 * ThermSenseCoreSel bits were introduced in Revision F
264197205Sjkim		 * but CurTmp seems working fine as early as Revision C.
265197205Sjkim		 * However, it is not clear whether ThermSenseSel and/or
266197205Sjkim		 * ThermSenseCoreSel work in undocumented cases as well.
267197205Sjkim		 * In fact, the Linux driver suggests it may not work but
268197205Sjkim		 * we just assume it does until we find otherwise.
269232090Sjkim		 *
270232090Sjkim		 * XXX According to Linux, CurTmp starts at -28C on
271232090Sjkim		 * Socket AM2 Revision G processors, which is not
272232090Sjkim		 * documented anywhere.
273197102Sjkim		 */
274232090Sjkim		if (model >= 0x40)
275197205Sjkim			sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
276232090Sjkim		if (model >= 0x60 && model != 0xc1) {
277232090Sjkim			do_cpuid(0x80000001, regs);
278232090Sjkim			bid = (regs[1] >> 9) & 0x1f;
279232090Sjkim			switch (model) {
280232090Sjkim			case 0x68: /* Socket S1g1 */
281232090Sjkim			case 0x6c:
282232090Sjkim			case 0x7c:
283232090Sjkim				break;
284232090Sjkim			case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
285232090Sjkim				if (bid != 0x0b && bid != 0x0c)
286232090Sjkim					sc->sc_flags |=
287232090Sjkim					    AMDTEMP_FLAG_ALT_OFFSET;
288232090Sjkim				break;
289232090Sjkim			case 0x6f: /* Socket AM2 and ASB1 (1 core) */
290232090Sjkim			case 0x7f:
291232090Sjkim				if (bid != 0x07 && bid != 0x09 &&
292232090Sjkim				    bid != 0x0c)
293232090Sjkim					sc->sc_flags |=
294232090Sjkim					    AMDTEMP_FLAG_ALT_OFFSET;
295232090Sjkim				break;
296232090Sjkim			default:
297232090Sjkim				sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET;
298232090Sjkim			}
299232090Sjkim			sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
300197205Sjkim		}
301197102Sjkim
302197102Sjkim		/*
303197102Sjkim		 * There are two sensors per core.
304197102Sjkim		 */
305197102Sjkim		sc->sc_ntemps = 2;
306197102Sjkim
307189769Srpaulo		sc->sc_gettemp = amdtemp_gettemp0f;
308197102Sjkim		break;
309197102Sjkim	case 0x10:
310232090Sjkim		/*
311232090Sjkim		 * Erratum 319 Inaccurate Temperature Measurement
312232090Sjkim		 *
313232090Sjkim		 * http://support.amd.com/us/Processor_TechDocs/41322.pdf
314232090Sjkim		 */
315232090Sjkim		do_cpuid(0x80000001, regs);
316232090Sjkim		switch ((regs[1] >> 28) & 0xf) {
317232090Sjkim		case 0:	/* Socket F */
318232090Sjkim			erratum319 = 1;
319232090Sjkim			break;
320232090Sjkim		case 1:	/* Socket AM2+ or AM3 */
321232090Sjkim			if ((pci_cfgregread(pci_get_bus(dev),
322232090Sjkim			    pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) &
323232090Sjkim			    AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 ||
324232090Sjkim			    (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3))
325232090Sjkim				break;
326232090Sjkim			/* XXX 00100F42h (RB-C2) exists in both formats. */
327232090Sjkim			erratum319 = 1;
328232090Sjkim			break;
329232090Sjkim		}
330232090Sjkim		/* FALLTHROUGH */
331197102Sjkim	case 0x11:
332232090Sjkim	case 0x12:
333232090Sjkim	case 0x14:
334232090Sjkim	case 0x15:
335263869Sbrueffer	case 0x16:
336197102Sjkim		/*
337197102Sjkim		 * There is only one sensor per package.
338197102Sjkim		 */
339197102Sjkim		sc->sc_ntemps = 1;
340197102Sjkim
341189769Srpaulo		sc->sc_gettemp = amdtemp_gettemp;
342197102Sjkim		break;
343189769Srpaulo	}
344189769Srpaulo
345197102Sjkim	/* Find number of cores per package. */
346197102Sjkim	sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
347197102Sjkim	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
348197102Sjkim	if (sc->sc_ncores > MAXCPU)
349197102Sjkim		return (ENXIO);
350197102Sjkim
351232090Sjkim	if (erratum319)
352232090Sjkim		device_printf(dev,
353232090Sjkim		    "Erratum 319: temperature measurement may be inaccurate\n");
354197102Sjkim	if (bootverbose)
355197102Sjkim		device_printf(dev, "Found %d cores and %d sensors.\n",
356197102Sjkim		    sc->sc_ncores,
357197102Sjkim		    sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
358197102Sjkim
359178151Srpaulo	/*
360189769Srpaulo	 * dev.amdtemp.N tree.
361178151Srpaulo	 */
362232090Sjkim	unit = device_get_unit(dev);
363232090Sjkim	snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit);
364232090Sjkim	TUNABLE_INT_FETCH(tn, &sc->sc_offset);
365232090Sjkim
366178151Srpaulo	sysctlctx = device_get_sysctl_ctx(dev);
367232090Sjkim	SYSCTL_ADD_INT(sysctlctx,
368232090Sjkim	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
369232090Sjkim	    "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0,
370232090Sjkim	    "Temperature sensor offset");
371178151Srpaulo	sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
372197102Sjkim	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
373232090Sjkim	    "core0", CTLFLAG_RD, 0, "Core 0");
374197102Sjkim
375178151Srpaulo	SYSCTL_ADD_PROC(sysctlctx,
376178151Srpaulo	    SYSCTL_CHILDREN(sysctlnode),
377232090Sjkim	    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
378232090Sjkim	    dev, CORE0_SENSOR0, amdtemp_sysctl, "IK",
379232090Sjkim	    "Core 0 / Sensor 0 temperature");
380178151Srpaulo
381197102Sjkim	if (sc->sc_ntemps > 1) {
382197102Sjkim		SYSCTL_ADD_PROC(sysctlctx,
383197102Sjkim		    SYSCTL_CHILDREN(sysctlnode),
384232090Sjkim		    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
385232090Sjkim		    dev, CORE0_SENSOR1, amdtemp_sysctl, "IK",
386232090Sjkim		    "Core 0 / Sensor 1 temperature");
387197102Sjkim
388232090Sjkim		if (sc->sc_ncores > 1) {
389232090Sjkim			sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
390232090Sjkim			    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
391232090Sjkim			    OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1");
392232090Sjkim
393197102Sjkim			SYSCTL_ADD_PROC(sysctlctx,
394197102Sjkim			    SYSCTL_CHILDREN(sysctlnode),
395232090Sjkim			    OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD,
396232090Sjkim			    dev, CORE1_SENSOR0, amdtemp_sysctl, "IK",
397232090Sjkim			    "Core 1 / Sensor 0 temperature");
398232090Sjkim
399232090Sjkim			SYSCTL_ADD_PROC(sysctlctx,
400232090Sjkim			    SYSCTL_CHILDREN(sysctlnode),
401232090Sjkim			    OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD,
402232090Sjkim			    dev, CORE1_SENSOR1, amdtemp_sysctl, "IK",
403232090Sjkim			    "Core 1 / Sensor 1 temperature");
404232090Sjkim		}
405197102Sjkim	}
406197102Sjkim
407197102Sjkim	/*
408197102Sjkim	 * Try to create dev.cpu sysctl entries and setup intrhook function.
409197102Sjkim	 * This is needed because the cpu driver may be loaded late on boot,
410197102Sjkim	 * after us.
411197102Sjkim	 */
412197102Sjkim	amdtemp_intrhook(dev);
413197102Sjkim	sc->sc_ich.ich_func = amdtemp_intrhook;
414197102Sjkim	sc->sc_ich.ich_arg = dev;
415197102Sjkim	if (config_intrhook_establish(&sc->sc_ich) != 0) {
416197102Sjkim		device_printf(dev, "config_intrhook_establish failed!\n");
417197102Sjkim		return (ENXIO);
418197102Sjkim	}
419197102Sjkim
420178151Srpaulo	return (0);
421178151Srpaulo}
422178151Srpaulo
423180312Srpaulovoid
424189769Srpauloamdtemp_intrhook(void *arg)
425180312Srpaulo{
426189769Srpaulo	struct amdtemp_softc *sc;
427180312Srpaulo	struct sysctl_ctx_list *sysctlctx;
428197102Sjkim	device_t dev = (device_t)arg;
429197102Sjkim	device_t acpi, cpu, nexus;
430197102Sjkim	amdsensor_t sensor;
431197102Sjkim	int i;
432180312Srpaulo
433180312Srpaulo	sc = device_get_softc(dev);
434197102Sjkim
435180312Srpaulo	/*
436180312Srpaulo	 * dev.cpu.N.temperature.
437180312Srpaulo	 */
438180312Srpaulo	nexus = device_find_child(root_bus, "nexus", 0);
439180312Srpaulo	acpi = device_find_child(nexus, "acpi", 0);
440180312Srpaulo
441197102Sjkim	for (i = 0; i < sc->sc_ncores; i++) {
442197102Sjkim		if (sc->sc_sysctl_cpu[i] != NULL)
443197102Sjkim			continue;
444180312Srpaulo		cpu = device_find_child(acpi, "cpu",
445197102Sjkim		    device_get_unit(dev) * sc->sc_ncores + i);
446197102Sjkim		if (cpu != NULL) {
447180312Srpaulo			sysctlctx = device_get_sysctl_ctx(cpu);
448180312Srpaulo
449197102Sjkim			sensor = sc->sc_ntemps > 1 ?
450232090Sjkim			    (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0;
451180312Srpaulo			sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
452180312Srpaulo			    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
453180312Srpaulo			    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
454197102Sjkim			    dev, sensor, amdtemp_sysctl, "IK",
455197102Sjkim			    "Current temparature");
456180312Srpaulo		}
457180312Srpaulo	}
458197102Sjkim	if (sc->sc_ich.ich_arg != NULL)
459197102Sjkim		config_intrhook_disestablish(&sc->sc_ich);
460180312Srpaulo}
461180312Srpaulo
462178151Srpauloint
463189769Srpauloamdtemp_detach(device_t dev)
464178151Srpaulo{
465197102Sjkim	struct amdtemp_softc *sc = device_get_softc(dev);
466178151Srpaulo	int i;
467197102Sjkim
468197102Sjkim	for (i = 0; i < sc->sc_ncores; i++)
469197102Sjkim		if (sc->sc_sysctl_cpu[i] != NULL)
470178151Srpaulo			sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
471178151Srpaulo
472189769Srpaulo	/* NewBus removes the dev.amdtemp.N tree by itself. */
473197102Sjkim
474178151Srpaulo	return (0);
475178151Srpaulo}
476178151Srpaulo
477178151Srpaulostatic int
478189769Srpauloamdtemp_sysctl(SYSCTL_HANDLER_ARGS)
479178151Srpaulo{
480197102Sjkim	device_t dev = (device_t)arg1;
481189769Srpaulo	struct amdtemp_softc *sc = device_get_softc(dev);
482197102Sjkim	amdsensor_t sensor = (amdsensor_t)arg2;
483197102Sjkim	int32_t auxtemp[2], temp;
484178151Srpaulo	int error;
485178151Srpaulo
486197102Sjkim	switch (sensor) {
487178151Srpaulo	case CORE0:
488232090Sjkim		auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0);
489232090Sjkim		auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1);
490178988Srpaulo		temp = imax(auxtemp[0], auxtemp[1]);
491178151Srpaulo		break;
492178151Srpaulo	case CORE1:
493232090Sjkim		auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0);
494232090Sjkim		auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1);
495178988Srpaulo		temp = imax(auxtemp[0], auxtemp[1]);
496178151Srpaulo		break;
497178151Srpaulo	default:
498197102Sjkim		temp = sc->sc_gettemp(dev, sensor);
499178151Srpaulo		break;
500178151Srpaulo	}
501178151Srpaulo	error = sysctl_handle_int(oidp, &temp, 0, req);
502197102Sjkim
503178151Srpaulo	return (error);
504178151Srpaulo}
505178151Srpaulo
506197102Sjkim#define	AMDTEMP_ZERO_C_TO_K	2732
507197102Sjkim
508178151Srpaulostatic int32_t
509189769Srpauloamdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
510178151Srpaulo{
511197102Sjkim	struct amdtemp_softc *sc = device_get_softc(dev);
512232090Sjkim	uint32_t mask, offset, temp;
513197102Sjkim
514197102Sjkim	/* Set Sensor/Core selector. */
515232090Sjkim	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
516232090Sjkim	temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR);
517178151Srpaulo	switch (sensor) {
518232090Sjkim	case CORE0_SENSOR1:
519232090Sjkim		temp |= AMDTEMP_TTSR_SELSENSOR;
520197103Sjkim		/* FALLTHROUGH */
521232090Sjkim	case CORE0_SENSOR0:
522197102Sjkim	case CORE0:
523197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
524232090Sjkim			temp |= AMDTEMP_TTSR_SELCORE;
525178151Srpaulo		break;
526232090Sjkim	case CORE1_SENSOR1:
527232090Sjkim		temp |= AMDTEMP_TTSR_SELSENSOR;
528197103Sjkim		/* FALLTHROUGH */
529232090Sjkim	case CORE1_SENSOR0:
530197102Sjkim	case CORE1:
531197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
532232090Sjkim			temp |= AMDTEMP_TTSR_SELCORE;
533178151Srpaulo		break;
534178151Srpaulo	}
535232090Sjkim	pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1);
536197102Sjkim
537232090Sjkim	mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
538232090Sjkim	offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49;
539197102Sjkim	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
540232090Sjkim	temp = ((temp >> 14) & mask) * 5 / 2;
541232090Sjkim	temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10;
542197102Sjkim
543178151Srpaulo	return (temp);
544178151Srpaulo}
545189769Srpaulo
546189769Srpaulostatic int32_t
547189769Srpauloamdtemp_gettemp(device_t dev, amdsensor_t sensor)
548189769Srpaulo{
549232090Sjkim	struct amdtemp_softc *sc = device_get_softc(dev);
550189769Srpaulo	uint32_t temp;
551189769Srpaulo
552197102Sjkim	temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
553232090Sjkim	temp = ((temp >> 21) & 0x7ff) * 5 / 4;
554232090Sjkim	temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10;
555197102Sjkim
556189769Srpaulo	return (temp);
557189769Srpaulo}
558