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 34 #include <asm/uaccess.h> 35 36 #include <acpi/acpi_bus.h> 37 #include <acpi/processor.h> 38 #include <acpi/acpi_drivers.h> 39 40 #define PREFIX "ACPI: " 41 42 #define ACPI_PROCESSOR_CLASS "processor" 43 #define _COMPONENT ACPI_PROCESSOR_COMPONENT 44 ACPI_MODULE_NAME("processor_thermal"); 45 46 #ifdef CONFIG_CPU_FREQ 47 48 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it 49 * offers (in most cases) voltage scaling in addition to frequency scaling, and 50 * thus a cubic (instead of linear) reduction of energy. Also, we allow for 51 * _any_ cpufreq driver and not only the acpi-cpufreq driver. 52 */ 53 54 #define CPUFREQ_THERMAL_MIN_STEP 0 55 #define CPUFREQ_THERMAL_MAX_STEP 3 56 57 static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); 58 static unsigned int acpi_thermal_cpufreq_is_init = 0; 59 60 static int cpu_has_cpufreq(unsigned int cpu) 61 { 62 struct cpufreq_policy policy; 63 if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu)) 64 return 0; 65 return 1; 66 } 67 68 static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, 69 unsigned long event, void *data) 70 { 71 struct cpufreq_policy *policy = data; 72 unsigned long max_freq = 0; 73 74 if (event != CPUFREQ_ADJUST) 75 goto out; 76 77 max_freq = ( 78 policy->cpuinfo.max_freq * 79 (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) 80 ) / 100; 81 82 cpufreq_verify_within_limits(policy, 0, max_freq); 83 84 out: 85 return 0; 86 } 87 88 static struct notifier_block acpi_thermal_cpufreq_notifier_block = { 89 .notifier_call = acpi_thermal_cpufreq_notifier, 90 }; 91 92 static int cpufreq_get_max_state(unsigned int cpu) 93 { 94 if (!cpu_has_cpufreq(cpu)) 95 return 0; 96 97 return CPUFREQ_THERMAL_MAX_STEP; 98 } 99 100 static int cpufreq_get_cur_state(unsigned int cpu) 101 { 102 if (!cpu_has_cpufreq(cpu)) 103 return 0; 104 105 return per_cpu(cpufreq_thermal_reduction_pctg, cpu); 106 } 107 108 static int cpufreq_set_cur_state(unsigned int cpu, int state) 109 { 110 if (!cpu_has_cpufreq(cpu)) 111 return 0; 112 113 per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; 114 cpufreq_update_policy(cpu); 115 return 0; 116 } 117 118 void acpi_thermal_cpufreq_init(void) 119 { 120 int i; 121 122 for (i = 0; i < nr_cpu_ids; i++) 123 if (cpu_present(i)) 124 per_cpu(cpufreq_thermal_reduction_pctg, i) = 0; 125 126 i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, 127 CPUFREQ_POLICY_NOTIFIER); 128 if (!i) 129 acpi_thermal_cpufreq_is_init = 1; 130 } 131 132 void acpi_thermal_cpufreq_exit(void) 133 { 134 if (acpi_thermal_cpufreq_is_init) 135 cpufreq_unregister_notifier 136 (&acpi_thermal_cpufreq_notifier_block, 137 CPUFREQ_POLICY_NOTIFIER); 138 139 acpi_thermal_cpufreq_is_init = 0; 140 } 141 142 #else /* ! CONFIG_CPU_FREQ */ 143 static int cpufreq_get_max_state(unsigned int cpu) 144 { 145 return 0; 146 } 147 148 static int cpufreq_get_cur_state(unsigned int cpu) 149 { 150 return 0; 151 } 152 153 static int cpufreq_set_cur_state(unsigned int cpu, int state) 154 { 155 return 0; 156 } 157 158 #endif 159 160 int acpi_processor_get_limit_info(struct acpi_processor *pr) 161 { 162 163 if (!pr) 164 return -EINVAL; 165 166 if (pr->flags.throttling) 167 pr->flags.limit = 1; 168 169 return 0; 170 } 171 172 /* thermal coolign device callbacks */ 173 static int acpi_processor_max_state(struct acpi_processor *pr) 174 { 175 int max_state = 0; 176 177 /* 178 * There exists four states according to 179 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 180 */ 181 max_state += cpufreq_get_max_state(pr->id); 182 if (pr->flags.throttling) 183 max_state += (pr->throttling.state_count -1); 184 185 return max_state; 186 } 187 static int 188 processor_get_max_state(struct thermal_cooling_device *cdev, 189 unsigned long *state) 190 { 191 struct acpi_device *device = cdev->devdata; 192 struct acpi_processor *pr = acpi_driver_data(device); 193 194 if (!device || !pr) 195 return -EINVAL; 196 197 *state = acpi_processor_max_state(pr); 198 return 0; 199 } 200 201 static int 202 processor_get_cur_state(struct thermal_cooling_device *cdev, 203 unsigned long *cur_state) 204 { 205 struct acpi_device *device = cdev->devdata; 206 struct acpi_processor *pr = acpi_driver_data(device); 207 208 if (!device || !pr) 209 return -EINVAL; 210 211 *cur_state = cpufreq_get_cur_state(pr->id); 212 if (pr->flags.throttling) 213 *cur_state += pr->throttling.state; 214 return 0; 215 } 216 217 static int 218 processor_set_cur_state(struct thermal_cooling_device *cdev, 219 unsigned long state) 220 { 221 struct acpi_device *device = cdev->devdata; 222 struct acpi_processor *pr = acpi_driver_data(device); 223 int result = 0; 224 int max_pstate; 225 226 if (!device || !pr) 227 return -EINVAL; 228 229 max_pstate = cpufreq_get_max_state(pr->id); 230 231 if (state > acpi_processor_max_state(pr)) 232 return -EINVAL; 233 234 if (state <= max_pstate) { 235 if (pr->flags.throttling && pr->throttling.state) 236 result = acpi_processor_set_throttling(pr, 0, false); 237 cpufreq_set_cur_state(pr->id, state); 238 } else { 239 cpufreq_set_cur_state(pr->id, max_pstate); 240 result = acpi_processor_set_throttling(pr, 241 state - max_pstate, false); 242 } 243 return result; 244 } 245 246 const struct thermal_cooling_device_ops processor_cooling_ops = { 247 .get_max_state = processor_get_max_state, 248 .get_cur_state = processor_get_cur_state, 249 .set_cur_state = processor_set_cur_state, 250 }; 251