13a514b87SHasso Tepper /*
2575aab54SSascha Wildner * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org>
33a514b87SHasso Tepper * All rights reserved.
43a514b87SHasso Tepper *
53a514b87SHasso Tepper * Redistribution and use in source and binary forms, with or without
63a514b87SHasso Tepper * modification, are permitted provided that the following conditions
73a514b87SHasso Tepper * are met:
83a514b87SHasso Tepper * 1. Redistributions of source code must retain the above copyright
93a514b87SHasso Tepper * notice, this list of conditions and the following disclaimer.
103a514b87SHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
113a514b87SHasso Tepper * notice, this list of conditions and the following disclaimer in the
123a514b87SHasso Tepper * documentation and/or other materials provided with the distribution.
133a514b87SHasso Tepper *
143a514b87SHasso Tepper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
153a514b87SHasso Tepper * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
163a514b87SHasso Tepper * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
173a514b87SHasso Tepper * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
183a514b87SHasso Tepper * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
193a514b87SHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
203a514b87SHasso Tepper * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213a514b87SHasso Tepper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
223a514b87SHasso Tepper * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
233a514b87SHasso Tepper * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
243a514b87SHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
253a514b87SHasso Tepper *
26575aab54SSascha Wildner * $FreeBSD: src/sys/dev/coretemp/coretemp.c,v 1.14 2011/05/05 19:15:15 delphij Exp $
273a514b87SHasso Tepper */
283a514b87SHasso Tepper
293a514b87SHasso Tepper /*
303a514b87SHasso Tepper * Device driver for Intel's On Die thermal sensor via MSR.
313a514b87SHasso Tepper * First introduced in Intel's Core line of processors.
323a514b87SHasso Tepper */
333a514b87SHasso Tepper
343a514b87SHasso Tepper #include <sys/param.h>
353a514b87SHasso Tepper #include <sys/bus.h>
363a514b87SHasso Tepper #include <sys/systm.h>
373a514b87SHasso Tepper #include <sys/module.h>
383a514b87SHasso Tepper #include <sys/conf.h>
39056f320bSSepherosa Ziehau #include <sys/cpu_topology.h>
403a514b87SHasso Tepper #include <sys/kernel.h>
41*dae65060Szrj #include <sys/malloc.h>
423a514b87SHasso Tepper #include <sys/sensors.h>
433a514b87SHasso Tepper #include <sys/proc.h> /* for curthread */
443a514b87SHasso Tepper #include <sys/sched.h>
45ce72fc09SSepherosa Ziehau #include <sys/thread2.h>
46680d36f5SSepherosa Ziehau #include <sys/bitops.h>
473a514b87SHasso Tepper
483a514b87SHasso Tepper #include <machine/specialreg.h>
493a514b87SHasso Tepper #include <machine/cpufunc.h>
5086b7a03aSSascha Wildner #include <machine/cputypes.h>
513a514b87SHasso Tepper #include <machine/md_var.h>
523a514b87SHasso Tepper
53c000328cSSepherosa Ziehau #include "cpu_if.h"
54c000328cSSepherosa Ziehau
55680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_TM_STATUS __BIT64(0)
56680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_TM_STATUS_LOG __BIT64(1)
57680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_PROCHOT __BIT64(2)
58680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_PROCHOT_LOG __BIT64(3)
59680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_CRIT __BIT64(4)
60680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_CRIT_LOG __BIT64(5)
61680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_THRESH1 __BIT64(6)
62680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_THRESH1_LOG __BIT64(7)
63680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_THRESH2 __BIT64(8)
64680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_THRESH2_LOG __BIT64(9)
65680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_PWRLIM __BIT64(10)
66680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_PWRLIM_LOG __BIT64(11)
67680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_READ __BITS64(16, 22)
68680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_RES __BITS64(27, 30)
69680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_READ_VALID __BIT64(31)
70680d36f5SSepherosa Ziehau
71680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_HAS_STATUS(msr) \
72680d36f5SSepherosa Ziehau (((msr) & (MSR_THERM_STATUS_TM_STATUS | MSR_THERM_STATUS_TM_STATUS_LOG)) ==\
73680d36f5SSepherosa Ziehau (MSR_THERM_STATUS_TM_STATUS | MSR_THERM_STATUS_TM_STATUS_LOG))
74680d36f5SSepherosa Ziehau
75680d36f5SSepherosa Ziehau #define MSR_THERM_STATUS_IS_CRITICAL(msr) \
76680d36f5SSepherosa Ziehau (((msr) & (MSR_THERM_STATUS_CRIT | MSR_THERM_STATUS_CRIT_LOG)) == \
77680d36f5SSepherosa Ziehau (MSR_THERM_STATUS_CRIT | MSR_THERM_STATUS_CRIT_LOG))
78680d36f5SSepherosa Ziehau
7985843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_TM_STATUS __BIT64(0)
8085843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_TM_STATUS_LOG __BIT64(1)
8185843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_PROCHOT __BIT64(2)
8285843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_PROCHOT_LOG __BIT64(3)
8385843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_CRIT __BIT64(4)
8485843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_CRIT_LOG __BIT64(5)
8585843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_THRESH1 __BIT64(6)
8685843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_THRESH1_LOG __BIT64(7)
8785843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_THRESH2 __BIT64(8)
8885843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_THRESH2_LOG __BIT64(9)
8985843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_PWRLIM __BIT64(10)
9085843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_PWRLIM_LOG __BIT64(11)
9185843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_READ __BITS64(16, 22)
9285843744SSepherosa Ziehau
9385843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_HAS_STATUS(msr) \
9485843744SSepherosa Ziehau (((msr) & (MSR_PKGTM_STATUS_TM_STATUS | MSR_PKGTM_STATUS_TM_STATUS_LOG)) ==\
9585843744SSepherosa Ziehau (MSR_PKGTM_STATUS_TM_STATUS | MSR_PKGTM_STATUS_TM_STATUS_LOG))
9685843744SSepherosa Ziehau
9785843744SSepherosa Ziehau #define MSR_PKGTM_STATUS_IS_CRITICAL(msr) \
9885843744SSepherosa Ziehau (((msr) & (MSR_PKGTM_STATUS_CRIT | MSR_PKGTM_STATUS_CRIT_LOG)) == \
9985843744SSepherosa Ziehau (MSR_PKGTM_STATUS_CRIT | MSR_PKGTM_STATUS_CRIT_LOG))
10085843744SSepherosa Ziehau
10185843744SSepherosa Ziehau #define CORETEMP_TEMP_INVALID -1
10285843744SSepherosa Ziehau
103056f320bSSepherosa Ziehau struct coretemp_sensor {
104c000328cSSepherosa Ziehau struct ksensordev *c_sensdev;
105056f320bSSepherosa Ziehau struct ksensor c_sens;
106056f320bSSepherosa Ziehau };
107056f320bSSepherosa Ziehau
1083a514b87SHasso Tepper struct coretemp_softc {
1093a514b87SHasso Tepper device_t sc_dev;
1103a514b87SHasso Tepper int sc_tjmax;
111ce72fc09SSepherosa Ziehau
112056f320bSSepherosa Ziehau int sc_nsens;
113056f320bSSepherosa Ziehau struct coretemp_sensor *sc_sens;
11485843744SSepherosa Ziehau struct coretemp_sensor *sc_pkg_sens;
115056f320bSSepherosa Ziehau
1164c79bfdaSSepherosa Ziehau struct sensor_task *sc_senstask;
117ce72fc09SSepherosa Ziehau int sc_cpu;
118ce72fc09SSepherosa Ziehau volatile uint32_t sc_flags; /* CORETEMP_FLAG_ */
119ce72fc09SSepherosa Ziehau volatile uint64_t sc_msr;
12085843744SSepherosa Ziehau volatile uint64_t sc_pkg_msr;
1213a514b87SHasso Tepper };
1223a514b87SHasso Tepper
12318df9562SSepherosa Ziehau #define CORETEMP_FLAG_CRIT 0x4
12485843744SSepherosa Ziehau #define CORETEMP_FLAG_PKGCRIT 0x8
12585843744SSepherosa Ziehau
12685843744SSepherosa Ziehau #define CORETEMP_HAS_PKGSENSOR(sc) ((sc)->sc_pkg_sens != NULL)
127ce72fc09SSepherosa Ziehau
1283a514b87SHasso Tepper /*
1293a514b87SHasso Tepper * Device methods.
1303a514b87SHasso Tepper */
1313a514b87SHasso Tepper static void coretemp_identify(driver_t *driver, device_t parent);
1323a514b87SHasso Tepper static int coretemp_probe(device_t dev);
1333a514b87SHasso Tepper static int coretemp_attach(device_t dev);
1343a514b87SHasso Tepper static int coretemp_detach(device_t dev);
1353a514b87SHasso Tepper
1364c79bfdaSSepherosa Ziehau static void coretemp_msr_fetch(struct coretemp_softc *sc, uint64_t *msr,
13785843744SSepherosa Ziehau uint64_t *pkg_msr);
13885843744SSepherosa Ziehau static int coretemp_msr_temp(struct coretemp_softc *sc, uint64_t msr);
13985843744SSepherosa Ziehau static void coretemp_sensor_update(struct coretemp_softc *sc, int temp);
14085843744SSepherosa Ziehau static void coretemp_sensor_task(void *arg);
14185843744SSepherosa Ziehau
14285843744SSepherosa Ziehau static void coretemp_pkg_sensor_task(void *arg);
14385843744SSepherosa Ziehau static void coretemp_pkg_sensor_update(struct coretemp_softc *sc, int temp);
14485843744SSepherosa Ziehau static int coretemp_pkg_msr_temp(struct coretemp_softc *sc, uint64_t msr);
1453a514b87SHasso Tepper
1463a514b87SHasso Tepper static device_method_t coretemp_methods[] = {
1473a514b87SHasso Tepper /* Device interface */
1483a514b87SHasso Tepper DEVMETHOD(device_identify, coretemp_identify),
1493a514b87SHasso Tepper DEVMETHOD(device_probe, coretemp_probe),
1503a514b87SHasso Tepper DEVMETHOD(device_attach, coretemp_attach),
1513a514b87SHasso Tepper DEVMETHOD(device_detach, coretemp_detach),
1523a514b87SHasso Tepper
153d3c9c58eSSascha Wildner DEVMETHOD_END
1543a514b87SHasso Tepper };
1553a514b87SHasso Tepper
1563a514b87SHasso Tepper static driver_t coretemp_driver = {
1573a514b87SHasso Tepper "coretemp",
1583a514b87SHasso Tepper coretemp_methods,
1593a514b87SHasso Tepper sizeof(struct coretemp_softc),
1603a514b87SHasso Tepper };
1613a514b87SHasso Tepper
1623a514b87SHasso Tepper static devclass_t coretemp_devclass;
1633a514b87SHasso Tepper DRIVER_MODULE(coretemp, cpu, coretemp_driver, coretemp_devclass, NULL, NULL);
16400961cb1SSascha Wildner MODULE_VERSION(coretemp, 1);
1653a514b87SHasso Tepper
16685843744SSepherosa Ziehau static __inline void
coretemp_sensor_set(struct ksensor * sens,const struct coretemp_softc * sc,uint32_t crit_flag,int temp)16785843744SSepherosa Ziehau coretemp_sensor_set(struct ksensor *sens, const struct coretemp_softc *sc,
16885843744SSepherosa Ziehau uint32_t crit_flag, int temp)
16985843744SSepherosa Ziehau {
1707273d7b8SSepherosa Ziehau enum sensor_status status;
1717273d7b8SSepherosa Ziehau
17285843744SSepherosa Ziehau if (sc->sc_flags & crit_flag)
1737273d7b8SSepherosa Ziehau status = SENSOR_S_CRIT;
17485843744SSepherosa Ziehau else
1757273d7b8SSepherosa Ziehau status = SENSOR_S_OK;
1767273d7b8SSepherosa Ziehau sensor_set_temp_degc(sens, temp, status);
17785843744SSepherosa Ziehau }
17885843744SSepherosa Ziehau
1793a514b87SHasso Tepper static void
coretemp_identify(driver_t * driver,device_t parent)1803a514b87SHasso Tepper coretemp_identify(driver_t *driver, device_t parent)
1813a514b87SHasso Tepper {
1823a514b87SHasso Tepper device_t child;
1833a514b87SHasso Tepper
1843a514b87SHasso Tepper /* Make sure we're not being doubly invoked. */
1853a514b87SHasso Tepper if (device_find_child(parent, "coretemp", -1) != NULL)
1863a514b87SHasso Tepper return;
1873a514b87SHasso Tepper
188e99c31a3SSepherosa Ziehau /* Check that the vendor is Intel. */
189e99c31a3SSepherosa Ziehau if (cpu_vendor_id != CPU_VENDOR_INTEL)
1903a514b87SHasso Tepper return;
191e99c31a3SSepherosa Ziehau
1923a514b87SHasso Tepper /*
193e99c31a3SSepherosa Ziehau * Some Intel CPUs, namely the PIII, don't have thermal sensors,
194e99c31a3SSepherosa Ziehau * but report them in cpu_thermal_feature. This leads to a later
195e99c31a3SSepherosa Ziehau * GPF when the sensor is queried via a MSR, so we stop here.
1963a514b87SHasso Tepper */
197e99c31a3SSepherosa Ziehau if (CPUID_TO_MODEL(cpu_id) < 0xe)
198e99c31a3SSepherosa Ziehau return;
199e99c31a3SSepherosa Ziehau
200e99c31a3SSepherosa Ziehau if ((cpu_thermal_feature & CPUID_THERMAL_SENSOR) == 0)
2013a514b87SHasso Tepper return;
2023a514b87SHasso Tepper
2033a514b87SHasso Tepper /*
2043a514b87SHasso Tepper * We add a child for each CPU since settings must be performed
2053a514b87SHasso Tepper * on each CPU in the SMP case.
2063a514b87SHasso Tepper */
2073a514b87SHasso Tepper child = device_add_child(parent, "coretemp", -1);
2083a514b87SHasso Tepper if (child == NULL)
2093a514b87SHasso Tepper device_printf(parent, "add coretemp child failed\n");
2103a514b87SHasso Tepper }
2113a514b87SHasso Tepper
2123a514b87SHasso Tepper static int
coretemp_probe(device_t dev)2133a514b87SHasso Tepper coretemp_probe(device_t dev)
2143a514b87SHasso Tepper {
2153a514b87SHasso Tepper if (resource_disabled("coretemp", 0))
2163a514b87SHasso Tepper return (ENXIO);
2173a514b87SHasso Tepper
2183a514b87SHasso Tepper device_set_desc(dev, "CPU On-Die Thermal Sensors");
2193a514b87SHasso Tepper
2203a514b87SHasso Tepper return (BUS_PROBE_GENERIC);
2213a514b87SHasso Tepper }
2223a514b87SHasso Tepper
2233a514b87SHasso Tepper static int
coretemp_attach(device_t dev)2243a514b87SHasso Tepper coretemp_attach(device_t dev)
2253a514b87SHasso Tepper {
2263a514b87SHasso Tepper struct coretemp_softc *sc = device_get_softc(dev);
227056f320bSSepherosa Ziehau const struct cpu_node *node, *start_node;
228056f320bSSepherosa Ziehau cpumask_t cpu_mask;
2293a514b87SHasso Tepper device_t pdev;
2303a514b87SHasso Tepper uint64_t msr;
231575aab54SSascha Wildner int cpu_model, cpu_stepping;
232056f320bSSepherosa Ziehau int ret, tjtarget, cpu, sens_idx;
23385843744SSepherosa Ziehau int master_cpu;
23485843744SSepherosa Ziehau struct coretemp_sensor *csens;
235c000328cSSepherosa Ziehau boolean_t sens_task = FALSE;
2363a514b87SHasso Tepper
2373a514b87SHasso Tepper sc->sc_dev = dev;
2383a514b87SHasso Tepper pdev = device_get_parent(dev);
239575aab54SSascha Wildner cpu_model = CPUID_TO_MODEL(cpu_id);
240575aab54SSascha Wildner cpu_stepping = cpu_id & CPUID_STEPPING;
241575aab54SSascha Wildner
242013ec85cSSepherosa Ziehau #if 0
243013ec85cSSepherosa Ziehau /*
244575aab54SSascha Wildner * XXXrpaulo: I have this CPU model and when it returns from C3
245575aab54SSascha Wildner * coretemp continues to function properly.
246575aab54SSascha Wildner */
2473a514b87SHasso Tepper
2483a514b87SHasso Tepper /*
2493a514b87SHasso Tepper * Check for errata AE18.
2503a514b87SHasso Tepper * "Processor Digital Thermal Sensor (DTS) Readout stops
2513a514b87SHasso Tepper * updating upon returning from C3/C4 state."
2523a514b87SHasso Tepper *
2533a514b87SHasso Tepper * Adapted from the Linux coretemp driver.
2543a514b87SHasso Tepper */
255575aab54SSascha Wildner if (cpu_model == 0xe && cpu_stepping < 0xc) {
2563a514b87SHasso Tepper msr = rdmsr(MSR_BIOS_SIGN);
2573a514b87SHasso Tepper msr = msr >> 32;
2583a514b87SHasso Tepper if (msr < 0x39) {
2593a514b87SHasso Tepper device_printf(dev, "not supported (Intel errata "
2603a514b87SHasso Tepper "AE18), try updating your BIOS\n");
2613a514b87SHasso Tepper return (ENXIO);
2623a514b87SHasso Tepper }
2633a514b87SHasso Tepper }
264575aab54SSascha Wildner #endif
265575aab54SSascha Wildner
266575aab54SSascha Wildner /*
267575aab54SSascha Wildner * Use 100C as the initial value.
268575aab54SSascha Wildner */
269575aab54SSascha Wildner sc->sc_tjmax = 100;
270575aab54SSascha Wildner
271575aab54SSascha Wildner if ((cpu_model == 0xf && cpu_stepping >= 2) || cpu_model == 0xe) {
2723a514b87SHasso Tepper /*
2733a514b87SHasso Tepper * On some Core 2 CPUs, there's an undocumented MSR that
2743a514b87SHasso Tepper * can tell us if Tj(max) is 100 or 85.
2753a514b87SHasso Tepper *
276056f320bSSepherosa Ziehau * The if-clause for CPUs having the MSR_IA32_EXT_CONFIG
277056f320bSSepherosa Ziehau * was adapted from the Linux coretemp driver.
2783a514b87SHasso Tepper */
2793a514b87SHasso Tepper msr = rdmsr(MSR_IA32_EXT_CONFIG);
2803a514b87SHasso Tepper if (msr & (1 << 30))
2813a514b87SHasso Tepper sc->sc_tjmax = 85;
282575aab54SSascha Wildner } else if (cpu_model == 0x17) {
283575aab54SSascha Wildner switch (cpu_stepping) {
284575aab54SSascha Wildner case 0x6: /* Mobile Core 2 Duo */
285575aab54SSascha Wildner sc->sc_tjmax = 105;
286575aab54SSascha Wildner break;
287575aab54SSascha Wildner default: /* Unknown stepping */
288575aab54SSascha Wildner break;
2893a514b87SHasso Tepper }
290575aab54SSascha Wildner } else if (cpu_model == 0x1c) {
291575aab54SSascha Wildner switch (cpu_stepping) {
292575aab54SSascha Wildner case 0xa: /* 45nm Atom D400, N400 and D500 series */
293575aab54SSascha Wildner sc->sc_tjmax = 100;
294575aab54SSascha Wildner break;
295575aab54SSascha Wildner default:
296575aab54SSascha Wildner sc->sc_tjmax = 90;
297575aab54SSascha Wildner break;
298575aab54SSascha Wildner }
299575aab54SSascha Wildner } else {
300575aab54SSascha Wildner /*
301575aab54SSascha Wildner * Attempt to get Tj(max) from MSR IA32_TEMPERATURE_TARGET.
302575aab54SSascha Wildner *
303575aab54SSascha Wildner * This method is described in Intel white paper "CPU
304575aab54SSascha Wildner * Monitoring With DTS/PECI". (#322683)
305575aab54SSascha Wildner */
306575aab54SSascha Wildner ret = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &msr);
307575aab54SSascha Wildner if (ret == 0) {
308575aab54SSascha Wildner tjtarget = (msr >> 16) & 0xff;
309575aab54SSascha Wildner
310575aab54SSascha Wildner /*
311575aab54SSascha Wildner * On earlier generation of processors, the value
312575aab54SSascha Wildner * obtained from IA32_TEMPERATURE_TARGET register is
313575aab54SSascha Wildner * an offset that needs to be summed with a model
314575aab54SSascha Wildner * specific base. It is however not clear what
315575aab54SSascha Wildner * these numbers are, with the publicly available
316575aab54SSascha Wildner * documents from Intel.
317575aab54SSascha Wildner *
31882844f50SSepherosa Ziehau * For now, we consider [70, 110]C range, as
319575aab54SSascha Wildner * described in #322683, as "reasonable" and accept
320575aab54SSascha Wildner * these values whenever the MSR is available for
321575aab54SSascha Wildner * read, regardless the CPU model.
322575aab54SSascha Wildner */
32382844f50SSepherosa Ziehau if (tjtarget >= 70 && tjtarget <= 110)
324575aab54SSascha Wildner sc->sc_tjmax = tjtarget;
325575aab54SSascha Wildner else
326575aab54SSascha Wildner device_printf(dev, "Tj(target) value %d "
327575aab54SSascha Wildner "does not seem right.\n", tjtarget);
328575aab54SSascha Wildner } else
329575aab54SSascha Wildner device_printf(dev, "Can not get Tj(target) "
330575aab54SSascha Wildner "from your CPU, using 100C.\n");
331575aab54SSascha Wildner }
332575aab54SSascha Wildner
333575aab54SSascha Wildner if (bootverbose)
334575aab54SSascha Wildner device_printf(dev, "Setting TjMax=%d\n", sc->sc_tjmax);
3353a514b87SHasso Tepper
336ce72fc09SSepherosa Ziehau sc->sc_cpu = device_get_unit(device_get_parent(dev));
337ce72fc09SSepherosa Ziehau
338056f320bSSepherosa Ziehau start_node = get_cpu_node_by_cpuid(sc->sc_cpu);
339056f320bSSepherosa Ziehau
340056f320bSSepherosa Ziehau node = start_node;
341056f320bSSepherosa Ziehau while (node != NULL) {
34261e47a39SSepherosa Ziehau if (node->type == CORE_LEVEL) {
34361e47a39SSepherosa Ziehau if (node->child_no == 0)
34461e47a39SSepherosa Ziehau node = NULL;
345056f320bSSepherosa Ziehau break;
34661e47a39SSepherosa Ziehau }
347056f320bSSepherosa Ziehau node = node->parent_node;
348056f320bSSepherosa Ziehau }
349056f320bSSepherosa Ziehau if (node != NULL) {
35085843744SSepherosa Ziehau master_cpu = BSRCPUMASK(node->members);
351056f320bSSepherosa Ziehau if (bootverbose) {
352056f320bSSepherosa Ziehau device_printf(dev, "master cpu%d, count %u\n",
353056f320bSSepherosa Ziehau master_cpu, node->child_no);
354056f320bSSepherosa Ziehau }
355056f320bSSepherosa Ziehau if (sc->sc_cpu != master_cpu)
356056f320bSSepherosa Ziehau return (0);
357056f320bSSepherosa Ziehau
358056f320bSSepherosa Ziehau KKASSERT(node->child_no > 0);
359056f320bSSepherosa Ziehau sc->sc_nsens = node->child_no;
360056f320bSSepherosa Ziehau cpu_mask = node->members;
361056f320bSSepherosa Ziehau } else {
362056f320bSSepherosa Ziehau sc->sc_nsens = 1;
363056f320bSSepherosa Ziehau CPUMASK_ASSBIT(cpu_mask, sc->sc_cpu);
364056f320bSSepherosa Ziehau }
365056f320bSSepherosa Ziehau sc->sc_sens = kmalloc(sizeof(struct coretemp_sensor) * sc->sc_nsens,
366056f320bSSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO);
367056f320bSSepherosa Ziehau
368056f320bSSepherosa Ziehau sens_idx = 0;
369056f320bSSepherosa Ziehau CPUSET_FOREACH(cpu, cpu_mask) {
370c000328cSSepherosa Ziehau device_t cpu_dev;
371c000328cSSepherosa Ziehau
372c000328cSSepherosa Ziehau cpu_dev = devclass_find_unit("cpu", cpu);
373c000328cSSepherosa Ziehau if (cpu_dev == NULL)
374c000328cSSepherosa Ziehau continue;
375c000328cSSepherosa Ziehau
376056f320bSSepherosa Ziehau KKASSERT(sens_idx < sc->sc_nsens);
377056f320bSSepherosa Ziehau csens = &sc->sc_sens[sens_idx];
378056f320bSSepherosa Ziehau
379c000328cSSepherosa Ziehau csens->c_sensdev = CPU_GET_SENSDEV(cpu_dev);
380c000328cSSepherosa Ziehau if (csens->c_sensdev == NULL)
381c000328cSSepherosa Ziehau continue;
382c000328cSSepherosa Ziehau
3833a514b87SHasso Tepper /*
3843a514b87SHasso Tepper * Add hw.sensors.cpuN.temp0 MIB.
3853a514b87SHasso Tepper */
386056f320bSSepherosa Ziehau ksnprintf(csens->c_sens.desc, sizeof(csens->c_sens.desc),
387949251baSSepherosa Ziehau "node%d core%d temp", get_chip_ID(cpu),
388056f320bSSepherosa Ziehau get_core_number_within_chip(cpu));
389056f320bSSepherosa Ziehau csens->c_sens.type = SENSOR_TEMP;
3907273d7b8SSepherosa Ziehau sensor_set_unknown(&csens->c_sens);
391c000328cSSepherosa Ziehau sensor_attach(csens->c_sensdev, &csens->c_sens);
392056f320bSSepherosa Ziehau
393056f320bSSepherosa Ziehau ++sens_idx;
394056f320bSSepherosa Ziehau }
39585843744SSepherosa Ziehau
396c000328cSSepherosa Ziehau if (sens_idx == 0) {
397c000328cSSepherosa Ziehau kfree(sc->sc_sens, M_DEVBUF);
398c000328cSSepherosa Ziehau sc->sc_sens = NULL;
399c000328cSSepherosa Ziehau sc->sc_nsens = 0;
400c000328cSSepherosa Ziehau } else {
401c000328cSSepherosa Ziehau sens_task = TRUE;
402c000328cSSepherosa Ziehau }
403c000328cSSepherosa Ziehau
40485843744SSepherosa Ziehau if (cpu_thermal_feature & CPUID_THERMAL_PTM) {
40585843744SSepherosa Ziehau boolean_t pkg_sens = TRUE;
40685843744SSepherosa Ziehau
40785843744SSepherosa Ziehau /*
40885843744SSepherosa Ziehau * Package thermal sensor
40985843744SSepherosa Ziehau */
41085843744SSepherosa Ziehau
41185843744SSepherosa Ziehau node = start_node;
41285843744SSepherosa Ziehau while (node != NULL) {
41385843744SSepherosa Ziehau if (node->type == CHIP_LEVEL) {
41485843744SSepherosa Ziehau if (node->child_no == 0)
41585843744SSepherosa Ziehau node = NULL;
41685843744SSepherosa Ziehau break;
41785843744SSepherosa Ziehau }
41885843744SSepherosa Ziehau node = node->parent_node;
41985843744SSepherosa Ziehau }
42085843744SSepherosa Ziehau if (node != NULL) {
42185843744SSepherosa Ziehau master_cpu = BSRCPUMASK(node->members);
42285843744SSepherosa Ziehau if (bootverbose) {
42385843744SSepherosa Ziehau device_printf(dev, "pkg master cpu%d\n",
42485843744SSepherosa Ziehau master_cpu);
42585843744SSepherosa Ziehau }
42685843744SSepherosa Ziehau if (sc->sc_cpu != master_cpu)
42785843744SSepherosa Ziehau pkg_sens = FALSE;
42885843744SSepherosa Ziehau }
42985843744SSepherosa Ziehau
43085843744SSepherosa Ziehau if (pkg_sens) {
43185843744SSepherosa Ziehau csens = sc->sc_pkg_sens =
43285843744SSepherosa Ziehau kmalloc(sizeof(struct coretemp_sensor), M_DEVBUF,
43385843744SSepherosa Ziehau M_WAITOK | M_ZERO);
434c000328cSSepherosa Ziehau csens->c_sensdev = kmalloc(sizeof(struct ksensordev),
435c000328cSSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO);
43685843744SSepherosa Ziehau
43785843744SSepherosa Ziehau /*
43885843744SSepherosa Ziehau * Add hw.sensors.cpu_nodeN.temp0 MIB.
43985843744SSepherosa Ziehau */
440c000328cSSepherosa Ziehau ksnprintf(csens->c_sensdev->xname,
441c000328cSSepherosa Ziehau sizeof(csens->c_sensdev->xname), "cpu_node%d",
44285843744SSepherosa Ziehau get_chip_ID(sc->sc_cpu));
44385843744SSepherosa Ziehau ksnprintf(csens->c_sens.desc,
444949251baSSepherosa Ziehau sizeof(csens->c_sens.desc), "node%d temp",
44585843744SSepherosa Ziehau get_chip_ID(sc->sc_cpu));
44685843744SSepherosa Ziehau csens->c_sens.type = SENSOR_TEMP;
4477273d7b8SSepherosa Ziehau sensor_set_unknown(&csens->c_sens);
448c000328cSSepherosa Ziehau sensor_attach(csens->c_sensdev, &csens->c_sens);
449c000328cSSepherosa Ziehau sensordev_install(csens->c_sensdev);
450c000328cSSepherosa Ziehau
451c000328cSSepherosa Ziehau sens_task = TRUE;
45285843744SSepherosa Ziehau }
45385843744SSepherosa Ziehau }
45485843744SSepherosa Ziehau
455c000328cSSepherosa Ziehau if (sens_task) {
4564c79bfdaSSepherosa Ziehau if (CORETEMP_HAS_PKGSENSOR(sc)) {
4574c79bfdaSSepherosa Ziehau sc->sc_senstask = sensor_task_register2(sc,
4584c79bfdaSSepherosa Ziehau coretemp_pkg_sensor_task, 2, sc->sc_cpu);
4594c79bfdaSSepherosa Ziehau } else {
460c000328cSSepherosa Ziehau KASSERT(sc->sc_sens != NULL, ("no sensors"));
4614c79bfdaSSepherosa Ziehau sc->sc_senstask = sensor_task_register2(sc,
4624c79bfdaSSepherosa Ziehau coretemp_sensor_task, 2, sc->sc_cpu);
4634c79bfdaSSepherosa Ziehau }
464c000328cSSepherosa Ziehau }
4653a514b87SHasso Tepper
4663a514b87SHasso Tepper return (0);
4673a514b87SHasso Tepper }
4683a514b87SHasso Tepper
4693a514b87SHasso Tepper static int
coretemp_detach(device_t dev)4703a514b87SHasso Tepper coretemp_detach(device_t dev)
4713a514b87SHasso Tepper {
4723a514b87SHasso Tepper struct coretemp_softc *sc = device_get_softc(dev);
473c000328cSSepherosa Ziehau struct coretemp_sensor *csens;
474c000328cSSepherosa Ziehau
475c000328cSSepherosa Ziehau if (sc->sc_senstask != NULL)
476c000328cSSepherosa Ziehau sensor_task_unregister2(sc->sc_senstask);
4773a514b87SHasso Tepper
478056f320bSSepherosa Ziehau if (sc->sc_nsens > 0) {
479056f320bSSepherosa Ziehau int i;
4803a514b87SHasso Tepper
481c000328cSSepherosa Ziehau for (i = 0; i < sc->sc_nsens; ++i) {
482c000328cSSepherosa Ziehau csens = &sc->sc_sens[i];
483c000328cSSepherosa Ziehau if (csens->c_sensdev == NULL)
484c000328cSSepherosa Ziehau continue;
485c000328cSSepherosa Ziehau sensor_detach(csens->c_sensdev, &csens->c_sens);
486c000328cSSepherosa Ziehau }
487056f320bSSepherosa Ziehau kfree(sc->sc_sens, M_DEVBUF);
488c000328cSSepherosa Ziehau }
48985843744SSepherosa Ziehau
49085843744SSepherosa Ziehau if (sc->sc_pkg_sens != NULL) {
491c000328cSSepherosa Ziehau csens = sc->sc_pkg_sens;
492c000328cSSepherosa Ziehau sensordev_deinstall(csens->c_sensdev);
493c000328cSSepherosa Ziehau kfree(csens->c_sensdev, M_DEVBUF);
494c000328cSSepherosa Ziehau kfree(csens, M_DEVBUF);
495056f320bSSepherosa Ziehau }
4963a514b87SHasso Tepper return (0);
4973a514b87SHasso Tepper }
4983a514b87SHasso Tepper
49985843744SSepherosa Ziehau static int
coretemp_msr_temp(struct coretemp_softc * sc,uint64_t msr)50085843744SSepherosa Ziehau coretemp_msr_temp(struct coretemp_softc *sc, uint64_t msr)
50185843744SSepherosa Ziehau {
50285843744SSepherosa Ziehau int temp;
5033a514b87SHasso Tepper
5043a514b87SHasso Tepper /*
5053a514b87SHasso Tepper * Check for Thermal Status and Thermal Status Log.
5063a514b87SHasso Tepper */
507680d36f5SSepherosa Ziehau if (MSR_THERM_STATUS_HAS_STATUS(msr))
50885843744SSepherosa Ziehau device_printf(sc->sc_dev, "PROCHOT asserted\n");
5093a514b87SHasso Tepper
510680d36f5SSepherosa Ziehau if (msr & MSR_THERM_STATUS_READ_VALID)
511680d36f5SSepherosa Ziehau temp = sc->sc_tjmax - __SHIFTOUT(msr, MSR_THERM_STATUS_READ);
512680d36f5SSepherosa Ziehau else
51385843744SSepherosa Ziehau temp = CORETEMP_TEMP_INVALID;
5143a514b87SHasso Tepper
5153a514b87SHasso Tepper /*
5163a514b87SHasso Tepper * Check for Critical Temperature Status and Critical
5173a514b87SHasso Tepper * Temperature Log.
5183a514b87SHasso Tepper * It doesn't really matter if the current temperature is
5193a514b87SHasso Tepper * invalid because the "Critical Temperature Log" bit will
5203a514b87SHasso Tepper * tell us if the Critical Temperature has been reached in
5213a514b87SHasso Tepper * past. It's not directly related to the current temperature.
5223a514b87SHasso Tepper *
5233a514b87SHasso Tepper * If we reach a critical level, allow devctl(4) to catch this
5243a514b87SHasso Tepper * and shutdown the system.
5253a514b87SHasso Tepper */
526680d36f5SSepherosa Ziehau if (MSR_THERM_STATUS_IS_CRITICAL(msr)) {
52718df9562SSepherosa Ziehau if ((sc->sc_flags & CORETEMP_FLAG_CRIT) == 0) {
5283f8829e8SSepherosa Ziehau char stemp[16], data[64];
52918df9562SSepherosa Ziehau
53085843744SSepherosa Ziehau device_printf(sc->sc_dev,
53185843744SSepherosa Ziehau "critical temperature detected, "
5323a514b87SHasso Tepper "suggest system shutdown\n");
5333a514b87SHasso Tepper ksnprintf(stemp, sizeof(stemp), "%d", temp);
5343f8829e8SSepherosa Ziehau ksnprintf(data, sizeof(data),
5353f8829e8SSepherosa Ziehau "notify=0xcc node=%d core=%d",
5363f8829e8SSepherosa Ziehau get_chip_ID(sc->sc_cpu),
5373f8829e8SSepherosa Ziehau get_core_number_within_chip(sc->sc_cpu));
5383f8829e8SSepherosa Ziehau devctl_notify("coretemp", "Thermal", stemp, data);
5394c79bfdaSSepherosa Ziehau sc->sc_flags |= CORETEMP_FLAG_CRIT;
54018df9562SSepherosa Ziehau }
54118df9562SSepherosa Ziehau } else if (sc->sc_flags & CORETEMP_FLAG_CRIT) {
5424c79bfdaSSepherosa Ziehau sc->sc_flags &= ~CORETEMP_FLAG_CRIT;
5433a514b87SHasso Tepper }
5443a514b87SHasso Tepper
54585843744SSepherosa Ziehau return temp;
546ce72fc09SSepherosa Ziehau }
547ce72fc09SSepherosa Ziehau
54885843744SSepherosa Ziehau static int
coretemp_pkg_msr_temp(struct coretemp_softc * sc,uint64_t msr)54985843744SSepherosa Ziehau coretemp_pkg_msr_temp(struct coretemp_softc *sc, uint64_t msr)
55085843744SSepherosa Ziehau {
55185843744SSepherosa Ziehau int temp;
55285843744SSepherosa Ziehau
55385843744SSepherosa Ziehau /*
55485843744SSepherosa Ziehau * Check for Thermal Status and Thermal Status Log.
55585843744SSepherosa Ziehau */
55685843744SSepherosa Ziehau if (MSR_PKGTM_STATUS_HAS_STATUS(msr))
55785843744SSepherosa Ziehau device_printf(sc->sc_dev, "package PROCHOT asserted\n");
55885843744SSepherosa Ziehau
55985843744SSepherosa Ziehau temp = sc->sc_tjmax - __SHIFTOUT(msr, MSR_PKGTM_STATUS_READ);
56085843744SSepherosa Ziehau
56185843744SSepherosa Ziehau /*
56285843744SSepherosa Ziehau * Check for Critical Temperature Status and Critical
56385843744SSepherosa Ziehau * Temperature Log.
56485843744SSepherosa Ziehau * It doesn't really matter if the current temperature is
56585843744SSepherosa Ziehau * invalid because the "Critical Temperature Log" bit will
56685843744SSepherosa Ziehau * tell us if the Critical Temperature has been reached in
56785843744SSepherosa Ziehau * past. It's not directly related to the current temperature.
56885843744SSepherosa Ziehau *
56985843744SSepherosa Ziehau * If we reach a critical level, allow devctl(4) to catch this
57085843744SSepherosa Ziehau * and shutdown the system.
57185843744SSepherosa Ziehau */
57285843744SSepherosa Ziehau if (MSR_PKGTM_STATUS_IS_CRITICAL(msr)) {
57385843744SSepherosa Ziehau if ((sc->sc_flags & CORETEMP_FLAG_PKGCRIT) == 0) {
5743f8829e8SSepherosa Ziehau char stemp[16], data[64];
57585843744SSepherosa Ziehau
57685843744SSepherosa Ziehau device_printf(sc->sc_dev,
57785843744SSepherosa Ziehau "critical temperature detected, "
57885843744SSepherosa Ziehau "suggest system shutdown\n");
57985843744SSepherosa Ziehau ksnprintf(stemp, sizeof(stemp), "%d", temp);
5803f8829e8SSepherosa Ziehau ksnprintf(data, sizeof(data), "notify=0xcc node=%d",
5813f8829e8SSepherosa Ziehau get_chip_ID(sc->sc_cpu));
5823f8829e8SSepherosa Ziehau devctl_notify("coretemp", "Thermal", stemp, data);
5834c79bfdaSSepherosa Ziehau sc->sc_flags |= CORETEMP_FLAG_PKGCRIT;
58485843744SSepherosa Ziehau }
58585843744SSepherosa Ziehau } else if (sc->sc_flags & CORETEMP_FLAG_PKGCRIT) {
5864c79bfdaSSepherosa Ziehau sc->sc_flags &= ~CORETEMP_FLAG_PKGCRIT;
58785843744SSepherosa Ziehau }
58885843744SSepherosa Ziehau
58985843744SSepherosa Ziehau return temp;
59085843744SSepherosa Ziehau }
59185843744SSepherosa Ziehau
5924c79bfdaSSepherosa Ziehau static void
coretemp_msr_fetch(struct coretemp_softc * sc,uint64_t * msr,uint64_t * pkg_msr)59385843744SSepherosa Ziehau coretemp_msr_fetch(struct coretemp_softc *sc, uint64_t *msr, uint64_t *pkg_msr)
59485843744SSepherosa Ziehau {
5954c79bfdaSSepherosa Ziehau KASSERT(sc->sc_cpu == mycpuid,
5964c79bfdaSSepherosa Ziehau ("%s not on the target cpu%d, but on %d",
5974c79bfdaSSepherosa Ziehau device_get_name(sc->sc_dev), sc->sc_cpu, mycpuid));
5984c79bfdaSSepherosa Ziehau
59985843744SSepherosa Ziehau *msr = rdmsr(MSR_THERM_STATUS);
60085843744SSepherosa Ziehau if (pkg_msr != NULL)
60185843744SSepherosa Ziehau *pkg_msr = rdmsr(MSR_PKG_THERM_STATUS);
60285843744SSepherosa Ziehau }
6033a514b87SHasso Tepper
6043a514b87SHasso Tepper static void
coretemp_sensor_update(struct coretemp_softc * sc,int temp)60585843744SSepherosa Ziehau coretemp_sensor_update(struct coretemp_softc *sc, int temp)
6063a514b87SHasso Tepper {
607c000328cSSepherosa Ziehau struct coretemp_sensor *csens;
60885843744SSepherosa Ziehau int i;
6093a514b87SHasso Tepper
610c000328cSSepherosa Ziehau if (sc->sc_sens == NULL)
611c000328cSSepherosa Ziehau return;
612c000328cSSepherosa Ziehau
6134c79bfdaSSepherosa Ziehau if (temp == CORETEMP_TEMP_INVALID) {
614c000328cSSepherosa Ziehau for (i = 0; i < sc->sc_nsens; ++i) {
615c000328cSSepherosa Ziehau csens = &sc->sc_sens[i];
616c000328cSSepherosa Ziehau if (csens->c_sensdev == NULL)
617c000328cSSepherosa Ziehau continue;
618c000328cSSepherosa Ziehau sensor_set_invalid(&csens->c_sens);
619c000328cSSepherosa Ziehau }
6203a514b87SHasso Tepper } else {
621056f320bSSepherosa Ziehau for (i = 0; i < sc->sc_nsens; ++i) {
622c000328cSSepherosa Ziehau csens = &sc->sc_sens[i];
623c000328cSSepherosa Ziehau if (csens->c_sensdev == NULL)
624c000328cSSepherosa Ziehau continue;
625c000328cSSepherosa Ziehau coretemp_sensor_set(&csens->c_sens, sc,
62685843744SSepherosa Ziehau CORETEMP_FLAG_CRIT, temp);
62785843744SSepherosa Ziehau }
62885843744SSepherosa Ziehau }
62985843744SSepherosa Ziehau }
63085843744SSepherosa Ziehau
63185843744SSepherosa Ziehau static void
coretemp_pkg_sensor_update(struct coretemp_softc * sc,int temp)63285843744SSepherosa Ziehau coretemp_pkg_sensor_update(struct coretemp_softc *sc, int temp)
63385843744SSepherosa Ziehau {
63485843744SSepherosa Ziehau KKASSERT(sc->sc_pkg_sens != NULL);
6354c79bfdaSSepherosa Ziehau if (temp == CORETEMP_TEMP_INVALID) {
6367273d7b8SSepherosa Ziehau sensor_set_invalid(&sc->sc_pkg_sens->c_sens);
63785843744SSepherosa Ziehau } else {
63885843744SSepherosa Ziehau coretemp_sensor_set(&sc->sc_pkg_sens->c_sens, sc,
63985843744SSepherosa Ziehau CORETEMP_FLAG_PKGCRIT, temp);
64085843744SSepherosa Ziehau }
64185843744SSepherosa Ziehau }
64285843744SSepherosa Ziehau
64385843744SSepherosa Ziehau static void
coretemp_sensor_task(void * arg)64485843744SSepherosa Ziehau coretemp_sensor_task(void *arg)
64585843744SSepherosa Ziehau {
64685843744SSepherosa Ziehau struct coretemp_softc *sc = arg;
64785843744SSepherosa Ziehau uint64_t msr;
64885843744SSepherosa Ziehau int temp;
64985843744SSepherosa Ziehau
6504c79bfdaSSepherosa Ziehau coretemp_msr_fetch(sc, &msr, NULL);
65185843744SSepherosa Ziehau temp = coretemp_msr_temp(sc, msr);
65285843744SSepherosa Ziehau
65385843744SSepherosa Ziehau coretemp_sensor_update(sc, temp);
654056f320bSSepherosa Ziehau }
65585843744SSepherosa Ziehau
65685843744SSepherosa Ziehau static void
coretemp_pkg_sensor_task(void * arg)65785843744SSepherosa Ziehau coretemp_pkg_sensor_task(void *arg)
65885843744SSepherosa Ziehau {
65985843744SSepherosa Ziehau struct coretemp_softc *sc = arg;
66085843744SSepherosa Ziehau uint64_t msr, pkg_msr;
66185843744SSepherosa Ziehau int temp, pkg_temp;
66285843744SSepherosa Ziehau
6634c79bfdaSSepherosa Ziehau coretemp_msr_fetch(sc, &msr, &pkg_msr);
66485843744SSepherosa Ziehau temp = coretemp_msr_temp(sc, msr);
66585843744SSepherosa Ziehau pkg_temp = coretemp_pkg_msr_temp(sc, pkg_msr);
66685843744SSepherosa Ziehau
66785843744SSepherosa Ziehau coretemp_sensor_update(sc, temp);
66885843744SSepherosa Ziehau coretemp_pkg_sensor_update(sc, pkg_temp);
6693a514b87SHasso Tepper }
670