intel_tcc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
  4. * Copyright (c) 2022, Intel Corporation.
  5. */
  6. #include <linux/errno.h>
  7. #include <linux/intel_tcc.h>
  8. #include <asm/cpu_device_id.h>
  9. #include <asm/intel-family.h>
  10. #include <asm/msr.h>
  11. /**
  12. * struct temp_masks - Bitmasks for temperature readings
  13. * @tcc_offset: TCC offset in MSR_TEMPERATURE_TARGET
  14. * @digital_readout: Digital readout in MSR_IA32_THERM_STATUS
  15. * @pkg_digital_readout: Digital readout in MSR_IA32_PACKAGE_THERM_STATUS
  16. *
  17. * Bitmasks to extract the fields of the MSR_TEMPERATURE and IA32_[PACKAGE]_
  18. * THERM_STATUS registers for different processor models.
  19. *
  20. * The bitmask of TjMax is not included in this structure. It is always 0xff.
  21. */
  22. struct temp_masks {
  23. u32 tcc_offset;
  24. u32 digital_readout;
  25. u32 pkg_digital_readout;
  26. };
  27. #define TCC_MODEL_TEMP_MASKS(model, _tcc_offset, _digital_readout, \
  28. _pkg_digital_readout) \
  29. static const struct temp_masks temp_##model __initconst = { \
  30. .tcc_offset = _tcc_offset, \
  31. .digital_readout = _digital_readout, \
  32. .pkg_digital_readout = _pkg_digital_readout \
  33. }
  34. TCC_MODEL_TEMP_MASKS(nehalem, 0, 0x7f, 0x7f);
  35. TCC_MODEL_TEMP_MASKS(haswell_x, 0xf, 0x7f, 0x7f);
  36. TCC_MODEL_TEMP_MASKS(broadwell, 0x3f, 0x7f, 0x7f);
  37. TCC_MODEL_TEMP_MASKS(goldmont, 0x7f, 0x7f, 0x7f);
  38. TCC_MODEL_TEMP_MASKS(tigerlake, 0x3f, 0xff, 0xff);
  39. TCC_MODEL_TEMP_MASKS(sapphirerapids, 0x3f, 0x7f, 0xff);
  40. /* Use these masks for processors not included in @tcc_cpu_ids. */
  41. static struct temp_masks intel_tcc_temp_masks __ro_after_init = {
  42. .tcc_offset = 0x7f,
  43. .digital_readout = 0xff,
  44. .pkg_digital_readout = 0xff,
  45. };
  46. static const struct x86_cpu_id intel_tcc_cpu_ids[] __initconst = {
  47. X86_MATCH_VFM(INTEL_CORE_YONAH, &temp_nehalem),
  48. X86_MATCH_VFM(INTEL_CORE2_MEROM, &temp_nehalem),
  49. X86_MATCH_VFM(INTEL_CORE2_MEROM_L, &temp_nehalem),
  50. X86_MATCH_VFM(INTEL_CORE2_PENRYN, &temp_nehalem),
  51. X86_MATCH_VFM(INTEL_CORE2_DUNNINGTON, &temp_nehalem),
  52. X86_MATCH_VFM(INTEL_NEHALEM, &temp_nehalem),
  53. X86_MATCH_VFM(INTEL_NEHALEM_G, &temp_nehalem),
  54. X86_MATCH_VFM(INTEL_NEHALEM_EP, &temp_nehalem),
  55. X86_MATCH_VFM(INTEL_NEHALEM_EX, &temp_nehalem),
  56. X86_MATCH_VFM(INTEL_WESTMERE, &temp_nehalem),
  57. X86_MATCH_VFM(INTEL_WESTMERE_EP, &temp_nehalem),
  58. X86_MATCH_VFM(INTEL_WESTMERE_EX, &temp_nehalem),
  59. X86_MATCH_VFM(INTEL_SANDYBRIDGE, &temp_nehalem),
  60. X86_MATCH_VFM(INTEL_SANDYBRIDGE_X, &temp_nehalem),
  61. X86_MATCH_VFM(INTEL_IVYBRIDGE, &temp_nehalem),
  62. X86_MATCH_VFM(INTEL_IVYBRIDGE_X, &temp_haswell_x),
  63. X86_MATCH_VFM(INTEL_HASWELL, &temp_nehalem),
  64. X86_MATCH_VFM(INTEL_HASWELL_X, &temp_haswell_x),
  65. X86_MATCH_VFM(INTEL_HASWELL_L, &temp_nehalem),
  66. X86_MATCH_VFM(INTEL_HASWELL_G, &temp_nehalem),
  67. X86_MATCH_VFM(INTEL_BROADWELL, &temp_broadwell),
  68. X86_MATCH_VFM(INTEL_BROADWELL_G, &temp_broadwell),
  69. X86_MATCH_VFM(INTEL_BROADWELL_X, &temp_haswell_x),
  70. X86_MATCH_VFM(INTEL_BROADWELL_D, &temp_haswell_x),
  71. X86_MATCH_VFM(INTEL_SKYLAKE_L, &temp_broadwell),
  72. X86_MATCH_VFM(INTEL_SKYLAKE, &temp_broadwell),
  73. X86_MATCH_VFM(INTEL_SKYLAKE_X, &temp_haswell_x),
  74. X86_MATCH_VFM(INTEL_KABYLAKE_L, &temp_broadwell),
  75. X86_MATCH_VFM(INTEL_KABYLAKE, &temp_broadwell),
  76. X86_MATCH_VFM(INTEL_COMETLAKE, &temp_broadwell),
  77. X86_MATCH_VFM(INTEL_COMETLAKE_L, &temp_broadwell),
  78. X86_MATCH_VFM(INTEL_CANNONLAKE_L, &temp_broadwell),
  79. X86_MATCH_VFM(INTEL_ICELAKE_X, &temp_broadwell),
  80. X86_MATCH_VFM(INTEL_ICELAKE_D, &temp_broadwell),
  81. X86_MATCH_VFM(INTEL_ICELAKE, &temp_broadwell),
  82. X86_MATCH_VFM(INTEL_ICELAKE_L, &temp_broadwell),
  83. X86_MATCH_VFM(INTEL_ICELAKE_NNPI, &temp_broadwell),
  84. X86_MATCH_VFM(INTEL_ROCKETLAKE, &temp_broadwell),
  85. X86_MATCH_VFM(INTEL_TIGERLAKE_L, &temp_tigerlake),
  86. X86_MATCH_VFM(INTEL_TIGERLAKE, &temp_tigerlake),
  87. X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &temp_sapphirerapids),
  88. X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &temp_sapphirerapids),
  89. X86_MATCH_VFM(INTEL_LAKEFIELD, &temp_broadwell),
  90. X86_MATCH_VFM(INTEL_ALDERLAKE, &temp_tigerlake),
  91. X86_MATCH_VFM(INTEL_ALDERLAKE_L, &temp_tigerlake),
  92. X86_MATCH_VFM(INTEL_RAPTORLAKE, &temp_tigerlake),
  93. X86_MATCH_VFM(INTEL_RAPTORLAKE_P, &temp_tigerlake),
  94. X86_MATCH_VFM(INTEL_RAPTORLAKE_S, &temp_tigerlake),
  95. X86_MATCH_VFM(INTEL_ATOM_BONNELL, &temp_nehalem),
  96. X86_MATCH_VFM(INTEL_ATOM_BONNELL_MID, &temp_nehalem),
  97. X86_MATCH_VFM(INTEL_ATOM_SALTWELL, &temp_nehalem),
  98. X86_MATCH_VFM(INTEL_ATOM_SALTWELL_MID, &temp_nehalem),
  99. X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, &temp_broadwell),
  100. X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_D, &temp_broadwell),
  101. X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID, &temp_broadwell),
  102. X86_MATCH_VFM(INTEL_ATOM_AIRMONT, &temp_broadwell),
  103. X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID2, &temp_broadwell),
  104. X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP, &temp_broadwell),
  105. X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &temp_goldmont),
  106. X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D, &temp_goldmont),
  107. X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &temp_goldmont),
  108. X86_MATCH_VFM(INTEL_ATOM_TREMONT_D, &temp_broadwell),
  109. X86_MATCH_VFM(INTEL_ATOM_TREMONT, &temp_broadwell),
  110. X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, &temp_broadwell),
  111. X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &temp_tigerlake),
  112. X86_MATCH_VFM(INTEL_XEON_PHI_KNL, &temp_broadwell),
  113. X86_MATCH_VFM(INTEL_XEON_PHI_KNM, &temp_broadwell),
  114. {}
  115. };
  116. static int __init intel_tcc_init(void)
  117. {
  118. const struct x86_cpu_id *id;
  119. id = x86_match_cpu(intel_tcc_cpu_ids);
  120. if (id)
  121. memcpy(&intel_tcc_temp_masks, (const void *)id->driver_data,
  122. sizeof(intel_tcc_temp_masks));
  123. return 0;
  124. }
  125. /*
  126. * Use subsys_initcall to ensure temperature bitmasks are initialized before
  127. * the drivers that use this library.
  128. */
  129. subsys_initcall(intel_tcc_init);
  130. /**
  131. * intel_tcc_get_offset_mask() - Returns the bitmask to read TCC offset
  132. *
  133. * Get the model-specific bitmask to extract TCC_OFFSET from the MSR
  134. * TEMPERATURE_TARGET register. If the mask is 0, it means the processor does
  135. * not support TCC offset.
  136. *
  137. * Return: The model-specific bitmask for TCC offset.
  138. */
  139. u32 intel_tcc_get_offset_mask(void)
  140. {
  141. return intel_tcc_temp_masks.tcc_offset;
  142. }
  143. EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask, "INTEL_TCC");
  144. /**
  145. * get_temp_mask() - Returns the model-specific bitmask for temperature
  146. *
  147. * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
  148. *
  149. * Get the model-specific bitmask to extract the temperature reading from the
  150. * MSR_IA32_[PACKAGE]_THERM_STATUS register.
  151. *
  152. * Callers must check if the thermal status registers are supported.
  153. *
  154. * Return: The model-specific bitmask for temperature reading
  155. */
  156. static u32 get_temp_mask(bool pkg)
  157. {
  158. return pkg ? intel_tcc_temp_masks.pkg_digital_readout :
  159. intel_tcc_temp_masks.digital_readout;
  160. }
  161. /**
  162. * intel_tcc_get_tjmax() - returns the default TCC activation Temperature
  163. * @cpu: cpu that the MSR should be run on, negative value means any cpu.
  164. *
  165. * Get the TjMax value, which is the default thermal throttling or TCC
  166. * activation temperature in degrees C.
  167. *
  168. * Return: Tjmax value in degrees C on success, negative error code otherwise.
  169. */
  170. int intel_tcc_get_tjmax(int cpu)
  171. {
  172. u32 low, high;
  173. int val, err;
  174. if (cpu < 0)
  175. err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  176. else
  177. err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  178. if (err)
  179. return err;
  180. val = (low >> 16) & 0xff;
  181. return val ? val : -ENODATA;
  182. }
  183. EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, "INTEL_TCC");
  184. /**
  185. * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
  186. * @cpu: cpu that the MSR should be run on, negative value means any cpu.
  187. *
  188. * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
  189. * activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
  190. *
  191. * Return: Tcc offset value in degrees C on success, negative error code otherwise.
  192. */
  193. int intel_tcc_get_offset(int cpu)
  194. {
  195. u32 low, high;
  196. int err;
  197. if (cpu < 0)
  198. err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  199. else
  200. err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  201. if (err)
  202. return err;
  203. return (low >> 24) & intel_tcc_temp_masks.tcc_offset;
  204. }
  205. EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, "INTEL_TCC");
  206. /**
  207. * intel_tcc_set_offset() - set the TCC offset value to Tjmax
  208. * @cpu: cpu that the MSR should be run on, negative value means any cpu.
  209. * @offset: TCC offset value in degree C
  210. *
  211. * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
  212. * activation temperature equals "Tjmax" - "TCC Offset", in degree C.
  213. *
  214. * Return: On success returns 0, negative error code otherwise.
  215. */
  216. int intel_tcc_set_offset(int cpu, int offset)
  217. {
  218. u32 low, high;
  219. int err;
  220. if (!intel_tcc_temp_masks.tcc_offset)
  221. return -ENODEV;
  222. if (offset < 0 || offset > intel_tcc_temp_masks.tcc_offset)
  223. return -EINVAL;
  224. if (cpu < 0)
  225. err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  226. else
  227. err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
  228. if (err)
  229. return err;
  230. /* MSR Locked */
  231. if (low & BIT(31))
  232. return -EPERM;
  233. low &= ~(intel_tcc_temp_masks.tcc_offset << 24);
  234. low |= offset << 24;
  235. if (cpu < 0)
  236. return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high);
  237. else
  238. return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high);
  239. }
  240. EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, "INTEL_TCC");
  241. /**
  242. * intel_tcc_get_temp() - returns the current temperature
  243. * @cpu: cpu that the MSR should be run on, negative value means any cpu.
  244. * @temp: pointer to the memory for saving cpu temperature.
  245. * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
  246. *
  247. * Get the current temperature returned by the CPU core/package level
  248. * thermal sensor, in degrees C.
  249. *
  250. * Return: 0 on success, negative error code otherwise.
  251. */
  252. int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
  253. {
  254. u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
  255. u32 low, high, mask;
  256. int tjmax, err;
  257. tjmax = intel_tcc_get_tjmax(cpu);
  258. if (tjmax < 0)
  259. return tjmax;
  260. if (cpu < 0)
  261. err = rdmsr_safe(msr, &low, &high);
  262. else
  263. err = rdmsr_safe_on_cpu(cpu, msr, &low, &high);
  264. if (err)
  265. return err;
  266. /* Temperature is beyond the valid thermal sensor range */
  267. if (!(low & BIT(31)))
  268. return -ENODATA;
  269. mask = get_temp_mask(pkg);
  270. *temp = tjmax - ((low >> 16) & mask);
  271. return 0;
  272. }
  273. EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, "INTEL_TCC");