| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: coretemp.c,v 1.36.4.1 2020/07/15 14:02:36 martin Exp $ */ | | 1 | /* $NetBSD: coretemp.c,v 1.36.4.2 2023/07/29 11:01:14 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2011 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jukka Ruohonen. | | 8 | * by Jukka Ruohonen. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * | | 13 | * |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -51,27 +51,27 @@ | | | @@ -51,27 +51,27 @@ |
51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | 51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
53 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 53 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | | 54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | | 55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
56 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 56 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
57 | * POSSIBILITY OF SUCH DAMAGE. | | 57 | * POSSIBILITY OF SUCH DAMAGE. |
58 | * | | 58 | * |
59 | * $FreeBSD: src/sys/dev/coretemp/coretemp.c,v 1.4 2007/10/15 20:00:21 netchild Exp $ | | 59 | * $FreeBSD: src/sys/dev/coretemp/coretemp.c,v 1.4 2007/10/15 20:00:21 netchild Exp $ |
60 | * | | 60 | * |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: coretemp.c,v 1.36.4.1 2020/07/15 14:02:36 martin Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: coretemp.c,v 1.36.4.2 2023/07/29 11:01:14 martin Exp $"); |
65 | | | 65 | |
66 | #include <sys/param.h> | | 66 | #include <sys/param.h> |
67 | #include <sys/device.h> | | 67 | #include <sys/device.h> |
68 | #include <sys/cpu.h> | | 68 | #include <sys/cpu.h> |
69 | #include <sys/module.h> | | 69 | #include <sys/module.h> |
70 | #include <sys/xcall.h> | | 70 | #include <sys/xcall.h> |
71 | | | 71 | |
72 | #include <dev/sysmon/sysmonvar.h> | | 72 | #include <dev/sysmon/sysmonvar.h> |
73 | | | 73 | |
74 | #include <machine/cpuvar.h> | | 74 | #include <machine/cpuvar.h> |
75 | #include <machine/cpufunc.h> | | 75 | #include <machine/cpufunc.h> |
76 | #include <machine/cputypes.h> | | 76 | #include <machine/cputypes.h> |
77 | #include <machine/specialreg.h> | | 77 | #include <machine/specialreg.h> |
| @@ -92,26 +92,30 @@ __KERNEL_RCSID(0, "$NetBSD: coretemp.c,v | | | @@ -92,26 +92,30 @@ __KERNEL_RCSID(0, "$NetBSD: coretemp.c,v |
92 | | | 92 | |
93 | #define MSR_THERM_INTR_HITEMP __BIT(0) | | 93 | #define MSR_THERM_INTR_HITEMP __BIT(0) |
94 | #define MSR_THERM_INTR_LOTEMPT __BIT(1) | | 94 | #define MSR_THERM_INTR_LOTEMPT __BIT(1) |
95 | #define MSR_THERM_INTR_PROCHOT __BIT(2) | | 95 | #define MSR_THERM_INTR_PROCHOT __BIT(2) |
96 | #define MSR_THERM_INTR_FORCPR __BIT(3) | | 96 | #define MSR_THERM_INTR_FORCPR __BIT(3) |
97 | #define MSR_THERM_INTR_OVERHEAT __BIT(4) | | 97 | #define MSR_THERM_INTR_OVERHEAT __BIT(4) |
98 | #define MSR_THERM_INTR_TRIP1_VAL __BITS(8, 14) | | 98 | #define MSR_THERM_INTR_TRIP1_VAL __BITS(8, 14) |
99 | #define MSR_THERM_INTR_TRIP1 __BIT(15) | | 99 | #define MSR_THERM_INTR_TRIP1 __BIT(15) |
100 | #define MSR_THERM_INTR_TRIP2_VAL __BITS(16, 22) | | 100 | #define MSR_THERM_INTR_TRIP2_VAL __BITS(16, 22) |
101 | #define MSR_THERM_INTR_TRIP2 __BIT(23) | | 101 | #define MSR_THERM_INTR_TRIP2 __BIT(23) |
102 | | | 102 | |
103 | #define MSR_TEMP_TARGET_READOUT __BITS(16, 23) | | 103 | #define MSR_TEMP_TARGET_READOUT __BITS(16, 23) |
104 | | | 104 | |
| | | 105 | #define TJMAX_DEFAULT 100 |
| | | 106 | #define TJMAX_LIMIT_LOW 60 |
| | | 107 | #define TJMAX_LIMIT_HIGH 120 |
| | | 108 | |
105 | static int coretemp_match(device_t, cfdata_t, void *); | | 109 | static int coretemp_match(device_t, cfdata_t, void *); |
106 | static void coretemp_attach(device_t, device_t, void *); | | 110 | static void coretemp_attach(device_t, device_t, void *); |
107 | static int coretemp_detach(device_t, int); | | 111 | static int coretemp_detach(device_t, int); |
108 | static int coretemp_quirks(struct cpu_info *); | | 112 | static int coretemp_quirks(struct cpu_info *); |
109 | static void coretemp_tjmax(device_t); | | 113 | static void coretemp_tjmax(device_t); |
110 | static void coretemp_refresh(struct sysmon_envsys *, envsys_data_t *); | | 114 | static void coretemp_refresh(struct sysmon_envsys *, envsys_data_t *); |
111 | static void coretemp_refresh_xcall(void *, void *); | | 115 | static void coretemp_refresh_xcall(void *, void *); |
112 | | | 116 | |
113 | struct coretemp_softc { | | 117 | struct coretemp_softc { |
114 | device_t sc_dev; | | 118 | device_t sc_dev; |
115 | struct cpu_info *sc_ci; | | 119 | struct cpu_info *sc_ci; |
116 | struct sysmon_envsys *sc_sme; | | 120 | struct sysmon_envsys *sc_sme; |
117 | envsys_data_t sc_sensor; | | 121 | envsys_data_t sc_sensor; |
| @@ -249,36 +253,35 @@ coretemp_quirks(struct cpu_info *ci) | | | @@ -249,36 +253,35 @@ coretemp_quirks(struct cpu_info *ci) |
249 | | | 253 | |
250 | if (msr < 0x39) | | 254 | if (msr < 0x39) |
251 | return 0; | | 255 | return 0; |
252 | } | | 256 | } |
253 | | | 257 | |
254 | return 1; | | 258 | return 1; |
255 | } | | 259 | } |
256 | | | 260 | |
257 | void | | 261 | void |
258 | coretemp_tjmax(device_t self) | | 262 | coretemp_tjmax(device_t self) |
259 | { | | 263 | { |
260 | struct coretemp_softc *sc = device_private(self); | | 264 | struct coretemp_softc *sc = device_private(self); |
261 | struct cpu_info *ci = sc->sc_ci; | | 265 | struct cpu_info *ci = sc->sc_ci; |
262 | uint32_t model, stepping; | | | |
263 | uint64_t msr; | | 266 | uint64_t msr; |
| | | 267 | uint32_t model, stepping; |
| | | 268 | int tjmax; |
264 | | | 269 | |
265 | model = CPUID_TO_MODEL(ci->ci_signature); | | 270 | model = CPUID_TO_MODEL(ci->ci_signature); |
266 | stepping = CPUID_TO_STEPPING(ci->ci_signature); | | 271 | stepping = CPUID_TO_STEPPING(ci->ci_signature); |
267 | | | 272 | |
268 | /* | | 273 | /* Set the initial value. */ |
269 | * Use 100C as the initial value. | | 274 | sc->sc_tjmax = TJMAX_DEFAULT; |
270 | */ | | | |
271 | sc->sc_tjmax = 100; | | | |
272 | | | 275 | |
273 | if ((model == 0x0f && stepping >= 2) || (model == 0x0e)) { | | 276 | if ((model == 0x0f && stepping >= 2) || (model == 0x0e)) { |
274 | /* | | 277 | /* |
275 | * Check MSR_IA32_PLATFORM_ID(0x17) bit 28. It's not documented | | 278 | * Check MSR_IA32_PLATFORM_ID(0x17) bit 28. It's not documented |
276 | * in the datasheet, but the following page describes the | | 279 | * in the datasheet, but the following page describes the |
277 | * detail: | | 280 | * detail: |
278 | * http://software.intel.com/en-us/articles/ | | 281 | * http://software.intel.com/en-us/articles/ |
279 | * mobile-intel-core2-processor-detection-table/ | | 282 | * mobile-intel-core2-processor-detection-table/ |
280 | * Was: http://softwarecommunity.intel.com/Wiki/Mobility/ | | 283 | * Was: http://softwarecommunity.intel.com/Wiki/Mobility/ |
281 | * 720.htm | | 284 | * 720.htm |
282 | */ | | 285 | */ |
283 | if (rdmsr_safe(MSR_IA32_PLATFORM_ID, &msr) != 0) | | 286 | if (rdmsr_safe(MSR_IA32_PLATFORM_ID, &msr) != 0) |
284 | goto notee; | | 287 | goto notee; |
| @@ -294,57 +297,57 @@ coretemp_tjmax(device_t self) | | | @@ -294,57 +297,57 @@ coretemp_tjmax(device_t self) |
294 | } | | 297 | } |
295 | } else if (model == 0x17 && stepping == 0x06) { | | 298 | } else if (model == 0x17 && stepping == 0x06) { |
296 | /* The mobile Penryn family. */ | | 299 | /* The mobile Penryn family. */ |
297 | sc->sc_tjmax = 105; | | 300 | sc->sc_tjmax = 105; |
298 | return; | | 301 | return; |
299 | } else if (model == 0x1c) { | | 302 | } else if (model == 0x1c) { |
300 | if (stepping == 0x0a) { | | 303 | if (stepping == 0x0a) { |
301 | /* 45nm Atom D400, N400 and D500 series */ | | 304 | /* 45nm Atom D400, N400 and D500 series */ |
302 | sc->sc_tjmax = 100; | | 305 | sc->sc_tjmax = 100; |
303 | } else | | 306 | } else |
304 | sc->sc_tjmax = 90; | | 307 | sc->sc_tjmax = 90; |
305 | } else { | | 308 | } else { |
306 | notee: | | 309 | notee: |
307 | /* | | 310 | /* Attempt to get Tj(max) from IA32_TEMPERATURE_TARGET. */ |
308 | * Attempt to get Tj(max) from IA32_TEMPERATURE_TARGET, | | 311 | if (rdmsr_safe(MSR_TEMPERATURE_TARGET, &msr) == EFAULT) { |
309 | * but only consider the interval [70, 110] C as valid. | | 312 | aprint_error_dev(sc->sc_dev, |
310 | * It is not fully known which CPU models have the MSR. | | 313 | "Failed to read TEMPERATURE_TARGET MSR. " |
311 | */ | | 314 | "Use the default (%d)\n", sc->sc_tjmax); |
312 | if (rdmsr_safe(MSR_TEMPERATURE_TARGET, &msr) == EFAULT) | | | |
313 | return; | | | |
314 | | | | |
315 | msr = __SHIFTOUT(msr, MSR_TEMP_TARGET_READOUT); | | | |
316 | | | | |
317 | if (msr >= 70 && msr <= 110) { | | | |
318 | sc->sc_tjmax = msr; | | | |
319 | return; | | 315 | return; |
320 | } | | 316 | } |
| | | 317 | |
| | | 318 | tjmax = __SHIFTOUT(msr, MSR_TEMP_TARGET_READOUT); |
| | | 319 | if ((tjmax < TJMAX_LIMIT_LOW) || (tjmax > TJMAX_LIMIT_HIGH)) |
| | | 320 | aprint_error_dev(sc->sc_dev, |
| | | 321 | "WARNING: Tjmax(%d) might exceeded the limit.\n", |
| | | 322 | tjmax); |
| | | 323 | sc->sc_tjmax = tjmax; |
321 | } | | 324 | } |
322 | } | | 325 | } |
323 | | | 326 | |
324 | static void | | 327 | static void |
325 | coretemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 328 | coretemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
326 | { | | 329 | { |
327 | struct coretemp_softc *sc = sme->sme_cookie; | | 330 | struct coretemp_softc *sc = sme->sme_cookie; |
328 | uint64_t xc; | | 331 | uint64_t xc; |
329 | | | 332 | |
330 | xc = xc_unicast(0, coretemp_refresh_xcall, sc, edata, sc->sc_ci); | | 333 | xc = xc_unicast(0, coretemp_refresh_xcall, sc, edata, sc->sc_ci); |
331 | xc_wait(xc); | | 334 | xc_wait(xc); |
332 | } | | 335 | } |
333 | | | 336 | |
334 | static void | | 337 | static void |
335 | coretemp_refresh_xcall(void *arg0, void *arg1) | | 338 | coretemp_refresh_xcall(void *arg0, void *arg1) |
336 | { | | 339 | { |
337 | struct coretemp_softc *sc = arg0; | | 340 | struct coretemp_softc *sc = arg0; |
338 | envsys_data_t *edata = arg1; | | 341 | envsys_data_t *edata = arg1; |
339 | uint64_t msr; | | 342 | uint64_t msr; |
340 | | | 343 | |
341 | msr = rdmsr(MSR_THERM_STATUS); | | 344 | msr = rdmsr(MSR_THERM_STATUS); |
342 | | | 345 | |
343 | if ((msr & MSR_THERM_STATUS_VALID) == 0) | | 346 | if ((msr & MSR_THERM_STATUS_VALID) == 0) |
344 | edata->state = ENVSYS_SINVALID; | | 347 | edata->state = ENVSYS_SINVALID; |
345 | else { | | 348 | else { |
346 | /* | | 349 | /* |
347 | * The temperature is computed by | | 350 | * The temperature is computed by |
348 | * subtracting the reading by Tj(max). | | 351 | * subtracting the reading by Tj(max). |
349 | */ | | 352 | */ |
350 | edata->value_cur = sc->sc_tjmax; | | 353 | edata->value_cur = sc->sc_tjmax; |