root/drivers/acpi/processor_thermal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phys_package_first_cpu
  2. cpu_has_cpufreq
  3. cpufreq_get_max_state
  4. cpufreq_get_cur_state
  5. cpufreq_set_cur_state
  6. acpi_thermal_cpufreq_init
  7. acpi_thermal_cpufreq_exit
  8. cpufreq_get_max_state
  9. cpufreq_get_cur_state
  10. cpufreq_set_cur_state
  11. acpi_processor_max_state
  12. processor_get_max_state
  13. processor_get_cur_state
  14. processor_set_cur_state

   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
  24 ACPI_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 
  37 static 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  */
  49 static 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 
  60 static 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 
  68 static 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 
  76 static 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 
  84 static 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(!freq_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 = freq_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 
 128 void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
 129 {
 130         unsigned int cpu;
 131 
 132         for_each_cpu(cpu, policy->related_cpus) {
 133                 struct acpi_processor *pr = per_cpu(processors, cpu);
 134                 int ret;
 135 
 136                 if (!pr)
 137                         continue;
 138 
 139                 ret = freq_qos_add_request(&policy->constraints,
 140                                            &pr->thermal_req,
 141                                            FREQ_QOS_MAX, INT_MAX);
 142                 if (ret < 0)
 143                         pr_err("Failed to add freq constraint for CPU%d (%d)\n",
 144                                cpu, ret);
 145         }
 146 }
 147 
 148 void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
 149 {
 150         unsigned int cpu;
 151 
 152         for_each_cpu(cpu, policy->related_cpus) {
 153                 struct acpi_processor *pr = per_cpu(processors, policy->cpu);
 154 
 155                 if (pr)
 156                         freq_qos_remove_request(&pr->thermal_req);
 157         }
 158 }
 159 #else                           /* ! CONFIG_CPU_FREQ */
 160 static int cpufreq_get_max_state(unsigned int cpu)
 161 {
 162         return 0;
 163 }
 164 
 165 static int cpufreq_get_cur_state(unsigned int cpu)
 166 {
 167         return 0;
 168 }
 169 
 170 static int cpufreq_set_cur_state(unsigned int cpu, int state)
 171 {
 172         return 0;
 173 }
 174 
 175 #endif
 176 
 177 /* thermal cooling device callbacks */
 178 static int acpi_processor_max_state(struct acpi_processor *pr)
 179 {
 180         int max_state = 0;
 181 
 182         /*
 183          * There exists four states according to
 184          * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3
 185          */
 186         max_state += cpufreq_get_max_state(pr->id);
 187         if (pr->flags.throttling)
 188                 max_state += (pr->throttling.state_count -1);
 189 
 190         return max_state;
 191 }
 192 static int
 193 processor_get_max_state(struct thermal_cooling_device *cdev,
 194                         unsigned long *state)
 195 {
 196         struct acpi_device *device = cdev->devdata;
 197         struct acpi_processor *pr;
 198 
 199         if (!device)
 200                 return -EINVAL;
 201 
 202         pr = acpi_driver_data(device);
 203         if (!pr)
 204                 return -EINVAL;
 205 
 206         *state = acpi_processor_max_state(pr);
 207         return 0;
 208 }
 209 
 210 static int
 211 processor_get_cur_state(struct thermal_cooling_device *cdev,
 212                         unsigned long *cur_state)
 213 {
 214         struct acpi_device *device = cdev->devdata;
 215         struct acpi_processor *pr;
 216 
 217         if (!device)
 218                 return -EINVAL;
 219 
 220         pr = acpi_driver_data(device);
 221         if (!pr)
 222                 return -EINVAL;
 223 
 224         *cur_state = cpufreq_get_cur_state(pr->id);
 225         if (pr->flags.throttling)
 226                 *cur_state += pr->throttling.state;
 227         return 0;
 228 }
 229 
 230 static int
 231 processor_set_cur_state(struct thermal_cooling_device *cdev,
 232                         unsigned long state)
 233 {
 234         struct acpi_device *device = cdev->devdata;
 235         struct acpi_processor *pr;
 236         int result = 0;
 237         int max_pstate;
 238 
 239         if (!device)
 240                 return -EINVAL;
 241 
 242         pr = acpi_driver_data(device);
 243         if (!pr)
 244                 return -EINVAL;
 245 
 246         max_pstate = cpufreq_get_max_state(pr->id);
 247 
 248         if (state > acpi_processor_max_state(pr))
 249                 return -EINVAL;
 250 
 251         if (state <= max_pstate) {
 252                 if (pr->flags.throttling && pr->throttling.state)
 253                         result = acpi_processor_set_throttling(pr, 0, false);
 254                 cpufreq_set_cur_state(pr->id, state);
 255         } else {
 256                 cpufreq_set_cur_state(pr->id, max_pstate);
 257                 result = acpi_processor_set_throttling(pr,
 258                                 state - max_pstate, false);
 259         }
 260         return result;
 261 }
 262 
 263 const struct thermal_cooling_device_ops processor_cooling_ops = {
 264         .get_max_state = processor_get_max_state,
 265         .get_cur_state = processor_get_cur_state,
 266         .set_cur_state = processor_set_cur_state,
 267 };

/* [<][>][^][v][top][bottom][index][help] */