1 /* $NetBSD: coretemp.c,v 1.16 2010/08/25 05:07:43 jruoho Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Juan Romero Pardines. 5 * Copyright (c) 2007 Rui Paulo <rpaulo@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sys/dev/coretemp/coretemp.c,v 1.4 2007/10/15 20:00:21 netchild Exp $ 30 * 31 */ 32 33 /* 34 * Device driver for Intel's On Die thermal sensor via MSR. 35 * First introduced in Intel's Core line of processors. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: coretemp.c,v 1.16 2010/08/25 05:07:43 jruoho Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/device.h> 43 #include <sys/kmem.h> 44 #include <sys/xcall.h> 45 #include <sys/cpu.h> 46 47 #include <dev/sysmon/sysmonvar.h> 48 49 #include <machine/cpuvar.h> 50 #include <machine/specialreg.h> 51 #include <machine/cpufunc.h> 52 53 struct coretemp_softc { 54 struct cpu_info *sc_ci; 55 struct sysmon_envsys *sc_sme; 56 envsys_data_t sc_sensor; 57 char sc_dvname[32]; 58 int sc_tjmax; 59 }; 60 61 static void coretemp_refresh(struct sysmon_envsys *, envsys_data_t *); 62 static void coretemp_refresh_xcall(void *, void *); 63 64 void 65 coretemp_register(struct cpu_info *ci) 66 { 67 struct coretemp_softc *sc; 68 uint32_t regs[4]; 69 uint64_t msr; 70 int cpumodel, cpuextmodel, cpumask; 71 72 /* 73 * Don't attach on anything but the first SMT ID. 74 */ 75 if (ci->ci_smt_id != 0) 76 return; 77 78 /* 79 * CPUID 0x06 returns 1 if the processor has on-die thermal 80 * sensors. EBX[0:3] contains the number of sensors. 81 */ 82 x86_cpuid(0x06, regs); 83 if ((regs[0] & CPUID_DSPM_DTS) == 0) 84 return; 85 86 sc = kmem_zalloc(sizeof(struct coretemp_softc), KM_NOSLEEP); 87 if (!sc) 88 return; 89 90 (void)snprintf(sc->sc_dvname, sizeof(sc->sc_dvname), "coretemp%d", 91 (int)device_unit(ci->ci_dev)); 92 cpumodel = CPUID2MODEL(ci->ci_signature); 93 /* extended model */ 94 cpuextmodel = CPUID2EXTMODEL(ci->ci_signature); 95 cpumask = ci->ci_signature & 15; 96 97 /* 98 * Check for errata AE18. 99 * "Processor Digital Thermal Sensor (DTS) Readout stops 100 * updating upon returning from C3/C4 state." 101 * 102 * Adapted from the Linux coretemp driver. 103 */ 104 if (cpumodel == 0xe && cpumask < 0xc) { 105 msr = rdmsr(MSR_BIOS_SIGN); 106 msr = msr >> 32; 107 if (msr < 0x39) { 108 aprint_debug("%s: not supported (Intel errata AE18), " 109 "try updating your BIOS\n", sc->sc_dvname); 110 goto bad; 111 } 112 } 113 114 /* 115 * On some Core 2 CPUs, there's an undocumented MSR that 116 * can tell us if Tj(max) is 100 or 85. 117 * 118 * The if-clause for CPUs having the MSR_IA32_EXT_CONFIG was adapted 119 * from the Linux coretemp driver. 120 * 121 * MSR_IA32_EXT_CONFIG is NOT safe on all CPUs 122 */ 123 sc->sc_tjmax = 100; 124 if ((cpumodel == 0xf && cpumask >= 2) || 125 (cpumodel == 0xe && cpuextmodel != 1)) { 126 msr = rdmsr(MSR_IA32_EXT_CONFIG); 127 if (msr & (1 << 30)) 128 sc->sc_tjmax = 85; 129 } 130 131 /* 132 * Check if the MSR contains thermal reading valid bit, this 133 * avoid false positives on systems that fake up a compatible 134 * CPU that doesn't have access to these MSRs; such as VMWare. 135 */ 136 msr = rdmsr(MSR_THERM_STATUS); 137 if ((msr & __BIT(31)) == 0) 138 goto bad; 139 140 sc->sc_ci = ci; 141 142 /* 143 * Only a temperature sensor and monitor for a critical state. 144 */ 145 sc->sc_sensor.units = ENVSYS_STEMP; 146 sc->sc_sensor.flags = ENVSYS_FMONCRITICAL; 147 (void)snprintf(sc->sc_sensor.desc, sizeof(sc->sc_sensor.desc), 148 "%s temperature", device_xname(ci->ci_dev)); 149 150 sc->sc_sme = sysmon_envsys_create(); 151 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { 152 sysmon_envsys_destroy(sc->sc_sme); 153 goto bad; 154 } 155 156 /* 157 * Hook into the system monitor. 158 */ 159 sc->sc_sme->sme_name = sc->sc_dvname; 160 sc->sc_sme->sme_cookie = sc; 161 sc->sc_sme->sme_refresh = coretemp_refresh; 162 163 if (sysmon_envsys_register(sc->sc_sme)) { 164 aprint_error("%s: unable to register with sysmon\n", 165 sc->sc_dvname); 166 sysmon_envsys_destroy(sc->sc_sme); 167 goto bad; 168 } 169 170 return; 171 172 bad: 173 kmem_free(sc, sizeof(struct coretemp_softc)); 174 } 175 176 static void 177 coretemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 178 { 179 struct coretemp_softc *sc = sme->sme_cookie; 180 uint64_t where; 181 182 where = xc_unicast(0, coretemp_refresh_xcall, sc, edata, sc->sc_ci); 183 xc_wait(where); 184 } 185 186 static void 187 coretemp_refresh_xcall(void *arg0, void *arg1) 188 { 189 struct coretemp_softc *sc = (struct coretemp_softc *)arg0; 190 envsys_data_t *edata = (envsys_data_t *)arg1; 191 uint64_t msr; 192 193 /* 194 * The digital temperature reading is located at bit 16 195 * of MSR_THERM_STATUS. 196 * 197 * There is a bit on that MSR that indicates whether the 198 * temperature is valid or not. 199 * 200 * The temperature is computed by subtracting the temperature 201 * reading by Tj(max). 202 */ 203 msr = rdmsr(MSR_THERM_STATUS); 204 205 /* 206 * Check for Thermal Status and Thermal Status Log. 207 */ 208 if ((msr & 0x3) == 0x3) 209 aprint_debug("%s: PROCHOT asserted\n", sc->sc_dvname); 210 211 /* 212 * Bit 31 contains "Reading valid" 213 */ 214 if (((msr >> 31) & 0x1) == 1) { 215 /* 216 * Starting on bit 16 and ending on bit 22. 217 */ 218 edata->value_cur = sc->sc_tjmax - ((msr >> 16) & 0x7f); 219 /* 220 * Convert to mK. 221 */ 222 edata->value_cur *= 1000000; 223 edata->value_cur += 273150000; 224 edata->state = ENVSYS_SVALID; 225 } else 226 edata->state = ENVSYS_SINVALID; 227 228 /* 229 * Check for Critical Temperature Status and Critical 230 * Temperature Log. 231 * It doesn't really matter if the current temperature is 232 * invalid because the "Critical Temperature Log" bit will 233 * tell us if the Critical Temperature has been reached in 234 * past. It's not directly related to the current temperature. 235 * 236 * If we reach a critical level, send a critical event to 237 * powerd(8) (if running). 238 */ 239 if (((msr >> 4) & 0x3) == 0x3) 240 edata->state = ENVSYS_SCRITICAL; 241 } 242