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