1 // SPDX-License-Identifier: GPL-2.0-only
3 * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
4 * Copyright (c) 2022, Intel Corporation.
7 #include <linux/errno.h>
8 #include <linux/intel_tcc.h>
9 #include <asm/cpu_device_id.h>
10 #include <asm/intel-family.h>
14 * struct temp_masks - Bitmasks for temperature readings
15 * @tcc_offset: TCC offset in MSR_TEMPERATURE_TARGET
16 * @digital_readout: Digital readout in MSR_IA32_THERM_STATUS
17 * @pkg_digital_readout: Digital readout in MSR_IA32_PACKAGE_THERM_STATUS
19 * Bitmasks to extract the fields of the MSR_TEMPERATURE and IA32_[PACKAGE]_
20 * THERM_STATUS registers for different processor models.
22 * The bitmask of TjMax is not included in this structure. It is always 0xff.
27 u32 pkg_digital_readout
;
30 #define TCC_MODEL_TEMP_MASKS(model, _tcc_offset, _digital_readout, \
31 _pkg_digital_readout) \
32 static const struct temp_masks temp_##model __initconst = { \
33 .tcc_offset = _tcc_offset, \
34 .digital_readout = _digital_readout, \
35 .pkg_digital_readout = _pkg_digital_readout \
38 TCC_MODEL_TEMP_MASKS(nehalem
, 0, 0x7f, 0x7f);
39 TCC_MODEL_TEMP_MASKS(haswell_x
, 0xf, 0x7f, 0x7f);
40 TCC_MODEL_TEMP_MASKS(broadwell
, 0x3f, 0x7f, 0x7f);
41 TCC_MODEL_TEMP_MASKS(goldmont
, 0x7f, 0x7f, 0x7f);
42 TCC_MODEL_TEMP_MASKS(tigerlake
, 0x3f, 0xff, 0xff);
43 TCC_MODEL_TEMP_MASKS(sapphirerapids
, 0x3f, 0x7f, 0xff);
45 /* Use these masks for processors not included in @tcc_cpu_ids. */
46 static struct temp_masks intel_tcc_temp_masks __ro_after_init
= {
48 .digital_readout
= 0xff,
49 .pkg_digital_readout
= 0xff,
52 static const struct x86_cpu_id intel_tcc_cpu_ids
[] __initconst
= {
53 X86_MATCH_VFM(INTEL_CORE_YONAH
, &temp_nehalem
),
54 X86_MATCH_VFM(INTEL_CORE2_MEROM
, &temp_nehalem
),
55 X86_MATCH_VFM(INTEL_CORE2_MEROM_L
, &temp_nehalem
),
56 X86_MATCH_VFM(INTEL_CORE2_PENRYN
, &temp_nehalem
),
57 X86_MATCH_VFM(INTEL_CORE2_DUNNINGTON
, &temp_nehalem
),
58 X86_MATCH_VFM(INTEL_NEHALEM
, &temp_nehalem
),
59 X86_MATCH_VFM(INTEL_NEHALEM_G
, &temp_nehalem
),
60 X86_MATCH_VFM(INTEL_NEHALEM_EP
, &temp_nehalem
),
61 X86_MATCH_VFM(INTEL_NEHALEM_EX
, &temp_nehalem
),
62 X86_MATCH_VFM(INTEL_WESTMERE
, &temp_nehalem
),
63 X86_MATCH_VFM(INTEL_WESTMERE_EP
, &temp_nehalem
),
64 X86_MATCH_VFM(INTEL_WESTMERE_EX
, &temp_nehalem
),
65 X86_MATCH_VFM(INTEL_SANDYBRIDGE
, &temp_nehalem
),
66 X86_MATCH_VFM(INTEL_SANDYBRIDGE_X
, &temp_nehalem
),
67 X86_MATCH_VFM(INTEL_IVYBRIDGE
, &temp_nehalem
),
68 X86_MATCH_VFM(INTEL_IVYBRIDGE_X
, &temp_haswell_x
),
69 X86_MATCH_VFM(INTEL_HASWELL
, &temp_nehalem
),
70 X86_MATCH_VFM(INTEL_HASWELL_X
, &temp_haswell_x
),
71 X86_MATCH_VFM(INTEL_HASWELL_L
, &temp_nehalem
),
72 X86_MATCH_VFM(INTEL_HASWELL_G
, &temp_nehalem
),
73 X86_MATCH_VFM(INTEL_BROADWELL
, &temp_broadwell
),
74 X86_MATCH_VFM(INTEL_BROADWELL_G
, &temp_broadwell
),
75 X86_MATCH_VFM(INTEL_BROADWELL_X
, &temp_haswell_x
),
76 X86_MATCH_VFM(INTEL_BROADWELL_D
, &temp_haswell_x
),
77 X86_MATCH_VFM(INTEL_SKYLAKE_L
, &temp_broadwell
),
78 X86_MATCH_VFM(INTEL_SKYLAKE
, &temp_broadwell
),
79 X86_MATCH_VFM(INTEL_SKYLAKE_X
, &temp_haswell_x
),
80 X86_MATCH_VFM(INTEL_KABYLAKE_L
, &temp_broadwell
),
81 X86_MATCH_VFM(INTEL_KABYLAKE
, &temp_broadwell
),
82 X86_MATCH_VFM(INTEL_COMETLAKE
, &temp_broadwell
),
83 X86_MATCH_VFM(INTEL_COMETLAKE_L
, &temp_broadwell
),
84 X86_MATCH_VFM(INTEL_CANNONLAKE_L
, &temp_broadwell
),
85 X86_MATCH_VFM(INTEL_ICELAKE_X
, &temp_broadwell
),
86 X86_MATCH_VFM(INTEL_ICELAKE_D
, &temp_broadwell
),
87 X86_MATCH_VFM(INTEL_ICELAKE
, &temp_broadwell
),
88 X86_MATCH_VFM(INTEL_ICELAKE_L
, &temp_broadwell
),
89 X86_MATCH_VFM(INTEL_ICELAKE_NNPI
, &temp_broadwell
),
90 X86_MATCH_VFM(INTEL_ROCKETLAKE
, &temp_broadwell
),
91 X86_MATCH_VFM(INTEL_TIGERLAKE_L
, &temp_tigerlake
),
92 X86_MATCH_VFM(INTEL_TIGERLAKE
, &temp_tigerlake
),
93 X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X
, &temp_sapphirerapids
),
94 X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X
, &temp_sapphirerapids
),
95 X86_MATCH_VFM(INTEL_LAKEFIELD
, &temp_broadwell
),
96 X86_MATCH_VFM(INTEL_ALDERLAKE
, &temp_tigerlake
),
97 X86_MATCH_VFM(INTEL_ALDERLAKE_L
, &temp_tigerlake
),
98 X86_MATCH_VFM(INTEL_RAPTORLAKE
, &temp_tigerlake
),
99 X86_MATCH_VFM(INTEL_RAPTORLAKE_P
, &temp_tigerlake
),
100 X86_MATCH_VFM(INTEL_RAPTORLAKE_S
, &temp_tigerlake
),
101 X86_MATCH_VFM(INTEL_ATOM_BONNELL
, &temp_nehalem
),
102 X86_MATCH_VFM(INTEL_ATOM_BONNELL_MID
, &temp_nehalem
),
103 X86_MATCH_VFM(INTEL_ATOM_SALTWELL
, &temp_nehalem
),
104 X86_MATCH_VFM(INTEL_ATOM_SALTWELL_MID
, &temp_nehalem
),
105 X86_MATCH_VFM(INTEL_ATOM_SILVERMONT
, &temp_broadwell
),
106 X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_D
, &temp_broadwell
),
107 X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID
, &temp_broadwell
),
108 X86_MATCH_VFM(INTEL_ATOM_AIRMONT
, &temp_broadwell
),
109 X86_MATCH_VFM(INTEL_ATOM_AIRMONT_MID
, &temp_broadwell
),
110 X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP
, &temp_broadwell
),
111 X86_MATCH_VFM(INTEL_ATOM_GOLDMONT
, &temp_goldmont
),
112 X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D
, &temp_goldmont
),
113 X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS
, &temp_goldmont
),
114 X86_MATCH_VFM(INTEL_ATOM_TREMONT_D
, &temp_broadwell
),
115 X86_MATCH_VFM(INTEL_ATOM_TREMONT
, &temp_broadwell
),
116 X86_MATCH_VFM(INTEL_ATOM_TREMONT_L
, &temp_broadwell
),
117 X86_MATCH_VFM(INTEL_ATOM_GRACEMONT
, &temp_tigerlake
),
118 X86_MATCH_VFM(INTEL_XEON_PHI_KNL
, &temp_broadwell
),
119 X86_MATCH_VFM(INTEL_XEON_PHI_KNM
, &temp_broadwell
),
123 static int __init
intel_tcc_init(void)
125 const struct x86_cpu_id
*id
;
127 id
= x86_match_cpu(intel_tcc_cpu_ids
);
129 memcpy(&intel_tcc_temp_masks
, (const void *)id
->driver_data
,
130 sizeof(intel_tcc_temp_masks
));
135 * Use subsys_initcall to ensure temperature bitmasks are initialized before
136 * the drivers that use this library.
138 subsys_initcall(intel_tcc_init
);
141 * intel_tcc_get_offset_mask() - Returns the bitmask to read TCC offset
143 * Get the model-specific bitmask to extract TCC_OFFSET from the MSR
144 * TEMPERATURE_TARGET register. If the mask is 0, it means the processor does
145 * not support TCC offset.
147 * Return: The model-specific bitmask for TCC offset.
149 u32
intel_tcc_get_offset_mask(void)
151 return intel_tcc_temp_masks
.tcc_offset
;
153 EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask
, "INTEL_TCC");
156 * get_temp_mask() - Returns the model-specific bitmask for temperature
158 * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
160 * Get the model-specific bitmask to extract the temperature reading from the
161 * MSR_IA32_[PACKAGE]_THERM_STATUS register.
163 * Callers must check if the thermal status registers are supported.
165 * Return: The model-specific bitmask for temperature reading
167 static u32
get_temp_mask(bool pkg
)
169 return pkg
? intel_tcc_temp_masks
.pkg_digital_readout
:
170 intel_tcc_temp_masks
.digital_readout
;
174 * intel_tcc_get_tjmax() - returns the default TCC activation Temperature
175 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
177 * Get the TjMax value, which is the default thermal throttling or TCC
178 * activation temperature in degrees C.
180 * Return: Tjmax value in degrees C on success, negative error code otherwise.
182 int intel_tcc_get_tjmax(int cpu
)
188 err
= rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
190 err
= rdmsr_safe_on_cpu(cpu
, MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
194 val
= (low
>> 16) & 0xff;
196 return val
? val
: -ENODATA
;
198 EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax
, "INTEL_TCC");
201 * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
202 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
204 * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
205 * activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
207 * Return: Tcc offset value in degrees C on success, negative error code otherwise.
209 int intel_tcc_get_offset(int cpu
)
215 err
= rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
217 err
= rdmsr_safe_on_cpu(cpu
, MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
221 return (low
>> 24) & intel_tcc_temp_masks
.tcc_offset
;
223 EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset
, "INTEL_TCC");
226 * intel_tcc_set_offset() - set the TCC offset value to Tjmax
227 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
228 * @offset: TCC offset value in degree C
230 * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
231 * activation temperature equals "Tjmax" - "TCC Offset", in degree C.
233 * Return: On success returns 0, negative error code otherwise.
236 int intel_tcc_set_offset(int cpu
, int offset
)
241 if (!intel_tcc_temp_masks
.tcc_offset
)
244 if (offset
< 0 || offset
> intel_tcc_temp_masks
.tcc_offset
)
248 err
= rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
250 err
= rdmsr_safe_on_cpu(cpu
, MSR_IA32_TEMPERATURE_TARGET
, &low
, &high
);
258 low
&= ~(intel_tcc_temp_masks
.tcc_offset
<< 24);
262 return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET
, low
, high
);
264 return wrmsr_safe_on_cpu(cpu
, MSR_IA32_TEMPERATURE_TARGET
, low
, high
);
266 EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset
, "INTEL_TCC");
269 * intel_tcc_get_temp() - returns the current temperature
270 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
271 * @temp: pointer to the memory for saving cpu temperature.
272 * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
274 * Get the current temperature returned by the CPU core/package level
275 * thermal sensor, in degrees C.
277 * Return: 0 on success, negative error code otherwise.
279 int intel_tcc_get_temp(int cpu
, int *temp
, bool pkg
)
281 u32 msr
= pkg
? MSR_IA32_PACKAGE_THERM_STATUS
: MSR_IA32_THERM_STATUS
;
285 tjmax
= intel_tcc_get_tjmax(cpu
);
290 err
= rdmsr_safe(msr
, &low
, &high
);
292 err
= rdmsr_safe_on_cpu(cpu
, msr
, &low
, &high
);
296 /* Temperature is beyond the valid thermal sensor range */
297 if (!(low
& BIT(31)))
300 mask
= get_temp_mask(pkg
);
302 *temp
= tjmax
- ((low
>> 16) & mask
);
306 EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp
, "INTEL_TCC");