1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * processor_thermal.c - Passive cooling submodule of the ACPI processor driver
4 *
5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
8 * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
9 * - Added processor hotplug support
10 */
11
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/cpufreq.h>
16 #include <linux/acpi.h>
17 #include <acpi/processor.h>
18 #include <linux/uaccess.h>
19
20 #include "internal.h"
21
22 #ifdef CONFIG_CPU_FREQ
23
24 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it
25 * offers (in most cases) voltage scaling in addition to frequency scaling, and
26 * thus a cubic (instead of linear) reduction of energy. Also, we allow for
27 * _any_ cpufreq driver and not only the acpi-cpufreq driver.
28 */
29
30 #define CPUFREQ_THERMAL_MIN_STEP 0
31
32 static int cpufreq_thermal_max_step __read_mostly = 3;
33
34 /*
35 * Minimum throttle percentage for processor_thermal cooling device.
36 * The processor_thermal driver uses it to calculate the percentage amount by
37 * which cpu frequency must be reduced for each cooling state. This is also used
38 * to calculate the maximum number of throttling steps or cooling states.
39 */
40 static int cpufreq_thermal_reduction_pctg __read_mostly = 20;
41
42 static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_step);
43
44 #define reduction_step(cpu) \
45 per_cpu(cpufreq_thermal_reduction_step, phys_package_first_cpu(cpu))
46
47 /*
48 * Emulate "per package data" using per cpu data (which should really be
49 * provided elsewhere)
50 *
51 * Note we can lose a CPU on cpu hotunplug, in this case we forget the state
52 * temporarily. Fortunately that's not a big issue here (I hope)
53 */
phys_package_first_cpu(int cpu)54 static int phys_package_first_cpu(int cpu)
55 {
56 int i;
57 int id = topology_physical_package_id(cpu);
58
59 for_each_online_cpu(i)
60 if (topology_physical_package_id(i) == id)
61 return i;
62 return 0;
63 }
64
cpu_has_cpufreq(unsigned int cpu)65 static bool cpu_has_cpufreq(unsigned int cpu)
66 {
67 if (!acpi_processor_cpufreq_init)
68 return 0;
69
70 struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
71
72 return policy != NULL;
73 }
74
cpufreq_get_max_state(unsigned int cpu)75 static int cpufreq_get_max_state(unsigned int cpu)
76 {
77 if (!cpu_has_cpufreq(cpu))
78 return 0;
79
80 return cpufreq_thermal_max_step;
81 }
82
cpufreq_get_cur_state(unsigned int cpu)83 static int cpufreq_get_cur_state(unsigned int cpu)
84 {
85 if (!cpu_has_cpufreq(cpu))
86 return 0;
87
88 return reduction_step(cpu);
89 }
90
cpufreq_update_thermal_limit(unsigned int cpu,struct acpi_processor * pr)91 static bool cpufreq_update_thermal_limit(unsigned int cpu, struct acpi_processor *pr)
92 {
93 unsigned long max_freq;
94 int ret;
95
96 struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
97 if (!policy)
98 return false;
99
100 max_freq = (policy->cpuinfo.max_freq *
101 (100 - reduction_step(cpu) * cpufreq_thermal_reduction_pctg)) / 100;
102
103 ret = freq_qos_update_request(&pr->thermal_req, max_freq);
104 if (ret < 0) {
105 pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n",
106 pr->id, ret);
107 }
108
109 return true;
110 }
111
cpufreq_set_cur_state(unsigned int cpu,int state)112 static int cpufreq_set_cur_state(unsigned int cpu, int state)
113 {
114 struct acpi_processor *pr;
115 int i;
116
117 if (!cpu_has_cpufreq(cpu))
118 return 0;
119
120 reduction_step(cpu) = state;
121
122 /*
123 * Update all the CPUs in the same package because they all
124 * contribute to the temperature and often share the same
125 * frequency.
126 */
127 for_each_online_cpu(i) {
128 if (topology_physical_package_id(i) !=
129 topology_physical_package_id(cpu))
130 continue;
131
132 pr = per_cpu(processors, i);
133
134 if (unlikely(!freq_qos_request_active(&pr->thermal_req)))
135 continue;
136
137 if (!cpufreq_update_thermal_limit(i, pr))
138 return -EINVAL;
139 }
140 return 0;
141 }
142
acpi_thermal_cpufreq_config(void)143 static void acpi_thermal_cpufreq_config(void)
144 {
145 int cpufreq_pctg = acpi_arch_thermal_cpufreq_pctg();
146
147 if (!cpufreq_pctg)
148 return;
149
150 cpufreq_thermal_reduction_pctg = cpufreq_pctg;
151
152 /*
153 * Derive the MAX_STEP from minimum throttle percentage so that the reduction
154 * percentage doesn't end up becoming negative. Also, cap the MAX_STEP so that
155 * the CPU performance doesn't become 0.
156 */
157 cpufreq_thermal_max_step = (100 / cpufreq_pctg) - 2;
158 }
159
acpi_thermal_cpufreq_init(struct cpufreq_policy * policy)160 void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
161 {
162 unsigned int cpu;
163
164 acpi_thermal_cpufreq_config();
165
166 for_each_cpu(cpu, policy->related_cpus) {
167 struct acpi_processor *pr = per_cpu(processors, cpu);
168 int ret;
169
170 if (!pr)
171 continue;
172
173 ret = freq_qos_add_request(&policy->constraints,
174 &pr->thermal_req,
175 FREQ_QOS_MAX, INT_MAX);
176 if (ret < 0) {
177 pr_err("Failed to add freq constraint for CPU%d (%d)\n",
178 cpu, ret);
179 continue;
180 }
181
182 thermal_cooling_device_update(pr->cdev);
183 }
184 }
185
acpi_thermal_cpufreq_exit(struct cpufreq_policy * policy)186 void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
187 {
188 unsigned int cpu;
189
190 for_each_cpu(cpu, policy->related_cpus) {
191 struct acpi_processor *pr = per_cpu(processors, cpu);
192
193 if (!pr)
194 continue;
195
196 freq_qos_remove_request(&pr->thermal_req);
197
198 thermal_cooling_device_update(pr->cdev);
199 }
200 }
201 #else /* ! CONFIG_CPU_FREQ */
cpufreq_get_max_state(unsigned int cpu)202 static int cpufreq_get_max_state(unsigned int cpu)
203 {
204 return 0;
205 }
206
cpufreq_get_cur_state(unsigned int cpu)207 static int cpufreq_get_cur_state(unsigned int cpu)
208 {
209 return 0;
210 }
211
cpufreq_set_cur_state(unsigned int cpu,int state)212 static int cpufreq_set_cur_state(unsigned int cpu, int state)
213 {
214 return 0;
215 }
216
217 #endif
218
219 /* thermal cooling device callbacks */
acpi_processor_max_state(struct acpi_processor * pr)220 static int acpi_processor_max_state(struct acpi_processor *pr)
221 {
222 int max_state = 0;
223
224 /*
225 * There exists four states according to
226 * cpufreq_thermal_reduction_step. 0, 1, 2, 3
227 */
228 max_state += cpufreq_get_max_state(pr->id);
229 if (pr->flags.throttling)
230 max_state += (pr->throttling.state_count -1);
231
232 return max_state;
233 }
234 static int
processor_get_max_state(struct thermal_cooling_device * cdev,unsigned long * state)235 processor_get_max_state(struct thermal_cooling_device *cdev,
236 unsigned long *state)
237 {
238 struct acpi_device *device = cdev->devdata;
239 struct acpi_processor *pr;
240
241 if (!device)
242 return -EINVAL;
243
244 pr = acpi_driver_data(device);
245 if (!pr)
246 return -EINVAL;
247
248 *state = acpi_processor_max_state(pr);
249 return 0;
250 }
251
252 static int
processor_get_cur_state(struct thermal_cooling_device * cdev,unsigned long * cur_state)253 processor_get_cur_state(struct thermal_cooling_device *cdev,
254 unsigned long *cur_state)
255 {
256 struct acpi_device *device = cdev->devdata;
257 struct acpi_processor *pr;
258
259 if (!device)
260 return -EINVAL;
261
262 pr = acpi_driver_data(device);
263 if (!pr)
264 return -EINVAL;
265
266 *cur_state = cpufreq_get_cur_state(pr->id);
267 if (pr->flags.throttling)
268 *cur_state += pr->throttling.state;
269 return 0;
270 }
271
272 static int
processor_set_cur_state(struct thermal_cooling_device * cdev,unsigned long state)273 processor_set_cur_state(struct thermal_cooling_device *cdev,
274 unsigned long state)
275 {
276 struct acpi_device *device = cdev->devdata;
277 struct acpi_processor *pr;
278 int result = 0;
279 int max_pstate;
280
281 if (!device)
282 return -EINVAL;
283
284 pr = acpi_driver_data(device);
285 if (!pr)
286 return -EINVAL;
287
288 max_pstate = cpufreq_get_max_state(pr->id);
289
290 if (state > acpi_processor_max_state(pr))
291 return -EINVAL;
292
293 if (state <= max_pstate) {
294 if (pr->flags.throttling && pr->throttling.state)
295 result = acpi_processor_set_throttling(pr, 0, false);
296 cpufreq_set_cur_state(pr->id, state);
297 } else {
298 cpufreq_set_cur_state(pr->id, max_pstate);
299 result = acpi_processor_set_throttling(pr,
300 state - max_pstate, false);
301 }
302 return result;
303 }
304
305 const struct thermal_cooling_device_ops processor_cooling_ops = {
306 .get_max_state = processor_get_max_state,
307 .get_cur_state = processor_get_cur_state,
308 .set_cur_state = processor_set_cur_state,
309 };
310
acpi_processor_thermal_init(struct acpi_processor * pr,struct acpi_device * device)311 int acpi_processor_thermal_init(struct acpi_processor *pr,
312 struct acpi_device *device)
313 {
314 int result = 0;
315
316 pr->cdev = thermal_cooling_device_register("Processor", device,
317 &processor_cooling_ops);
318 if (IS_ERR(pr->cdev)) {
319 result = PTR_ERR(pr->cdev);
320 return result;
321 }
322
323 dev_dbg(&device->dev, "registered as cooling_device%d\n",
324 pr->cdev->id);
325
326 result = sysfs_create_link(&device->dev.kobj,
327 &pr->cdev->device.kobj,
328 "thermal_cooling");
329 if (result) {
330 dev_err(&device->dev,
331 "Failed to create sysfs link 'thermal_cooling'\n");
332 goto err_thermal_unregister;
333 }
334
335 result = sysfs_create_link(&pr->cdev->device.kobj,
336 &device->dev.kobj,
337 "device");
338 if (result) {
339 dev_err(&pr->cdev->device,
340 "Failed to create sysfs link 'device'\n");
341 goto err_remove_sysfs_thermal;
342 }
343
344 return 0;
345
346 err_remove_sysfs_thermal:
347 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
348 err_thermal_unregister:
349 thermal_cooling_device_unregister(pr->cdev);
350
351 return result;
352 }
353
acpi_processor_thermal_exit(struct acpi_processor * pr,struct acpi_device * device)354 void acpi_processor_thermal_exit(struct acpi_processor *pr,
355 struct acpi_device *device)
356 {
357 if (pr->cdev) {
358 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
359 sysfs_remove_link(&pr->cdev->device.kobj, "device");
360 thermal_cooling_device_unregister(pr->cdev);
361 pr->cdev = NULL;
362 }
363 }
364