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