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 58 if (!acpi_processor_cpufreq_init) 59 return 0; 60 61 policy = cpufreq_cpu_get(cpu); 62 if (policy) { 63 cpufreq_cpu_put(policy); 64 return 1; 65 } 66 return 0; 67 } 68 69 static int cpufreq_get_max_state(unsigned int cpu) 70 { 71 if (!cpu_has_cpufreq(cpu)) 72 return 0; 73 74 return CPUFREQ_THERMAL_MAX_STEP; 75 } 76 77 static int cpufreq_get_cur_state(unsigned int cpu) 78 { 79 if (!cpu_has_cpufreq(cpu)) 80 return 0; 81 82 return reduction_pctg(cpu); 83 } 84 85 static int cpufreq_set_cur_state(unsigned int cpu, int state) 86 { 87 struct cpufreq_policy *policy; 88 struct acpi_processor *pr; 89 unsigned long max_freq; 90 int i, ret; 91 92 if (!cpu_has_cpufreq(cpu)) 93 return 0; 94 95 reduction_pctg(cpu) = state; 96 97 /* 98 * Update all the CPUs in the same package because they all 99 * contribute to the temperature and often share the same 100 * frequency. 101 */ 102 for_each_online_cpu(i) { 103 if (topology_physical_package_id(i) != 104 topology_physical_package_id(cpu)) 105 continue; 106 107 pr = per_cpu(processors, i); 108 109 if (unlikely(!freq_qos_request_active(&pr->thermal_req))) 110 continue; 111 112 policy = cpufreq_cpu_get(i); 113 if (!policy) 114 return -EINVAL; 115 116 max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100; 117 118 cpufreq_cpu_put(policy); 119 120 ret = freq_qos_update_request(&pr->thermal_req, max_freq); 121 if (ret < 0) { 122 pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", 123 pr->id, ret); 124 } 125 } 126 return 0; 127 } 128 129 void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy) 130 { 131 unsigned int cpu; 132 133 for_each_cpu(cpu, policy->related_cpus) { 134 struct acpi_processor *pr = per_cpu(processors, cpu); 135 int ret; 136 137 if (!pr) 138 continue; 139 140 ret = freq_qos_add_request(&policy->constraints, 141 &pr->thermal_req, 142 FREQ_QOS_MAX, INT_MAX); 143 if (ret < 0) { 144 pr_err("Failed to add freq constraint for CPU%d (%d)\n", 145 cpu, ret); 146 continue; 147 } 148 149 thermal_cooling_device_update(pr->cdev); 150 } 151 } 152 153 void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy) 154 { 155 unsigned int cpu; 156 157 for_each_cpu(cpu, policy->related_cpus) { 158 struct acpi_processor *pr = per_cpu(processors, cpu); 159 160 if (!pr) 161 continue; 162 163 freq_qos_remove_request(&pr->thermal_req); 164 165 thermal_cooling_device_update(pr->cdev); 166 } 167 } 168 #else /* ! CONFIG_CPU_FREQ */ 169 static int cpufreq_get_max_state(unsigned int cpu) 170 { 171 return 0; 172 } 173 174 static int cpufreq_get_cur_state(unsigned int cpu) 175 { 176 return 0; 177 } 178 179 static int cpufreq_set_cur_state(unsigned int cpu, int state) 180 { 181 return 0; 182 } 183 184 #endif 185 186 /* thermal cooling device callbacks */ 187 static int acpi_processor_max_state(struct acpi_processor *pr) 188 { 189 int max_state = 0; 190 191 /* 192 * There exists four states according to 193 * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3 194 */ 195 max_state += cpufreq_get_max_state(pr->id); 196 if (pr->flags.throttling) 197 max_state += (pr->throttling.state_count -1); 198 199 return max_state; 200 } 201 static int 202 processor_get_max_state(struct thermal_cooling_device *cdev, 203 unsigned long *state) 204 { 205 struct acpi_device *device = cdev->devdata; 206 struct acpi_processor *pr; 207 208 if (!device) 209 return -EINVAL; 210 211 pr = acpi_driver_data(device); 212 if (!pr) 213 return -EINVAL; 214 215 *state = acpi_processor_max_state(pr); 216 return 0; 217 } 218 219 static int 220 processor_get_cur_state(struct thermal_cooling_device *cdev, 221 unsigned long *cur_state) 222 { 223 struct acpi_device *device = cdev->devdata; 224 struct acpi_processor *pr; 225 226 if (!device) 227 return -EINVAL; 228 229 pr = acpi_driver_data(device); 230 if (!pr) 231 return -EINVAL; 232 233 *cur_state = cpufreq_get_cur_state(pr->id); 234 if (pr->flags.throttling) 235 *cur_state += pr->throttling.state; 236 return 0; 237 } 238 239 static int 240 processor_set_cur_state(struct thermal_cooling_device *cdev, 241 unsigned long state) 242 { 243 struct acpi_device *device = cdev->devdata; 244 struct acpi_processor *pr; 245 int result = 0; 246 int max_pstate; 247 248 if (!device) 249 return -EINVAL; 250 251 pr = acpi_driver_data(device); 252 if (!pr) 253 return -EINVAL; 254 255 max_pstate = cpufreq_get_max_state(pr->id); 256 257 if (state > acpi_processor_max_state(pr)) 258 return -EINVAL; 259 260 if (state <= max_pstate) { 261 if (pr->flags.throttling && pr->throttling.state) 262 result = acpi_processor_set_throttling(pr, 0, false); 263 cpufreq_set_cur_state(pr->id, state); 264 } else { 265 cpufreq_set_cur_state(pr->id, max_pstate); 266 result = acpi_processor_set_throttling(pr, 267 state - max_pstate, false); 268 } 269 return result; 270 } 271 272 const struct thermal_cooling_device_ops processor_cooling_ops = { 273 .get_max_state = processor_get_max_state, 274 .get_cur_state = processor_get_cur_state, 275 .set_cur_state = processor_set_cur_state, 276 }; 277 278 int acpi_processor_thermal_init(struct acpi_processor *pr, 279 struct acpi_device *device) 280 { 281 int result = 0; 282 283 pr->cdev = thermal_cooling_device_register("Processor", device, 284 &processor_cooling_ops); 285 if (IS_ERR(pr->cdev)) { 286 result = PTR_ERR(pr->cdev); 287 return result; 288 } 289 290 dev_dbg(&device->dev, "registered as cooling_device%d\n", 291 pr->cdev->id); 292 293 result = sysfs_create_link(&device->dev.kobj, 294 &pr->cdev->device.kobj, 295 "thermal_cooling"); 296 if (result) { 297 dev_err(&device->dev, 298 "Failed to create sysfs link 'thermal_cooling'\n"); 299 goto err_thermal_unregister; 300 } 301 302 result = sysfs_create_link(&pr->cdev->device.kobj, 303 &device->dev.kobj, 304 "device"); 305 if (result) { 306 dev_err(&pr->cdev->device, 307 "Failed to create sysfs link 'device'\n"); 308 goto err_remove_sysfs_thermal; 309 } 310 311 return 0; 312 313 err_remove_sysfs_thermal: 314 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 315 err_thermal_unregister: 316 thermal_cooling_device_unregister(pr->cdev); 317 318 return result; 319 } 320 321 void acpi_processor_thermal_exit(struct acpi_processor *pr, 322 struct acpi_device *device) 323 { 324 if (pr->cdev) { 325 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 326 sysfs_remove_link(&pr->cdev->device.kobj, "device"); 327 thermal_cooling_device_unregister(pr->cdev); 328 pr->cdev = NULL; 329 } 330 } 331