at v5.4-rc2 257 lines 6.0 kB view raw
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 24ACPI_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 37static 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 */ 49static int phys_package_first_cpu(int cpu) 50{ 51 int i; 52 int id = topology_physical_package_id(cpu); 53 54 for_each_online_cpu(i) 55 if (topology_physical_package_id(i) == id) 56 return i; 57 return 0; 58} 59 60static int cpu_has_cpufreq(unsigned int cpu) 61{ 62 struct cpufreq_policy policy; 63 if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu)) 64 return 0; 65 return 1; 66} 67 68static int cpufreq_get_max_state(unsigned int cpu) 69{ 70 if (!cpu_has_cpufreq(cpu)) 71 return 0; 72 73 return CPUFREQ_THERMAL_MAX_STEP; 74} 75 76static int cpufreq_get_cur_state(unsigned int cpu) 77{ 78 if (!cpu_has_cpufreq(cpu)) 79 return 0; 80 81 return reduction_pctg(cpu); 82} 83 84static int cpufreq_set_cur_state(unsigned int cpu, int state) 85{ 86 struct cpufreq_policy *policy; 87 struct acpi_processor *pr; 88 unsigned long max_freq; 89 int i, ret; 90 91 if (!cpu_has_cpufreq(cpu)) 92 return 0; 93 94 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 for_each_online_cpu(i) { 102 if (topology_physical_package_id(i) != 103 topology_physical_package_id(cpu)) 104 continue; 105 106 pr = per_cpu(processors, i); 107 108 if (unlikely(!dev_pm_qos_request_active(&pr->thermal_req))) 109 continue; 110 111 policy = cpufreq_cpu_get(i); 112 if (!policy) 113 return -EINVAL; 114 115 max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100; 116 117 cpufreq_cpu_put(policy); 118 119 ret = dev_pm_qos_update_request(&pr->thermal_req, max_freq); 120 if (ret < 0) { 121 pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", 122 pr->id, ret); 123 } 124 } 125 return 0; 126} 127 128void acpi_thermal_cpufreq_init(int cpu) 129{ 130 struct acpi_processor *pr = per_cpu(processors, cpu); 131 int ret; 132 133 ret = dev_pm_qos_add_request(get_cpu_device(cpu), 134 &pr->thermal_req, DEV_PM_QOS_MAX_FREQUENCY, 135 INT_MAX); 136 if (ret < 0) { 137 pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu, 138 ret); 139 return; 140 } 141} 142 143void acpi_thermal_cpufreq_exit(int cpu) 144{ 145 struct acpi_processor *pr = per_cpu(processors, cpu); 146 147 dev_pm_qos_remove_request(&pr->thermal_req); 148} 149#else /* ! CONFIG_CPU_FREQ */ 150static int cpufreq_get_max_state(unsigned int cpu) 151{ 152 return 0; 153} 154 155static int cpufreq_get_cur_state(unsigned int cpu) 156{ 157 return 0; 158} 159 160static int cpufreq_set_cur_state(unsigned int cpu, int state) 161{ 162 return 0; 163} 164 165#endif 166 167/* thermal cooling device callbacks */ 168static int acpi_processor_max_state(struct acpi_processor *pr) 169{ 170 int max_state = 0; 171 172 /* 173 * There exists four states according to 174 * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3 175 */ 176 max_state += cpufreq_get_max_state(pr->id); 177 if (pr->flags.throttling) 178 max_state += (pr->throttling.state_count -1); 179 180 return max_state; 181} 182static int 183processor_get_max_state(struct thermal_cooling_device *cdev, 184 unsigned long *state) 185{ 186 struct acpi_device *device = cdev->devdata; 187 struct acpi_processor *pr; 188 189 if (!device) 190 return -EINVAL; 191 192 pr = acpi_driver_data(device); 193 if (!pr) 194 return -EINVAL; 195 196 *state = acpi_processor_max_state(pr); 197 return 0; 198} 199 200static int 201processor_get_cur_state(struct thermal_cooling_device *cdev, 202 unsigned long *cur_state) 203{ 204 struct acpi_device *device = cdev->devdata; 205 struct acpi_processor *pr; 206 207 if (!device) 208 return -EINVAL; 209 210 pr = acpi_driver_data(device); 211 if (!pr) 212 return -EINVAL; 213 214 *cur_state = cpufreq_get_cur_state(pr->id); 215 if (pr->flags.throttling) 216 *cur_state += pr->throttling.state; 217 return 0; 218} 219 220static int 221processor_set_cur_state(struct thermal_cooling_device *cdev, 222 unsigned long state) 223{ 224 struct acpi_device *device = cdev->devdata; 225 struct acpi_processor *pr; 226 int result = 0; 227 int max_pstate; 228 229 if (!device) 230 return -EINVAL; 231 232 pr = acpi_driver_data(device); 233 if (!pr) 234 return -EINVAL; 235 236 max_pstate = cpufreq_get_max_state(pr->id); 237 238 if (state > acpi_processor_max_state(pr)) 239 return -EINVAL; 240 241 if (state <= max_pstate) { 242 if (pr->flags.throttling && pr->throttling.state) 243 result = acpi_processor_set_throttling(pr, 0, false); 244 cpufreq_set_cur_state(pr->id, state); 245 } else { 246 cpufreq_set_cur_state(pr->id, max_pstate); 247 result = acpi_processor_set_throttling(pr, 248 state - max_pstate, false); 249 } 250 return result; 251} 252 253const struct thermal_cooling_device_ops processor_cooling_ops = { 254 .get_max_state = processor_get_max_state, 255 .get_cur_state = processor_get_cur_state, 256 .set_cur_state = processor_set_cur_state, 257};