1 /* 2 * processor_thermal.c - Passive cooling submodule of the ACPI processor driver 3 * 4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 6 * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> 7 * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> 8 * - Added processor hotplug support 9 * 10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or (at 15 * your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License along 23 * with this program; if not, write to the Free Software Foundation, Inc., 24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 25 * 26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 */ 28 29 #include <linux/kernel.h> 30 #include <linux/module.h> 31 #include <linux/init.h> 32 #include <linux/cpufreq.h> 33 #include <linux/sysdev.h> 34 35 #include <asm/uaccess.h> 36 37 #include <acpi/acpi_bus.h> 38 #include <acpi/processor.h> 39 #include <acpi/acpi_drivers.h> 40 41 #define PREFIX "ACPI: " 42 43 #define ACPI_PROCESSOR_CLASS "processor" 44 #define _COMPONENT ACPI_PROCESSOR_COMPONENT 45 ACPI_MODULE_NAME("processor_thermal"); 46 47 #ifdef CONFIG_CPU_FREQ 48 49 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it 50 * offers (in most cases) voltage scaling in addition to frequency scaling, and 51 * thus a cubic (instead of linear) reduction of energy. Also, we allow for 52 * _any_ cpufreq driver and not only the acpi-cpufreq driver. 53 */ 54 55 #define CPUFREQ_THERMAL_MIN_STEP 0 56 #define CPUFREQ_THERMAL_MAX_STEP 3 57 58 static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); 59 static unsigned int acpi_thermal_cpufreq_is_init = 0; 60 61 static int cpu_has_cpufreq(unsigned int cpu) 62 { 63 struct cpufreq_policy policy; 64 if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu)) 65 return 0; 66 return 1; 67 } 68 69 static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, 70 unsigned long event, void *data) 71 { 72 struct cpufreq_policy *policy = data; 73 unsigned long max_freq = 0; 74 75 if (event != CPUFREQ_ADJUST) 76 goto out; 77 78 max_freq = ( 79 policy->cpuinfo.max_freq * 80 (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) 81 ) / 100; 82 83 cpufreq_verify_within_limits(policy, 0, max_freq); 84 85 out: 86 return 0; 87 } 88 89 static struct notifier_block acpi_thermal_cpufreq_notifier_block = { 90 .notifier_call = acpi_thermal_cpufreq_notifier, 91 }; 92 93 static int cpufreq_get_max_state(unsigned int cpu) 94 { 95 if (!cpu_has_cpufreq(cpu)) 96 return 0; 97 98 return CPUFREQ_THERMAL_MAX_STEP; 99 } 100 101 static int cpufreq_get_cur_state(unsigned int cpu) 102 { 103 if (!cpu_has_cpufreq(cpu)) 104 return 0; 105 106 return per_cpu(cpufreq_thermal_reduction_pctg, cpu); 107 } 108 109 static int cpufreq_set_cur_state(unsigned int cpu, int state) 110 { 111 if (!cpu_has_cpufreq(cpu)) 112 return 0; 113 114 per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; 115 cpufreq_update_policy(cpu); 116 return 0; 117 } 118 119 void acpi_thermal_cpufreq_init(void) 120 { 121 int i; 122 123 for (i = 0; i < nr_cpu_ids; i++) 124 if (cpu_present(i)) 125 per_cpu(cpufreq_thermal_reduction_pctg, i) = 0; 126 127 i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, 128 CPUFREQ_POLICY_NOTIFIER); 129 if (!i) 130 acpi_thermal_cpufreq_is_init = 1; 131 } 132 133 void acpi_thermal_cpufreq_exit(void) 134 { 135 if (acpi_thermal_cpufreq_is_init) 136 cpufreq_unregister_notifier 137 (&acpi_thermal_cpufreq_notifier_block, 138 CPUFREQ_POLICY_NOTIFIER); 139 140 acpi_thermal_cpufreq_is_init = 0; 141 } 142 143 #else /* ! CONFIG_CPU_FREQ */ 144 static int cpufreq_get_max_state(unsigned int cpu) 145 { 146 return 0; 147 } 148 149 static int cpufreq_get_cur_state(unsigned int cpu) 150 { 151 return 0; 152 } 153 154 static int cpufreq_set_cur_state(unsigned int cpu, int state) 155 { 156 return 0; 157 } 158 159 static int acpi_thermal_cpufreq_increase(unsigned int cpu) 160 { 161 return -ENODEV; 162 } 163 static int acpi_thermal_cpufreq_decrease(unsigned int cpu) 164 { 165 return -ENODEV; 166 } 167 168 #endif 169 170 int acpi_processor_get_limit_info(struct acpi_processor *pr) 171 { 172 173 if (!pr) 174 return -EINVAL; 175 176 if (pr->flags.throttling) 177 pr->flags.limit = 1; 178 179 return 0; 180 } 181 182 /* thermal coolign device callbacks */ 183 static int acpi_processor_max_state(struct acpi_processor *pr) 184 { 185 int max_state = 0; 186 187 /* 188 * There exists four states according to 189 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 190 */ 191 max_state += cpufreq_get_max_state(pr->id); 192 if (pr->flags.throttling) 193 max_state += (pr->throttling.state_count -1); 194 195 return max_state; 196 } 197 static int 198 processor_get_max_state(struct thermal_cooling_device *cdev, 199 unsigned long *state) 200 { 201 struct acpi_device *device = cdev->devdata; 202 struct acpi_processor *pr = acpi_driver_data(device); 203 204 if (!device || !pr) 205 return -EINVAL; 206 207 *state = acpi_processor_max_state(pr); 208 return 0; 209 } 210 211 static int 212 processor_get_cur_state(struct thermal_cooling_device *cdev, 213 unsigned long *cur_state) 214 { 215 struct acpi_device *device = cdev->devdata; 216 struct acpi_processor *pr = acpi_driver_data(device); 217 218 if (!device || !pr) 219 return -EINVAL; 220 221 *cur_state = cpufreq_get_cur_state(pr->id); 222 if (pr->flags.throttling) 223 *cur_state += pr->throttling.state; 224 return 0; 225 } 226 227 static int 228 processor_set_cur_state(struct thermal_cooling_device *cdev, 229 unsigned long state) 230 { 231 struct acpi_device *device = cdev->devdata; 232 struct acpi_processor *pr = acpi_driver_data(device); 233 int result = 0; 234 int max_pstate; 235 236 if (!device || !pr) 237 return -EINVAL; 238 239 max_pstate = cpufreq_get_max_state(pr->id); 240 241 if (state > acpi_processor_max_state(pr)) 242 return -EINVAL; 243 244 if (state <= max_pstate) { 245 if (pr->flags.throttling && pr->throttling.state) 246 result = acpi_processor_set_throttling(pr, 0, false); 247 cpufreq_set_cur_state(pr->id, state); 248 } else { 249 cpufreq_set_cur_state(pr->id, max_pstate); 250 result = acpi_processor_set_throttling(pr, 251 state - max_pstate, false); 252 } 253 return result; 254 } 255 256 struct thermal_cooling_device_ops processor_cooling_ops = { 257 .get_max_state = processor_get_max_state, 258 .get_cur_state = processor_get_cur_state, 259 .set_cur_state = processor_set_cur_state, 260 }; 261