Skip to content

Commit 6ae0092

Browse files
ricardonrafaeljw
authored andcommitted
thermal: intel: intel_tcc: Add model checks for temperature registers
The register MSR_TEMPERATURE_TARGET is not architectural. Its fields may be defined differently for each processor model. TCC_OFFSET is an example of such case. Despite being specified as architectural, the registers IA32_[PACKAGE]_ THERM_STATUS have become model-specific: in recent processors, the digital temperature readout uses bits [23:16] whereas the Intel Software Developer's manual specifies bits [22:16]. Create an array of processor models and their bitmasks for TCC_OFFSET and the digital temperature readout fields. Do not include recent processors. Instead, use the bitmasks of these recent processors as default. Use these model-specific bitmasks when reading TCC_OFFSET or the temperature sensors. Initialize a model-specific data structure during subsys_initcall() to have it ready when thermal drivers are loaded. Expose the new interface intel_tcc_get_offset_mask(). The intel_tcc_cooling driver will use it. Reviewed-by: Zhang Rui <[email protected]> Signed-off-by: Ricardo Neri <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 73abe70 commit 6ae0092

File tree

2 files changed

+173
-5
lines changed

2 files changed

+173
-5
lines changed

drivers/thermal/intel/intel_tcc.c

Lines changed: 172 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,170 @@
66

77
#include <linux/errno.h>
88
#include <linux/intel_tcc.h>
9+
#include <asm/cpu_device_id.h>
10+
#include <asm/intel-family.h>
911
#include <asm/msr.h>
1012

13+
/**
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
18+
*
19+
* Bitmasks to extract the fields of the MSR_TEMPERATURE and IA32_[PACKAGE]_
20+
* THERM_STATUS registers for different processor models.
21+
*
22+
* The bitmask of TjMax is not included in this structure. It is always 0xff.
23+
*/
24+
struct temp_masks {
25+
u32 tcc_offset;
26+
u32 digital_readout;
27+
u32 pkg_digital_readout;
28+
};
29+
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 \
36+
}
37+
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);
44+
45+
/* Use these masks for processors not included in @tcc_cpu_ids. */
46+
static struct temp_masks intel_tcc_temp_masks __ro_after_init = {
47+
.tcc_offset = 0x7f,
48+
.digital_readout = 0xff,
49+
.pkg_digital_readout = 0xff,
50+
};
51+
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),
120+
{}
121+
};
122+
123+
static int __init intel_tcc_init(void)
124+
{
125+
const struct x86_cpu_id *id;
126+
127+
id = x86_match_cpu(intel_tcc_cpu_ids);
128+
if (id)
129+
memcpy(&intel_tcc_temp_masks, (const void *)id->driver_data,
130+
sizeof(intel_tcc_temp_masks));
131+
132+
return 0;
133+
}
134+
/*
135+
* Use subsys_initcall to ensure temperature bitmasks are initialized before
136+
* the drivers that use this library.
137+
*/
138+
subsys_initcall(intel_tcc_init);
139+
140+
/**
141+
* intel_tcc_get_offset_mask() - Returns the bitmask to read TCC offset
142+
*
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.
146+
*
147+
* Return: The model-specific bitmask for TCC offset.
148+
*/
149+
u32 intel_tcc_get_offset_mask(void)
150+
{
151+
return intel_tcc_temp_masks.tcc_offset;
152+
}
153+
EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask, INTEL_TCC);
154+
155+
/**
156+
* get_temp_mask() - Returns the model-specific bitmask for temperature
157+
*
158+
* @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
159+
*
160+
* Get the model-specific bitmask to extract the temperature reading from the
161+
* MSR_IA32_[PACKAGE]_THERM_STATUS register.
162+
*
163+
* Callers must check if the thermal status registers are supported.
164+
*
165+
* Return: The model-specific bitmask for temperature reading
166+
*/
167+
static u32 get_temp_mask(bool pkg)
168+
{
169+
return pkg ? intel_tcc_temp_masks.pkg_digital_readout :
170+
intel_tcc_temp_masks.digital_readout;
171+
}
172+
11173
/**
12174
* intel_tcc_get_tjmax() - returns the default TCC activation Temperature
13175
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
@@ -56,7 +218,7 @@ int intel_tcc_get_offset(int cpu)
56218
if (err)
57219
return err;
58220

59-
return (low >> 24) & 0x3f;
221+
return (low >> 24) & intel_tcc_temp_masks.tcc_offset;
60222
}
61223
EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC);
62224

@@ -76,7 +238,10 @@ int intel_tcc_set_offset(int cpu, int offset)
76238
u32 low, high;
77239
int err;
78240

79-
if (offset < 0 || offset > 0x3f)
241+
if (!intel_tcc_temp_masks.tcc_offset)
242+
return -ENODEV;
243+
244+
if (offset < 0 || offset > intel_tcc_temp_masks.tcc_offset)
80245
return -EINVAL;
81246

82247
if (cpu < 0)
@@ -90,7 +255,7 @@ int intel_tcc_set_offset(int cpu, int offset)
90255
if (low & BIT(31))
91256
return -EPERM;
92257

93-
low &= ~(0x3f << 24);
258+
low &= ~(intel_tcc_temp_masks.tcc_offset << 24);
94259
low |= offset << 24;
95260

96261
if (cpu < 0)
@@ -113,8 +278,8 @@ EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC);
113278
*/
114279
int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
115280
{
116-
u32 low, high;
117281
u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
282+
u32 low, high, mask;
118283
int tjmax, err;
119284

120285
tjmax = intel_tcc_get_tjmax(cpu);
@@ -132,7 +297,9 @@ int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
132297
if (!(low & BIT(31)))
133298
return -ENODATA;
134299

135-
*temp = tjmax - ((low >> 16) & 0x7f);
300+
mask = get_temp_mask(pkg);
301+
302+
*temp = tjmax - ((low >> 16) & mask);
136303

137304
return 0;
138305
}

include/linux/intel_tcc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ int intel_tcc_get_tjmax(int cpu);
1414
int intel_tcc_get_offset(int cpu);
1515
int intel_tcc_set_offset(int cpu, int offset);
1616
int intel_tcc_get_temp(int cpu, int *temp, bool pkg);
17+
u32 intel_tcc_get_offset_mask(void);
1718

1819
#endif /* __INTEL_TCC_H__ */

0 commit comments

Comments
 (0)