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 | |
7 | #include <linux/errno.h> |
8 | #include <linux/intel_tcc.h> |
9 | #include <asm/msr.h> |
10 | |
11 | /** |
12 | * intel_tcc_get_tjmax() - returns the default TCC activation Temperature |
13 | * @cpu: cpu that the MSR should be run on, nagative value means any cpu. |
14 | * |
15 | * Get the TjMax value, which is the default thermal throttling or TCC |
16 | * activation temperature in degrees C. |
17 | * |
18 | * Return: Tjmax value in degrees C on success, negative error code otherwise. |
19 | */ |
20 | int intel_tcc_get_tjmax(int cpu) |
21 | { |
22 | u32 low, high; |
23 | int val, err; |
24 | |
25 | if (cpu < 0) |
26 | err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); |
27 | else |
28 | err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high); |
29 | if (err) |
30 | return err; |
31 | |
32 | val = (low >> 16) & 0xff; |
33 | |
34 | return val ? val : -ENODATA; |
35 | } |
36 | EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC); |
37 | |
38 | /** |
39 | * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax |
40 | * @cpu: cpu that the MSR should be run on, nagative value means any cpu. |
41 | * |
42 | * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC |
43 | * activation temperature equals "Tjmax" - "TCC Offset", in degrees C. |
44 | * |
45 | * Return: Tcc offset value in degrees C on success, negative error code otherwise. |
46 | */ |
47 | int intel_tcc_get_offset(int cpu) |
48 | { |
49 | u32 low, high; |
50 | int err; |
51 | |
52 | if (cpu < 0) |
53 | err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); |
54 | else |
55 | err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high); |
56 | if (err) |
57 | return err; |
58 | |
59 | return (low >> 24) & 0x3f; |
60 | } |
61 | EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC); |
62 | |
63 | /** |
64 | * intel_tcc_set_offset() - set the TCC offset value to Tjmax |
65 | * @cpu: cpu that the MSR should be run on, nagative value means any cpu. |
66 | * @offset: TCC offset value in degree C |
67 | * |
68 | * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC |
69 | * activation temperature equals "Tjmax" - "TCC Offset", in degree C. |
70 | * |
71 | * Return: On success returns 0, negative error code otherwise. |
72 | */ |
73 | |
74 | int intel_tcc_set_offset(int cpu, int offset) |
75 | { |
76 | u32 low, high; |
77 | int err; |
78 | |
79 | if (offset < 0 || offset > 0x3f) |
80 | return -EINVAL; |
81 | |
82 | if (cpu < 0) |
83 | err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); |
84 | else |
85 | err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high); |
86 | if (err) |
87 | return err; |
88 | |
89 | /* MSR Locked */ |
90 | if (low & BIT(31)) |
91 | return -EPERM; |
92 | |
93 | low &= ~(0x3f << 24); |
94 | low |= offset << 24; |
95 | |
96 | if (cpu < 0) |
97 | return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high); |
98 | else |
99 | return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: low, h: high); |
100 | } |
101 | EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC); |
102 | |
103 | /** |
104 | * intel_tcc_get_temp() - returns the current temperature |
105 | * @cpu: cpu that the MSR should be run on, nagative value means any cpu. |
106 | * @temp: pointer to the memory for saving cpu temperature. |
107 | * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor. |
108 | * |
109 | * Get the current temperature returned by the CPU core/package level |
110 | * thermal sensor, in degrees C. |
111 | * |
112 | * Return: 0 on success, negative error code otherwise. |
113 | */ |
114 | int intel_tcc_get_temp(int cpu, int *temp, bool pkg) |
115 | { |
116 | u32 low, high; |
117 | u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; |
118 | int tjmax, err; |
119 | |
120 | tjmax = intel_tcc_get_tjmax(cpu); |
121 | if (tjmax < 0) |
122 | return tjmax; |
123 | |
124 | if (cpu < 0) |
125 | err = rdmsr_safe(msr, &low, &high); |
126 | else |
127 | err = rdmsr_safe_on_cpu(cpu, msr_no: msr, l: &low, h: &high); |
128 | if (err) |
129 | return err; |
130 | |
131 | /* Temperature is beyond the valid thermal sensor range */ |
132 | if (!(low & BIT(31))) |
133 | return -ENODATA; |
134 | |
135 | *temp = tjmax - ((low >> 16) & 0x7f); |
136 | |
137 | return 0; |
138 | } |
139 | EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC); |
140 | |