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