Branch data Line data Source code
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 : : #define PREFIX "ACPI: "
21 : :
22 : : #define ACPI_PROCESSOR_CLASS "processor"
23 : : #define _COMPONENT ACPI_PROCESSOR_COMPONENT
24 : : ACPI_MODULE_NAME("processor_thermal");
25 : :
26 : : #ifdef CONFIG_CPU_FREQ
27 : :
28 : : /* If a passive cooling situation is detected, primarily CPUfreq is used, as it
29 : : * offers (in most cases) voltage scaling in addition to frequency scaling, and
30 : : * thus a cubic (instead of linear) reduction of energy. Also, we allow for
31 : : * _any_ cpufreq driver and not only the acpi-cpufreq driver.
32 : : */
33 : :
34 : : #define CPUFREQ_THERMAL_MIN_STEP 0
35 : : #define CPUFREQ_THERMAL_MAX_STEP 3
36 : :
37 : : static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
38 : :
39 : : #define reduction_pctg(cpu) \
40 : : per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
41 : :
42 : : /*
43 : : * Emulate "per package data" using per cpu data (which should really be
44 : : * provided elsewhere)
45 : : *
46 : : * Note we can lose a CPU on cpu hotunplug, in this case we forget the state
47 : : * temporarily. Fortunately that's not a big issue here (I hope)
48 : : */
49 : 0 : static int phys_package_first_cpu(int cpu)
50 : : {
51 : 0 : int i;
52 : 0 : int id = topology_physical_package_id(cpu);
53 : :
54 [ # # ]: 0 : for_each_online_cpu(i)
55 [ # # ]: 0 : if (topology_physical_package_id(i) == id)
56 : 0 : return i;
57 : : return 0;
58 : : }
59 : :
60 : 0 : static int cpu_has_cpufreq(unsigned int cpu)
61 : : {
62 : 0 : struct cpufreq_policy policy;
63 [ # # # # ]: 0 : if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu))
64 : 0 : return 0;
65 : : return 1;
66 : : }
67 : :
68 : 0 : static int cpufreq_get_max_state(unsigned int cpu)
69 : : {
70 [ # # # # ]: 0 : if (!cpu_has_cpufreq(cpu))
71 : 0 : return 0;
72 : :
73 : : return CPUFREQ_THERMAL_MAX_STEP;
74 : : }
75 : :
76 : 0 : static int cpufreq_get_cur_state(unsigned int cpu)
77 : : {
78 [ # # ]: 0 : if (!cpu_has_cpufreq(cpu))
79 : : return 0;
80 : :
81 : 0 : return reduction_pctg(cpu);
82 : : }
83 : :
84 : 0 : static int cpufreq_set_cur_state(unsigned int cpu, int state)
85 : : {
86 : 0 : struct cpufreq_policy *policy;
87 : 0 : struct acpi_processor *pr;
88 : 0 : unsigned long max_freq;
89 : 0 : int i, ret;
90 : :
91 [ # # ]: 0 : if (!cpu_has_cpufreq(cpu))
92 : : return 0;
93 : :
94 : 0 : reduction_pctg(cpu) = state;
95 : :
96 : : /*
97 : : * Update all the CPUs in the same package because they all
98 : : * contribute to the temperature and often share the same
99 : : * frequency.
100 : : */
101 [ # # ]: 0 : for_each_online_cpu(i) {
102 : 0 : if (topology_physical_package_id(i) !=
103 [ # # ]: 0 : topology_physical_package_id(cpu))
104 : 0 : continue;
105 : :
106 : 0 : pr = per_cpu(processors, i);
107 : :
108 [ # # # # ]: 0 : if (unlikely(!freq_qos_request_active(&pr->thermal_req)))
109 : 0 : continue;
110 : :
111 : 0 : policy = cpufreq_cpu_get(i);
112 [ # # ]: 0 : if (!policy)
113 : : return -EINVAL;
114 : :
115 : 0 : max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100;
116 : :
117 : 0 : cpufreq_cpu_put(policy);
118 : :
119 : 0 : ret = freq_qos_update_request(&pr->thermal_req, max_freq);
120 [ # # ]: 0 : if (ret < 0) {
121 : 0 : pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n",
122 : : pr->id, ret);
123 : : }
124 : : }
125 : : return 0;
126 : : }
127 : :
128 : 0 : void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
129 : : {
130 : 0 : unsigned int cpu;
131 : :
132 [ # # ]: 0 : for_each_cpu(cpu, policy->related_cpus) {
133 : 0 : struct acpi_processor *pr = per_cpu(processors, cpu);
134 : 0 : int ret;
135 : :
136 [ # # ]: 0 : if (!pr)
137 : 0 : continue;
138 : :
139 : 0 : ret = freq_qos_add_request(&policy->constraints,
140 : : &pr->thermal_req,
141 : : FREQ_QOS_MAX, INT_MAX);
142 [ # # ]: 0 : if (ret < 0)
143 : 0 : pr_err("Failed to add freq constraint for CPU%d (%d)\n",
144 : : cpu, ret);
145 : : }
146 : 0 : }
147 : :
148 : 0 : void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
149 : : {
150 : 0 : unsigned int cpu;
151 : :
152 [ # # ]: 0 : for_each_cpu(cpu, policy->related_cpus) {
153 : 0 : struct acpi_processor *pr = per_cpu(processors, policy->cpu);
154 : :
155 [ # # ]: 0 : if (pr)
156 : 0 : freq_qos_remove_request(&pr->thermal_req);
157 : : }
158 : 0 : }
159 : : #else /* ! CONFIG_CPU_FREQ */
160 : : static int cpufreq_get_max_state(unsigned int cpu)
161 : : {
162 : : return 0;
163 : : }
164 : :
165 : : static int cpufreq_get_cur_state(unsigned int cpu)
166 : : {
167 : : return 0;
168 : : }
169 : :
170 : : static int cpufreq_set_cur_state(unsigned int cpu, int state)
171 : : {
172 : : return 0;
173 : : }
174 : :
175 : : #endif
176 : :
177 : : /* thermal cooling device callbacks */
178 : 0 : static int acpi_processor_max_state(struct acpi_processor *pr)
179 : : {
180 : 0 : int max_state = 0;
181 : :
182 : : /*
183 : : * There exists four states according to
184 : : * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3
185 : : */
186 : 0 : max_state += cpufreq_get_max_state(pr->id);
187 [ # # ]: 0 : if (pr->flags.throttling)
188 : 0 : max_state += (pr->throttling.state_count -1);
189 : :
190 : 0 : return max_state;
191 : : }
192 : : static int
193 : 0 : processor_get_max_state(struct thermal_cooling_device *cdev,
194 : : unsigned long *state)
195 : : {
196 : 0 : struct acpi_device *device = cdev->devdata;
197 : 0 : struct acpi_processor *pr;
198 : :
199 [ # # ]: 0 : if (!device)
200 : : return -EINVAL;
201 : :
202 [ # # ]: 0 : pr = acpi_driver_data(device);
203 [ # # ]: 0 : if (!pr)
204 : : return -EINVAL;
205 : :
206 : 0 : *state = acpi_processor_max_state(pr);
207 : 0 : return 0;
208 : : }
209 : :
210 : : static int
211 : 0 : processor_get_cur_state(struct thermal_cooling_device *cdev,
212 : : unsigned long *cur_state)
213 : : {
214 : 0 : struct acpi_device *device = cdev->devdata;
215 : 0 : struct acpi_processor *pr;
216 : :
217 [ # # ]: 0 : if (!device)
218 : : return -EINVAL;
219 : :
220 [ # # ]: 0 : pr = acpi_driver_data(device);
221 [ # # ]: 0 : if (!pr)
222 : : return -EINVAL;
223 : :
224 : 0 : *cur_state = cpufreq_get_cur_state(pr->id);
225 [ # # ]: 0 : if (pr->flags.throttling)
226 : 0 : *cur_state += pr->throttling.state;
227 : : return 0;
228 : : }
229 : :
230 : : static int
231 : 0 : processor_set_cur_state(struct thermal_cooling_device *cdev,
232 : : unsigned long state)
233 : : {
234 : 0 : struct acpi_device *device = cdev->devdata;
235 : 0 : struct acpi_processor *pr;
236 : 0 : int result = 0;
237 : 0 : int max_pstate;
238 : :
239 [ # # ]: 0 : if (!device)
240 : : return -EINVAL;
241 : :
242 [ # # ]: 0 : pr = acpi_driver_data(device);
243 [ # # ]: 0 : if (!pr)
244 : : return -EINVAL;
245 : :
246 : 0 : max_pstate = cpufreq_get_max_state(pr->id);
247 : :
248 [ # # ]: 0 : if (state > acpi_processor_max_state(pr))
249 : : return -EINVAL;
250 : :
251 [ # # ]: 0 : if (state <= max_pstate) {
252 [ # # # # ]: 0 : if (pr->flags.throttling && pr->throttling.state)
253 : 0 : result = acpi_processor_set_throttling(pr, 0, false);
254 : 0 : cpufreq_set_cur_state(pr->id, state);
255 : : } else {
256 : 0 : cpufreq_set_cur_state(pr->id, max_pstate);
257 : 0 : result = acpi_processor_set_throttling(pr,
258 : 0 : state - max_pstate, false);
259 : : }
260 : : return result;
261 : : }
262 : :
263 : : const struct thermal_cooling_device_ops processor_cooling_ops = {
264 : : .get_max_state = processor_get_max_state,
265 : : .get_cur_state = processor_get_cur_state,
266 : : .set_cur_state = processor_set_cur_state,
267 : : };
|