Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branches 'release' and 'menlo' into release

Conflicts:

drivers/acpi/video.c

Signed-off-by: Len Brown <len.brown@intel.com>

Len Brown 26b6f223 e5e54bc8

+2455 -175
+246
Documentation/thermal/sysfs-api.txt
··· 1 + Generic Thermal Sysfs driver How To 2 + ========================= 3 + 4 + Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com> 5 + 6 + Updated: 2 January 2008 7 + 8 + Copyright (c) 2008 Intel Corporation 9 + 10 + 11 + 0. Introduction 12 + 13 + The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors) 14 + and thermal cooling devices (fan, processor...) to register with the thermal management 15 + solution and to be a part of it. 16 + 17 + This how-to focusses on enabling new thermal zone and cooling devices to participate 18 + in thermal management. 19 + This solution is platform independent and any type of thermal zone devices and 20 + cooling devices should be able to make use of the infrastructure. 21 + 22 + The main task of the thermal sysfs driver is to expose thermal zone attributes as well 23 + as cooling device attributes to the user space. 24 + An intelligent thermal management application can make decisions based on inputs 25 + from thermal zone attributes (the current temperature and trip point temperature) 26 + and throttle appropriate devices. 27 + 28 + [0-*] denotes any positive number starting from 0 29 + [1-*] denotes any positive number starting from 1 30 + 31 + 1. thermal sysfs driver interface functions 32 + 33 + 1.1 thermal zone device interface 34 + 1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips, 35 + void *devdata, struct thermal_zone_device_ops *ops) 36 + 37 + This interface function adds a new thermal zone device (sensor) to 38 + /sys/class/thermal folder as thermal_zone[0-*]. 39 + It tries to bind all the thermal cooling devices registered at the same time. 40 + 41 + name: the thermal zone name. 42 + trips: the total number of trip points this thermal zone supports. 43 + devdata: device private data 44 + ops: thermal zone device callbacks. 45 + .bind: bind the thermal zone device with a thermal cooling device. 46 + .unbind: unbing the thermal zone device with a thermal cooling device. 47 + .get_temp: get the current temperature of the thermal zone. 48 + .get_mode: get the current mode (user/kernel) of the thermal zone. 49 + "kernel" means thermal management is done in kernel. 50 + "user" will prevent kernel thermal driver actions upon trip points 51 + so that user applications can take charge of thermal management. 52 + .set_mode: set the mode (user/kernel) of the thermal zone. 53 + .get_trip_type: get the type of certain trip point. 54 + .get_trip_temp: get the temperature above which the certain trip point 55 + will be fired. 56 + 57 + 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) 58 + 59 + This interface function removes the thermal zone device. 60 + It deletes the corresponding entry form /sys/class/thermal folder and unbind all 61 + the thermal cooling devices it uses. 62 + 63 + 1.2 thermal cooling device interface 64 + 1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name, 65 + void *devdata, struct thermal_cooling_device_ops *) 66 + 67 + This interface function adds a new thermal cooling device (fan/processor/...) to 68 + /sys/class/thermal/ folder as cooling_device[0-*]. 69 + It tries to bind itself to all the thermal zone devices register at the same time. 70 + name: the cooling device name. 71 + devdata: device private data. 72 + ops: thermal cooling devices callbacks. 73 + .get_max_state: get the Maximum throttle state of the cooling device. 74 + .get_cur_state: get the Current throttle state of the cooling device. 75 + .set_cur_state: set the Current throttle state of the cooling device. 76 + 77 + 1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) 78 + 79 + This interface function remove the thermal cooling device. 80 + It deletes the corresponding entry form /sys/class/thermal folder and unbind 81 + itself from all the thermal zone devices using it. 82 + 83 + 1.3 interface for binding a thermal zone device with a thermal cooling device 84 + 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, 85 + int trip, struct thermal_cooling_device *cdev); 86 + 87 + This interface function bind a thermal cooling device to the certain trip point 88 + of a thermal zone device. 89 + This function is usually called in the thermal zone device .bind callback. 90 + tz: the thermal zone device 91 + cdev: thermal cooling device 92 + trip: indicates which trip point the cooling devices is associated with 93 + in this thermal zone. 94 + 95 + 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, 96 + int trip, struct thermal_cooling_device *cdev); 97 + 98 + This interface function unbind a thermal cooling device from the certain trip point 99 + of a thermal zone device. 100 + This function is usually called in the thermal zone device .unbind callback. 101 + tz: the thermal zone device 102 + cdev: thermal cooling device 103 + trip: indicates which trip point the cooling devices is associated with 104 + in this thermal zone. 105 + 106 + 2. sysfs attributes structure 107 + 108 + RO read only value 109 + RW read/write value 110 + 111 + All thermal sysfs attributes will be represented under /sys/class/thermal 112 + /sys/class/thermal/ 113 + 114 + Thermal zone device sys I/F, created once it's registered: 115 + |thermal_zone[0-*]: 116 + |-----type: Type of the thermal zone 117 + |-----temp: Current temperature 118 + |-----mode: Working mode of the thermal zone 119 + |-----trip_point_[0-*]_temp: Trip point temperature 120 + |-----trip_point_[0-*]_type: Trip point type 121 + 122 + Thermal cooling device sys I/F, created once it's registered: 123 + |cooling_device[0-*]: 124 + |-----type : Type of the cooling device(processor/fan/...) 125 + |-----max_state: Maximum cooling state of the cooling device 126 + |-----cur_state: Current cooling state of the cooling device 127 + 128 + 129 + These two dynamic attributes are created/removed in pairs. 130 + They represent the relationship between a thermal zone and its associated cooling device. 131 + They are created/removed for each 132 + thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection. 133 + 134 + |thermal_zone[0-*] 135 + |-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone 136 + |-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with 137 + 138 + 139 + *************************** 140 + * Thermal zone attributes * 141 + *************************** 142 + 143 + type Strings which represent the thermal zone type. 144 + This is given by thermal zone driver as part of registration. 145 + Eg: "ACPI thermal zone" indicates it's a ACPI thermal device 146 + RO 147 + Optional 148 + 149 + temp Current temperature as reported by thermal zone (sensor) 150 + Unit: degree celsius 151 + RO 152 + Required 153 + 154 + mode One of the predifned values in [kernel, user] 155 + This file gives information about the algorithm 156 + that is currently managing the thermal zone. 157 + It can be either default kernel based algorithm 158 + or user space application. 159 + RW 160 + Optional 161 + kernel = Thermal management in kernel thermal zone driver. 162 + user = Preventing kernel thermal zone driver actions upon 163 + trip points so that user application can take full 164 + charge of the thermal management. 165 + 166 + trip_point_[0-*]_temp The temperature above which trip point will be fired 167 + Unit: degree celsius 168 + RO 169 + Optional 170 + 171 + trip_point_[0-*]_type Strings which indicate the type of the trip point 172 + Eg. it can be one of critical, hot, passive, 173 + active[0-*] for ACPI thermal zone. 174 + RO 175 + Optional 176 + 177 + cdev[0-*] Sysfs link to the thermal cooling device node where the sys I/F 178 + for cooling device throttling control represents. 179 + RO 180 + Optional 181 + 182 + cdev[0-*]_trip_point The trip point with which cdev[0-*] is assocated in this thermal zone 183 + -1 means the cooling device is not associated with any trip point. 184 + RO 185 + Optional 186 + 187 + ****************************** 188 + * Cooling device attributes * 189 + ****************************** 190 + 191 + type String which represents the type of device 192 + eg: For generic ACPI: this should be "Fan", 193 + "Processor" or "LCD" 194 + eg. For memory controller device on intel_menlow platform: 195 + this should be "Memory controller" 196 + RO 197 + Optional 198 + 199 + max_state The maximum permissible cooling state of this cooling device. 200 + RO 201 + Required 202 + 203 + cur_state The current cooling state of this cooling device. 204 + the value can any integer numbers between 0 and max_state, 205 + cur_state == 0 means no cooling 206 + cur_state == max_state means the maximum cooling. 207 + RW 208 + Required 209 + 210 + 3. A simple implementation 211 + 212 + ACPI thermal zone may support multiple trip points like critical/hot/passive/active. 213 + If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time, 214 + it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all. 215 + It has one processor and one fan, which are both registered as thermal_cooling_device. 216 + If the processor is listed in _PSL method, and the fan is listed in _AL0 method, 217 + the sys I/F structure will be built like this: 218 + 219 + /sys/class/thermal: 220 + 221 + |thermal_zone1: 222 + |-----type: ACPI thermal zone 223 + |-----temp: 37 224 + |-----mode: kernel 225 + |-----trip_point_0_temp: 100 226 + |-----trip_point_0_type: critical 227 + |-----trip_point_1_temp: 80 228 + |-----trip_point_1_type: passive 229 + |-----trip_point_2_temp: 70 230 + |-----trip_point_2_type: active[0] 231 + |-----trip_point_3_temp: 60 232 + |-----trip_point_3_type: active[1] 233 + |-----cdev0: --->/sys/class/thermal/cooling_device0 234 + |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ 235 + |-----cdev1: --->/sys/class/thermal/cooling_device3 236 + |-----cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/ 237 + 238 + |cooling_device0: 239 + |-----type: Processor 240 + |-----max_state: 8 241 + |-----cur_state: 0 242 + 243 + |cooling_device3: 244 + |-----type: Fan 245 + |-----max_state: 2 246 + |-----cur_state: 0
+2
drivers/Kconfig
··· 60 60 61 61 source "drivers/hwmon/Kconfig" 62 62 63 + source "drivers/thermal/Kconfig" 64 + 63 65 source "drivers/watchdog/Kconfig" 64 66 65 67 source "drivers/ssb/Kconfig"
+1
drivers/Makefile
··· 65 65 obj-$(CONFIG_W1) += w1/ 66 66 obj-$(CONFIG_POWER_SUPPLY) += power/ 67 67 obj-$(CONFIG_HWMON) += hwmon/ 68 + obj-$(CONFIG_THERMAL) += thermal/ 68 69 obj-$(CONFIG_WATCHDOG) += watchdog/ 69 70 obj-$(CONFIG_PHONE) += telephony/ 70 71 obj-$(CONFIG_MD) += md/
+1
drivers/acpi/Kconfig
··· 186 186 config ACPI_THERMAL 187 187 tristate "Thermal Zone" 188 188 depends on ACPI_PROCESSOR 189 + select THERMAL 189 190 default y 190 191 help 191 192 This driver adds support for ACPI thermal zones. Most mobile and
+25
drivers/acpi/bus.c
··· 122 122 123 123 EXPORT_SYMBOL(acpi_bus_get_status); 124 124 125 + void acpi_bus_private_data_handler(acpi_handle handle, 126 + u32 function, void *context) 127 + { 128 + return; 129 + } 130 + EXPORT_SYMBOL(acpi_bus_private_data_handler); 131 + 132 + int acpi_bus_get_private_data(acpi_handle handle, void **data) 133 + { 134 + acpi_status status = AE_OK; 135 + 136 + if (!*data) 137 + return -EINVAL; 138 + 139 + status = acpi_get_data(handle, acpi_bus_private_data_handler, data); 140 + if (ACPI_FAILURE(status) || !*data) { 141 + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", 142 + handle)); 143 + return -ENODEV; 144 + } 145 + 146 + return 0; 147 + } 148 + EXPORT_SYMBOL(acpi_bus_get_private_data); 149 + 125 150 /* -------------------------------------------------------------------------- 126 151 Power Management 127 152 -------------------------------------------------------------------------- */
+85 -7
drivers/acpi/fan.c
··· 30 30 #include <linux/proc_fs.h> 31 31 #include <linux/seq_file.h> 32 32 #include <asm/uaccess.h> 33 - 33 + #include <linux/thermal.h> 34 34 #include <acpi/acpi_bus.h> 35 35 #include <acpi/acpi_drivers.h> 36 36 ··· 68 68 }, 69 69 }; 70 70 71 + /* thermal cooling device callbacks */ 72 + static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf) 73 + { 74 + /* ACPI fan device only support two states: ON/OFF */ 75 + return sprintf(buf, "1\n"); 76 + } 77 + 78 + static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf) 79 + { 80 + struct acpi_device *device = cdev->devdata; 81 + int state; 82 + int result; 83 + 84 + if (!device) 85 + return -EINVAL; 86 + 87 + result = acpi_bus_get_power(device->handle, &state); 88 + if (result) 89 + return result; 90 + 91 + return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" : 92 + (state == ACPI_STATE_D0 ? "1" : "unknown")); 93 + } 94 + 95 + static int 96 + fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) 97 + { 98 + struct acpi_device *device = cdev->devdata; 99 + int result; 100 + 101 + if (!device || (state != 0 && state != 1)) 102 + return -EINVAL; 103 + 104 + result = acpi_bus_set_power(device->handle, 105 + state ? ACPI_STATE_D0 : ACPI_STATE_D3); 106 + 107 + return result; 108 + } 109 + 110 + static struct thermal_cooling_device_ops fan_cooling_ops = { 111 + .get_max_state = fan_get_max_state, 112 + .get_cur_state = fan_get_cur_state, 113 + .set_cur_state = fan_set_cur_state, 114 + }; 115 + 71 116 /* -------------------------------------------------------------------------- 72 117 FS Interface (/proc) 73 118 -------------------------------------------------------------------------- */ 119 + #ifdef CONFIG_ACPI_PROCFS 74 120 75 121 static struct proc_dir_entry *acpi_fan_dir; 76 122 ··· 217 171 218 172 return 0; 219 173 } 174 + #else 175 + static int acpi_fan_add_fs(struct acpi_device *device) 176 + { 177 + return 0; 178 + } 220 179 180 + static int acpi_fan_remove_fs(struct acpi_device *device) 181 + { 182 + return 0; 183 + } 184 + #endif 221 185 /* -------------------------------------------------------------------------- 222 186 Driver Interface 223 187 -------------------------------------------------------------------------- */ ··· 235 179 static int acpi_fan_add(struct acpi_device *device) 236 180 { 237 181 int result = 0; 238 - struct acpi_fan *fan = NULL; 239 182 int state = 0; 240 - 183 + struct thermal_cooling_device *cdev; 241 184 242 185 if (!device) 243 186 return -EINVAL; ··· 254 199 acpi_bus_set_power(device->handle, state); 255 200 device->flags.force_power_state = 0; 256 201 202 + cdev = thermal_cooling_device_register("Fan", device, 203 + &fan_cooling_ops); 204 + if (cdev) 205 + printk(KERN_INFO PREFIX 206 + "%s is registered as cooling_device%d\n", 207 + device->dev.bus_id, cdev->id); 208 + else 209 + goto end; 210 + acpi_driver_data(device) = cdev; 211 + result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, 212 + "thermal_cooling"); 213 + if (result) 214 + return result; 215 + 216 + result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, 217 + "device"); 218 + if (result) 219 + return result; 220 + 257 221 result = acpi_fan_add_fs(device); 258 222 if (result) 259 223 goto end; ··· 282 208 !device->power.state ? "on" : "off"); 283 209 284 210 end: 285 - if (result) 286 - kfree(fan); 287 - 288 211 return result; 289 212 } 290 213 291 214 static int acpi_fan_remove(struct acpi_device *device, int type) 292 215 { 293 - if (!device || !acpi_driver_data(device)) 216 + struct thermal_cooling_device *cdev = acpi_driver_data(device); 217 + 218 + if (!device || !cdev) 294 219 return -EINVAL; 295 220 296 221 acpi_fan_remove_fs(device); 222 + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 223 + sysfs_remove_link(&cdev->device.kobj, "device"); 224 + thermal_cooling_device_unregister(cdev); 297 225 298 226 return 0; 299 227 } ··· 337 261 int result = 0; 338 262 339 263 264 + #ifdef CONFIG_ACPI_PROCFS 340 265 acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); 341 266 if (!acpi_fan_dir) 342 267 return -ENODEV; 343 268 acpi_fan_dir->owner = THIS_MODULE; 269 + #endif 344 270 345 271 result = acpi_bus_register_driver(&acpi_fan_driver); 346 272 if (result < 0) {
+23
drivers/acpi/processor_core.c
··· 668 668 669 669 acpi_processor_power_init(pr, device); 670 670 671 + pr->cdev = thermal_cooling_device_register("Processor", device, 672 + &processor_cooling_ops); 673 + if (pr->cdev) 674 + printk(KERN_INFO PREFIX 675 + "%s is registered as cooling_device%d\n", 676 + device->dev.bus_id, pr->cdev->id); 677 + else 678 + goto end; 679 + 680 + result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, 681 + "thermal_cooling"); 682 + if (result) 683 + return result; 684 + result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, 685 + "device"); 686 + if (result) 687 + return result; 688 + 671 689 if (pr->flags.throttling) { 672 690 printk(KERN_INFO PREFIX "%s [%s] (supports", 673 691 acpi_device_name(device), acpi_device_bid(device)); ··· 808 790 acpi_processor_notify); 809 791 810 792 acpi_processor_remove_fs(device); 793 + 794 + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 795 + sysfs_remove_link(&pr->cdev->device.kobj, "device"); 796 + thermal_cooling_device_unregister(pr->cdev); 797 + pr->cdev = NULL; 811 798 812 799 processors[pr->id] = NULL; 813 800
+129 -5
drivers/acpi/processor_thermal.c
··· 32 32 #include <linux/cpufreq.h> 33 33 #include <linux/proc_fs.h> 34 34 #include <linux/seq_file.h> 35 + #include <linux/sysdev.h> 35 36 36 37 #include <asm/uaccess.h> 37 38 ··· 94 93 * _any_ cpufreq driver and not only the acpi-cpufreq driver. 95 94 */ 96 95 96 + #define CPUFREQ_THERMAL_MIN_STEP 0 97 + #define CPUFREQ_THERMAL_MAX_STEP 3 98 + 97 99 static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; 98 100 static unsigned int acpi_thermal_cpufreq_is_init = 0; 99 101 ··· 113 109 if (!cpu_has_cpufreq(cpu)) 114 110 return -ENODEV; 115 111 116 - if (cpufreq_thermal_reduction_pctg[cpu] < 60) { 117 - cpufreq_thermal_reduction_pctg[cpu] += 20; 112 + if (cpufreq_thermal_reduction_pctg[cpu] < 113 + CPUFREQ_THERMAL_MAX_STEP) { 114 + cpufreq_thermal_reduction_pctg[cpu]++; 118 115 cpufreq_update_policy(cpu); 119 116 return 0; 120 117 } ··· 128 123 if (!cpu_has_cpufreq(cpu)) 129 124 return -ENODEV; 130 125 131 - if (cpufreq_thermal_reduction_pctg[cpu] > 20) 132 - cpufreq_thermal_reduction_pctg[cpu] -= 20; 126 + if (cpufreq_thermal_reduction_pctg[cpu] > 127 + (CPUFREQ_THERMAL_MIN_STEP + 1)) 128 + cpufreq_thermal_reduction_pctg[cpu]--; 133 129 else 134 130 cpufreq_thermal_reduction_pctg[cpu] = 0; 135 131 cpufreq_update_policy(cpu); ··· 149 143 150 144 max_freq = 151 145 (policy->cpuinfo.max_freq * 152 - (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; 146 + (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; 153 147 154 148 cpufreq_verify_within_limits(policy, 0, max_freq); 155 149 ··· 160 154 static struct notifier_block acpi_thermal_cpufreq_notifier_block = { 161 155 .notifier_call = acpi_thermal_cpufreq_notifier, 162 156 }; 157 + 158 + static int cpufreq_get_max_state(unsigned int cpu) 159 + { 160 + if (!cpu_has_cpufreq(cpu)) 161 + return 0; 162 + 163 + return CPUFREQ_THERMAL_MAX_STEP; 164 + } 165 + 166 + static int cpufreq_get_cur_state(unsigned int cpu) 167 + { 168 + if (!cpu_has_cpufreq(cpu)) 169 + return 0; 170 + 171 + return cpufreq_thermal_reduction_pctg[cpu]; 172 + } 173 + 174 + static int cpufreq_set_cur_state(unsigned int cpu, int state) 175 + { 176 + if (!cpu_has_cpufreq(cpu)) 177 + return 0; 178 + 179 + cpufreq_thermal_reduction_pctg[cpu] = state; 180 + cpufreq_update_policy(cpu); 181 + return 0; 182 + } 163 183 164 184 void acpi_thermal_cpufreq_init(void) 165 185 { ··· 211 179 } 212 180 213 181 #else /* ! CONFIG_CPU_FREQ */ 182 + static int cpufreq_get_max_state(unsigned int cpu) 183 + { 184 + return 0; 185 + } 186 + 187 + static int cpufreq_get_cur_state(unsigned int cpu) 188 + { 189 + return 0; 190 + } 191 + 192 + static int cpufreq_set_cur_state(unsigned int cpu, int state) 193 + { 194 + return 0; 195 + } 214 196 215 197 static int acpi_thermal_cpufreq_increase(unsigned int cpu) 216 198 { ··· 355 309 356 310 return 0; 357 311 } 312 + 313 + /* thermal coolign device callbacks */ 314 + static int acpi_processor_max_state(struct acpi_processor *pr) 315 + { 316 + int max_state = 0; 317 + 318 + /* 319 + * There exists four states according to 320 + * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 321 + */ 322 + max_state += cpufreq_get_max_state(pr->id); 323 + if (pr->flags.throttling) 324 + max_state += (pr->throttling.state_count -1); 325 + 326 + return max_state; 327 + } 328 + static int 329 + processor_get_max_state(struct thermal_cooling_device *cdev, char *buf) 330 + { 331 + struct acpi_device *device = cdev->devdata; 332 + struct acpi_processor *pr = acpi_driver_data(device); 333 + 334 + if (!device || !pr) 335 + return -EINVAL; 336 + 337 + return sprintf(buf, "%d\n", acpi_processor_max_state(pr)); 338 + } 339 + 340 + static int 341 + processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf) 342 + { 343 + struct acpi_device *device = cdev->devdata; 344 + struct acpi_processor *pr = acpi_driver_data(device); 345 + int cur_state; 346 + 347 + if (!device || !pr) 348 + return -EINVAL; 349 + 350 + cur_state = cpufreq_get_cur_state(pr->id); 351 + if (pr->flags.throttling) 352 + cur_state += pr->throttling.state; 353 + 354 + return sprintf(buf, "%d\n", cur_state); 355 + } 356 + 357 + static int 358 + processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) 359 + { 360 + struct acpi_device *device = cdev->devdata; 361 + struct acpi_processor *pr = acpi_driver_data(device); 362 + int result = 0; 363 + int max_pstate; 364 + 365 + if (!device || !pr) 366 + return -EINVAL; 367 + 368 + max_pstate = cpufreq_get_max_state(pr->id); 369 + 370 + if (state > acpi_processor_max_state(pr)) 371 + return -EINVAL; 372 + 373 + if (state <= max_pstate) { 374 + if (pr->flags.throttling && pr->throttling.state) 375 + result = acpi_processor_set_throttling(pr, 0); 376 + cpufreq_set_cur_state(pr->id, state); 377 + } else { 378 + cpufreq_set_cur_state(pr->id, max_pstate); 379 + result = acpi_processor_set_throttling(pr, 380 + state - max_pstate); 381 + } 382 + return result; 383 + } 384 + 385 + struct thermal_cooling_device_ops processor_cooling_ops = { 386 + .get_max_state = processor_get_max_state, 387 + .get_cur_state = processor_get_cur_state, 388 + .set_cur_state = processor_set_cur_state, 389 + }; 358 390 359 391 /* /proc interface */ 360 392
+497 -159
drivers/acpi/thermal.c
··· 43 43 #include <linux/seq_file.h> 44 44 #include <linux/reboot.h> 45 45 #include <asm/uaccess.h> 46 - 46 + #include <linux/thermal.h> 47 47 #include <acpi/acpi_bus.h> 48 48 #include <acpi/acpi_drivers.h> 49 49 ··· 64 64 65 65 #define ACPI_THERMAL_MAX_ACTIVE 10 66 66 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 67 - 68 - #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) 69 - #define CELSIUS_TO_KELVIN(t) ((t+273)*10) 70 67 71 68 #define _COMPONENT ACPI_THERMAL_COMPONENT 72 69 ACPI_MODULE_NAME("thermal"); ··· 192 195 struct acpi_thermal_trips trips; 193 196 struct acpi_handle_list devices; 194 197 struct timer_list timer; 198 + struct thermal_zone_device *thermal_zone; 199 + int tz_enabled; 195 200 struct mutex lock; 196 201 }; 197 202 ··· 320 321 return 0; 321 322 } 322 323 323 - static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) 324 + #define ACPI_TRIPS_CRITICAL 0x01 325 + #define ACPI_TRIPS_HOT 0x02 326 + #define ACPI_TRIPS_PASSIVE 0x04 327 + #define ACPI_TRIPS_ACTIVE 0x08 328 + #define ACPI_TRIPS_DEVICES 0x10 329 + 330 + #define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE) 331 + #define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES 332 + 333 + #define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \ 334 + ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \ 335 + ACPI_TRIPS_DEVICES) 336 + 337 + /* 338 + * This exception is thrown out in two cases: 339 + * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid 340 + * when re-evaluating the AML code. 341 + * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change. 342 + * We need to re-bind the cooling devices of a thermal zone when this occurs. 343 + */ 344 + #define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \ 345 + do { \ 346 + if (flags != ACPI_TRIPS_INIT) \ 347 + ACPI_EXCEPTION((AE_INFO, AE_ERROR, \ 348 + "ACPI thermal trip point %s changed\n" \ 349 + "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \ 350 + } while (0) 351 + 352 + static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) 324 353 { 325 354 acpi_status status = AE_OK; 326 - int i = 0; 327 - 328 - 329 - if (!tz) 330 - return -EINVAL; 355 + struct acpi_handle_list devices; 356 + int valid = 0; 357 + int i; 331 358 332 359 /* Critical Shutdown (required) */ 333 - 334 - status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, 335 - &tz->trips.critical.temperature); 336 - if (ACPI_FAILURE(status)) { 337 - tz->trips.critical.flags.valid = 0; 338 - ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); 339 - return -ENODEV; 340 - } else { 341 - tz->trips.critical.flags.valid = 1; 342 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, 343 - "Found critical threshold [%lu]\n", 344 - tz->trips.critical.temperature)); 345 - } 346 - 347 - if (tz->trips.critical.flags.valid == 1) { 348 - if (crt == -1) { 360 + if (flag & ACPI_TRIPS_CRITICAL) { 361 + status = acpi_evaluate_integer(tz->device->handle, 362 + "_CRT", NULL, &tz->trips.critical.temperature); 363 + if (ACPI_FAILURE(status)) { 349 364 tz->trips.critical.flags.valid = 0; 350 - } else if (crt > 0) { 351 - unsigned long crt_k = CELSIUS_TO_KELVIN(crt); 352 - 353 - /* 354 - * Allow override to lower critical threshold 355 - */ 356 - if (crt_k < tz->trips.critical.temperature) 357 - tz->trips.critical.temperature = crt_k; 365 + ACPI_EXCEPTION((AE_INFO, status, 366 + "No critical threshold")); 367 + return -ENODEV; 368 + } else { 369 + tz->trips.critical.flags.valid = 1; 370 + ACPI_DEBUG_PRINT((ACPI_DB_INFO, 371 + "Found critical threshold [%lu]\n", 372 + tz->trips.critical.temperature)); 373 + } 374 + if (tz->trips.critical.flags.valid == 1) { 375 + if (crt == -1) { 376 + tz->trips.critical.flags.valid = 0; 377 + } else if (crt > 0) { 378 + unsigned long crt_k = CELSIUS_TO_KELVIN(crt); 379 + /* 380 + * Allow override to lower critical threshold 381 + */ 382 + if (crt_k < tz->trips.critical.temperature) 383 + tz->trips.critical.temperature = crt_k; 384 + } 358 385 } 359 386 } 360 387 361 388 /* Critical Sleep (optional) */ 362 - 363 - status = 364 - acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, 365 - &tz->trips.hot.temperature); 366 - if (ACPI_FAILURE(status)) { 367 - tz->trips.hot.flags.valid = 0; 368 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); 369 - } else { 370 - tz->trips.hot.flags.valid = 1; 371 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", 372 - tz->trips.hot.temperature)); 373 - } 374 - 375 - /* Passive: Processors (optional) */ 376 - 377 - if (psv == -1) { 378 - status = AE_SUPPORT; 379 - } else if (psv > 0) { 380 - tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); 381 - status = AE_OK; 382 - } else { 389 + if (flag & ACPI_TRIPS_HOT) { 383 390 status = acpi_evaluate_integer(tz->device->handle, 384 - "_PSV", NULL, &tz->trips.passive.temperature); 385 - } 386 - 387 - if (ACPI_FAILURE(status)) { 388 - tz->trips.passive.flags.valid = 0; 389 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); 390 - } else { 391 - tz->trips.passive.flags.valid = 1; 392 - 393 - status = 394 - acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, 395 - &tz->trips.passive.tc1); 396 - if (ACPI_FAILURE(status)) 397 - tz->trips.passive.flags.valid = 0; 398 - 399 - status = 400 - acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, 401 - &tz->trips.passive.tc2); 402 - if (ACPI_FAILURE(status)) 403 - tz->trips.passive.flags.valid = 0; 404 - 405 - status = 406 - acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, 407 - &tz->trips.passive.tsp); 408 - if (ACPI_FAILURE(status)) 409 - tz->trips.passive.flags.valid = 0; 410 - 411 - status = 412 - acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, 413 - &tz->trips.passive.devices); 414 - if (ACPI_FAILURE(status)) 415 - tz->trips.passive.flags.valid = 0; 416 - 417 - if (!tz->trips.passive.flags.valid) 418 - printk(KERN_WARNING PREFIX "Invalid passive threshold\n"); 419 - else 391 + "_HOT", NULL, &tz->trips.hot.temperature); 392 + if (ACPI_FAILURE(status)) { 393 + tz->trips.hot.flags.valid = 0; 420 394 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 421 - "Found passive threshold [%lu]\n", 422 - tz->trips.passive.temperature)); 395 + "No hot threshold\n")); 396 + } else { 397 + tz->trips.hot.flags.valid = 1; 398 + ACPI_DEBUG_PRINT((ACPI_DB_INFO, 399 + "Found hot threshold [%lu]\n", 400 + tz->trips.critical.temperature)); 401 + } 423 402 } 424 403 425 - /* Active: Fans, etc. (optional) */ 404 + /* Passive (optional) */ 405 + if (flag & ACPI_TRIPS_PASSIVE) { 406 + valid = tz->trips.passive.flags.valid; 407 + if (psv == -1) { 408 + status = AE_SUPPORT; 409 + } else if (psv > 0) { 410 + tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); 411 + status = AE_OK; 412 + } else { 413 + status = acpi_evaluate_integer(tz->device->handle, 414 + "_PSV", NULL, &tz->trips.passive.temperature); 415 + } 426 416 417 + if (ACPI_FAILURE(status)) 418 + tz->trips.passive.flags.valid = 0; 419 + else { 420 + tz->trips.passive.flags.valid = 1; 421 + if (flag == ACPI_TRIPS_INIT) { 422 + status = acpi_evaluate_integer( 423 + tz->device->handle, "_TC1", 424 + NULL, &tz->trips.passive.tc1); 425 + if (ACPI_FAILURE(status)) 426 + tz->trips.passive.flags.valid = 0; 427 + status = acpi_evaluate_integer( 428 + tz->device->handle, "_TC2", 429 + NULL, &tz->trips.passive.tc2); 430 + if (ACPI_FAILURE(status)) 431 + tz->trips.passive.flags.valid = 0; 432 + status = acpi_evaluate_integer( 433 + tz->device->handle, "_TSP", 434 + NULL, &tz->trips.passive.tsp); 435 + if (ACPI_FAILURE(status)) 436 + tz->trips.passive.flags.valid = 0; 437 + } 438 + } 439 + } 440 + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) { 441 + memset(&devices, 0, sizeof(struct acpi_handle_list)); 442 + status = acpi_evaluate_reference(tz->device->handle, "_PSL", 443 + NULL, &devices); 444 + if (ACPI_FAILURE(status)) 445 + tz->trips.passive.flags.valid = 0; 446 + else 447 + tz->trips.passive.flags.valid = 1; 448 + 449 + if (memcmp(&tz->trips.passive.devices, &devices, 450 + sizeof(struct acpi_handle_list))) { 451 + memcpy(&tz->trips.passive.devices, &devices, 452 + sizeof(struct acpi_handle_list)); 453 + ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); 454 + } 455 + } 456 + if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { 457 + if (valid != tz->trips.passive.flags.valid) 458 + ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); 459 + } 460 + 461 + /* Active (optional) */ 427 462 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { 428 - 429 463 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; 464 + valid = tz->trips.active[i].flags.valid; 430 465 431 466 if (act == -1) 432 - break; /* disable all active trip points */ 467 + break; /* disable all active trip points */ 433 468 434 - status = acpi_evaluate_integer(tz->device->handle, 435 - name, NULL, &tz->trips.active[i].temperature); 436 - 437 - if (ACPI_FAILURE(status)) { 438 - if (i == 0) /* no active trip points */ 469 + if (flag & ACPI_TRIPS_ACTIVE) { 470 + status = acpi_evaluate_integer(tz->device->handle, 471 + name, NULL, &tz->trips.active[i].temperature); 472 + if (ACPI_FAILURE(status)) { 473 + tz->trips.active[i].flags.valid = 0; 474 + if (i == 0) 475 + break; 476 + if (act <= 0) 477 + break; 478 + if (i == 1) 479 + tz->trips.active[0].temperature = 480 + CELSIUS_TO_KELVIN(act); 481 + else 482 + /* 483 + * Don't allow override higher than 484 + * the next higher trip point 485 + */ 486 + tz->trips.active[i - 1].temperature = 487 + (tz->trips.active[i - 2].temperature < 488 + CELSIUS_TO_KELVIN(act) ? 489 + tz->trips.active[i - 2].temperature : 490 + CELSIUS_TO_KELVIN(act)); 439 491 break; 440 - if (act <= 0) /* no override requested */ 441 - break; 442 - if (i == 1) { /* 1 trip point */ 443 - tz->trips.active[0].temperature = 444 - CELSIUS_TO_KELVIN(act); 445 - } else { /* multiple trips */ 446 - /* 447 - * Don't allow override higher than 448 - * the next higher trip point 449 - */ 450 - tz->trips.active[i - 1].temperature = 451 - (tz->trips.active[i - 2].temperature < 452 - CELSIUS_TO_KELVIN(act) ? 453 - tz->trips.active[i - 2].temperature : 454 - CELSIUS_TO_KELVIN(act)); 455 - } 456 - break; 492 + } else 493 + tz->trips.active[i].flags.valid = 1; 457 494 } 458 495 459 496 name[2] = 'L'; 460 - status = 461 - acpi_evaluate_reference(tz->device->handle, name, NULL, 462 - &tz->trips.active[i].devices); 463 - if (ACPI_SUCCESS(status)) { 464 - tz->trips.active[i].flags.valid = 1; 465 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, 466 - "Found active threshold [%d]:[%lu]\n", 467 - i, tz->trips.active[i].temperature)); 468 - } else 469 - ACPI_EXCEPTION((AE_INFO, status, 470 - "Invalid active threshold [%d]", i)); 497 + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) { 498 + memset(&devices, 0, sizeof(struct acpi_handle_list)); 499 + status = acpi_evaluate_reference(tz->device->handle, 500 + name, NULL, &devices); 501 + if (ACPI_FAILURE(status)) 502 + tz->trips.active[i].flags.valid = 0; 503 + else 504 + tz->trips.active[i].flags.valid = 1; 505 + 506 + if (memcmp(&tz->trips.active[i].devices, &devices, 507 + sizeof(struct acpi_handle_list))) { 508 + memcpy(&tz->trips.active[i].devices, &devices, 509 + sizeof(struct acpi_handle_list)); 510 + ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); 511 + } 512 + } 513 + if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) 514 + if (valid != tz->trips.active[i].flags.valid) 515 + ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); 516 + 517 + if (!tz->trips.active[i].flags.valid) 518 + break; 519 + } 520 + 521 + if (flag & ACPI_TRIPS_DEVICES) { 522 + memset(&devices, 0, sizeof(struct acpi_handle_list)); 523 + status = acpi_evaluate_reference(tz->device->handle, "_TZD", 524 + NULL, &devices); 525 + if (memcmp(&tz->devices, &devices, 526 + sizeof(struct acpi_handle_list))) { 527 + memcpy(&tz->devices, &devices, 528 + sizeof(struct acpi_handle_list)); 529 + ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); 530 + } 471 531 } 472 532 473 533 return 0; 474 534 } 475 535 476 - static int acpi_thermal_get_devices(struct acpi_thermal *tz) 536 + static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) 477 537 { 478 - acpi_status status = AE_OK; 479 - 480 - 481 - if (!tz) 482 - return -EINVAL; 483 - 484 - status = 485 - acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices); 486 - if (ACPI_FAILURE(status)) 487 - return -ENODEV; 488 - 489 - return 0; 538 + return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); 490 539 } 491 540 492 541 static int acpi_thermal_critical(struct acpi_thermal *tz) ··· 782 735 if (result) 783 736 goto unlock; 784 737 738 + if (!tz->tz_enabled) 739 + goto unlock; 740 + 785 741 memset(&tz->state, 0, sizeof(tz->state)); 786 742 787 743 /* ··· 877 827 unlock: 878 828 mutex_unlock(&tz->lock); 879 829 } 830 + 831 + /* sys I/F for generic thermal sysfs support */ 832 + static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) 833 + { 834 + struct acpi_thermal *tz = thermal->devdata; 835 + 836 + if (!tz) 837 + return -EINVAL; 838 + 839 + return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); 840 + } 841 + 842 + static const char enabled[] = "kernel"; 843 + static const char disabled[] = "user"; 844 + static int thermal_get_mode(struct thermal_zone_device *thermal, 845 + char *buf) 846 + { 847 + struct acpi_thermal *tz = thermal->devdata; 848 + 849 + if (!tz) 850 + return -EINVAL; 851 + 852 + return sprintf(buf, "%s\n", tz->tz_enabled ? 853 + enabled : disabled); 854 + } 855 + 856 + static int thermal_set_mode(struct thermal_zone_device *thermal, 857 + const char *buf) 858 + { 859 + struct acpi_thermal *tz = thermal->devdata; 860 + int enable; 861 + 862 + if (!tz) 863 + return -EINVAL; 864 + 865 + /* 866 + * enable/disable thermal management from ACPI thermal driver 867 + */ 868 + if (!strncmp(buf, enabled, sizeof enabled - 1)) 869 + enable = 1; 870 + else if (!strncmp(buf, disabled, sizeof disabled - 1)) 871 + enable = 0; 872 + else 873 + return -EINVAL; 874 + 875 + if (enable != tz->tz_enabled) { 876 + tz->tz_enabled = enable; 877 + ACPI_DEBUG_PRINT((ACPI_DB_INFO, 878 + "%s ACPI thermal control\n", 879 + tz->tz_enabled ? enabled : disabled)); 880 + acpi_thermal_check(tz); 881 + } 882 + return 0; 883 + } 884 + 885 + static int thermal_get_trip_type(struct thermal_zone_device *thermal, 886 + int trip, char *buf) 887 + { 888 + struct acpi_thermal *tz = thermal->devdata; 889 + int i; 890 + 891 + if (!tz || trip < 0) 892 + return -EINVAL; 893 + 894 + if (tz->trips.critical.flags.valid) { 895 + if (!trip) 896 + return sprintf(buf, "critical\n"); 897 + trip--; 898 + } 899 + 900 + if (tz->trips.hot.flags.valid) { 901 + if (!trip) 902 + return sprintf(buf, "hot\n"); 903 + trip--; 904 + } 905 + 906 + if (tz->trips.passive.flags.valid) { 907 + if (!trip) 908 + return sprintf(buf, "passive\n"); 909 + trip--; 910 + } 911 + 912 + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && 913 + tz->trips.active[i].flags.valid; i++) { 914 + if (!trip) 915 + return sprintf(buf, "active%d\n", i); 916 + trip--; 917 + } 918 + 919 + return -EINVAL; 920 + } 921 + 922 + static int thermal_get_trip_temp(struct thermal_zone_device *thermal, 923 + int trip, char *buf) 924 + { 925 + struct acpi_thermal *tz = thermal->devdata; 926 + int i; 927 + 928 + if (!tz || trip < 0) 929 + return -EINVAL; 930 + 931 + if (tz->trips.critical.flags.valid) { 932 + if (!trip) 933 + return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( 934 + tz->trips.critical.temperature)); 935 + trip--; 936 + } 937 + 938 + if (tz->trips.hot.flags.valid) { 939 + if (!trip) 940 + return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( 941 + tz->trips.hot.temperature)); 942 + trip--; 943 + } 944 + 945 + if (tz->trips.passive.flags.valid) { 946 + if (!trip) 947 + return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( 948 + tz->trips.passive.temperature)); 949 + trip--; 950 + } 951 + 952 + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && 953 + tz->trips.active[i].flags.valid; i++) { 954 + if (!trip) 955 + return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( 956 + tz->trips.active[i].temperature)); 957 + trip--; 958 + } 959 + 960 + return -EINVAL; 961 + } 962 + 963 + typedef int (*cb)(struct thermal_zone_device *, int, 964 + struct thermal_cooling_device *); 965 + static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, 966 + struct thermal_cooling_device *cdev, 967 + cb action) 968 + { 969 + struct acpi_device *device = cdev->devdata; 970 + struct acpi_thermal *tz = thermal->devdata; 971 + struct acpi_device *dev; 972 + acpi_status status; 973 + acpi_handle handle; 974 + int i; 975 + int j; 976 + int trip = -1; 977 + int result = 0; 978 + 979 + if (tz->trips.critical.flags.valid) 980 + trip++; 981 + 982 + if (tz->trips.hot.flags.valid) 983 + trip++; 984 + 985 + if (tz->trips.passive.flags.valid) { 986 + trip++; 987 + for (i = 0; i < tz->trips.passive.devices.count; 988 + i++) { 989 + handle = tz->trips.passive.devices.handles[i]; 990 + status = acpi_bus_get_device(handle, &dev); 991 + if (ACPI_SUCCESS(status) && (dev == device)) { 992 + result = action(thermal, trip, cdev); 993 + if (result) 994 + goto failed; 995 + } 996 + } 997 + } 998 + 999 + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { 1000 + if (!tz->trips.active[i].flags.valid) 1001 + break; 1002 + trip++; 1003 + for (j = 0; 1004 + j < tz->trips.active[i].devices.count; 1005 + j++) { 1006 + handle = tz->trips.active[i].devices.handles[j]; 1007 + status = acpi_bus_get_device(handle, &dev); 1008 + if (ACPI_SUCCESS(status) && (dev == device)) { 1009 + result = action(thermal, trip, cdev); 1010 + if (result) 1011 + goto failed; 1012 + } 1013 + } 1014 + } 1015 + 1016 + for (i = 0; i < tz->devices.count; i++) { 1017 + handle = tz->devices.handles[i]; 1018 + status = acpi_bus_get_device(handle, &dev); 1019 + if (ACPI_SUCCESS(status) && (dev == device)) { 1020 + result = action(thermal, -1, cdev); 1021 + if (result) 1022 + goto failed; 1023 + } 1024 + } 1025 + 1026 + failed: 1027 + return result; 1028 + } 1029 + 1030 + static int 1031 + acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, 1032 + struct thermal_cooling_device *cdev) 1033 + { 1034 + return acpi_thermal_cooling_device_cb(thermal, cdev, 1035 + thermal_zone_bind_cooling_device); 1036 + } 1037 + 1038 + static int 1039 + acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, 1040 + struct thermal_cooling_device *cdev) 1041 + { 1042 + return acpi_thermal_cooling_device_cb(thermal, cdev, 1043 + thermal_zone_unbind_cooling_device); 1044 + } 1045 + 1046 + static struct thermal_zone_device_ops acpi_thermal_zone_ops = { 1047 + .bind = acpi_thermal_bind_cooling_device, 1048 + .unbind = acpi_thermal_unbind_cooling_device, 1049 + .get_temp = thermal_get_temp, 1050 + .get_mode = thermal_get_mode, 1051 + .set_mode = thermal_set_mode, 1052 + .get_trip_type = thermal_get_trip_type, 1053 + .get_trip_temp = thermal_get_trip_temp, 1054 + }; 1055 + 1056 + static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) 1057 + { 1058 + int trips = 0; 1059 + int result; 1060 + acpi_status status; 1061 + int i; 1062 + 1063 + if (tz->trips.critical.flags.valid) 1064 + trips++; 1065 + 1066 + if (tz->trips.hot.flags.valid) 1067 + trips++; 1068 + 1069 + if (tz->trips.passive.flags.valid) 1070 + trips++; 1071 + 1072 + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && 1073 + tz->trips.active[i].flags.valid; i++, trips++); 1074 + tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone", 1075 + trips, tz, &acpi_thermal_zone_ops); 1076 + if (!tz->thermal_zone) 1077 + return -ENODEV; 1078 + 1079 + result = sysfs_create_link(&tz->device->dev.kobj, 1080 + &tz->thermal_zone->device.kobj, "thermal_zone"); 1081 + if (result) 1082 + return result; 1083 + 1084 + result = sysfs_create_link(&tz->thermal_zone->device.kobj, 1085 + &tz->device->dev.kobj, "device"); 1086 + if (result) 1087 + return result; 1088 + 1089 + status = acpi_attach_data(tz->device->handle, 1090 + acpi_bus_private_data_handler, 1091 + tz->thermal_zone); 1092 + if (ACPI_FAILURE(status)) { 1093 + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1094 + "Error attaching device data\n")); 1095 + return -ENODEV; 1096 + } 1097 + 1098 + tz->tz_enabled = 1; 1099 + 1100 + printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n", 1101 + tz->device->dev.bus_id, tz->thermal_zone->id); 1102 + return 0; 1103 + } 1104 + 1105 + static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) 1106 + { 1107 + sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); 1108 + sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); 1109 + thermal_zone_device_unregister(tz->thermal_zone); 1110 + tz->thermal_zone = NULL; 1111 + acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); 1112 + } 1113 + 880 1114 881 1115 /* -------------------------------------------------------------------------- 882 1116 FS Interface (/proc) ··· 1518 1184 acpi_thermal_check(tz); 1519 1185 break; 1520 1186 case ACPI_THERMAL_NOTIFY_THRESHOLDS: 1521 - acpi_thermal_get_trip_points(tz); 1187 + acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); 1522 1188 acpi_thermal_check(tz); 1523 1189 acpi_bus_generate_proc_event(device, event, 0); 1524 1190 acpi_bus_generate_netlink_event(device->pnp.device_class, 1525 1191 device->dev.bus_id, event, 0); 1526 1192 break; 1527 1193 case ACPI_THERMAL_NOTIFY_DEVICES: 1528 - if (tz->flags.devices) 1529 - acpi_thermal_get_devices(tz); 1194 + acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); 1195 + acpi_thermal_check(tz); 1530 1196 acpi_bus_generate_proc_event(device, event, 0); 1531 1197 acpi_bus_generate_netlink_event(device->pnp.device_class, 1532 1198 device->dev.bus_id, event, 0); ··· 1569 1235 else 1570 1236 acpi_thermal_get_polling_frequency(tz); 1571 1237 1572 - /* Get devices in this thermal zone [_TZD] (optional) */ 1573 - result = acpi_thermal_get_devices(tz); 1574 - if (!result) 1575 - tz->flags.devices = 1; 1576 - 1577 1238 return 0; 1578 1239 } 1579 1240 ··· 1592 1263 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); 1593 1264 acpi_driver_data(device) = tz; 1594 1265 mutex_init(&tz->lock); 1266 + 1267 + 1595 1268 result = acpi_thermal_get_info(tz); 1596 1269 if (result) 1597 - goto end; 1270 + goto free_memory; 1271 + 1272 + result = acpi_thermal_register_thermal_zone(tz); 1273 + if (result) 1274 + goto free_memory; 1598 1275 1599 1276 result = acpi_thermal_add_fs(device); 1600 1277 if (result) 1601 - goto end; 1278 + goto unregister_thermal_zone; 1602 1279 1603 1280 init_timer(&tz->timer); 1604 1281 ··· 1615 1280 acpi_thermal_notify, tz); 1616 1281 if (ACPI_FAILURE(status)) { 1617 1282 result = -ENODEV; 1618 - goto end; 1283 + goto remove_fs; 1619 1284 } 1620 1285 1621 1286 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", 1622 1287 acpi_device_name(device), acpi_device_bid(device), 1623 1288 KELVIN_TO_CELSIUS(tz->temperature)); 1289 + goto end; 1624 1290 1625 - end: 1626 - if (result) { 1627 - acpi_thermal_remove_fs(device); 1628 - kfree(tz); 1629 - } 1630 - 1291 + remove_fs: 1292 + acpi_thermal_remove_fs(device); 1293 + unregister_thermal_zone: 1294 + thermal_zone_device_unregister(tz->thermal_zone); 1295 + free_memory: 1296 + kfree(tz); 1297 + end: 1631 1298 return result; 1632 1299 } 1633 1300 ··· 1669 1332 } 1670 1333 1671 1334 acpi_thermal_remove_fs(device); 1335 + acpi_thermal_unregister_thermal_zone(tz); 1672 1336 mutex_destroy(&tz->lock); 1673 1337 kfree(tz); 1674 1338 return 0;
+77 -1
drivers/acpi/video.c
··· 34 34 #include <linux/seq_file.h> 35 35 #include <linux/input.h> 36 36 #include <linux/backlight.h> 37 + #include <linux/thermal.h> 37 38 #include <linux/video_output.h> 38 39 #include <asm/uaccess.h> 39 40 ··· 180 179 struct acpi_device *dev; 181 180 struct acpi_video_device_brightness *brightness; 182 181 struct backlight_device *backlight; 182 + struct thermal_cooling_device *cdev; 183 183 struct output_device *output_dev; 184 184 }; 185 185 ··· 344 342 .set_state = acpi_video_output_set, 345 343 .get_status = acpi_video_output_get, 346 344 }; 345 + 346 + 347 + /* thermal cooling device callbacks */ 348 + static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) 349 + { 350 + struct acpi_device *device = cdev->devdata; 351 + struct acpi_video_device *video = acpi_driver_data(device); 352 + 353 + return sprintf(buf, "%d\n", video->brightness->count - 3); 354 + } 355 + 356 + static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) 357 + { 358 + struct acpi_device *device = cdev->devdata; 359 + struct acpi_video_device *video = acpi_driver_data(device); 360 + unsigned long level; 361 + int state; 362 + 363 + acpi_video_device_lcd_get_level_current(video, &level); 364 + for (state = 2; state < video->brightness->count; state++) 365 + if (level == video->brightness->levels[state]) 366 + return sprintf(buf, "%d\n", 367 + video->brightness->count - state - 1); 368 + 369 + return -EINVAL; 370 + } 371 + 372 + static int 373 + video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) 374 + { 375 + struct acpi_device *device = cdev->devdata; 376 + struct acpi_video_device *video = acpi_driver_data(device); 377 + int level; 378 + 379 + if ( state >= video->brightness->count - 2) 380 + return -EINVAL; 381 + 382 + state = video->brightness->count - state; 383 + level = video->brightness->levels[state -1]; 384 + return acpi_video_device_lcd_set_level(video, level); 385 + } 386 + 387 + static struct thermal_cooling_device_ops video_cooling_ops = { 388 + .get_max_state = video_get_max_state, 389 + .get_cur_state = video_get_cur_state, 390 + .set_cur_state = video_set_cur_state, 391 + }; 392 + 347 393 /* -------------------------------------------------------------------------- 348 394 Video Management 349 395 -------------------------------------------------------------------------- */ ··· 710 660 kfree(obj); 711 661 712 662 if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ 663 + int result; 713 664 static int count = 0; 714 665 char *name; 715 666 name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); ··· 723 672 device->backlight->props.max_brightness = device->brightness->count-3; 724 673 device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); 725 674 backlight_update_status(device->backlight); 726 - 727 675 kfree(name); 676 + 677 + device->cdev = thermal_cooling_device_register("LCD", 678 + device->dev, &video_cooling_ops); 679 + if (device->cdev) { 680 + printk(KERN_INFO PREFIX 681 + "%s is registered as cooling_device%d\n", 682 + device->dev->dev.bus_id, device->cdev->id); 683 + result = sysfs_create_link(&device->dev->dev.kobj, 684 + &device->cdev->device.kobj, 685 + "thermal_cooling"); 686 + if (result) 687 + printk(KERN_ERR PREFIX "Create sysfs link\n"); 688 + result = sysfs_create_link(&device->cdev->device.kobj, 689 + &device->dev->dev.kobj, 690 + "device"); 691 + if (result) 692 + printk(KERN_ERR PREFIX "Create sysfs link\n"); 693 + } 728 694 } 729 695 if (device->cap._DCS && device->cap._DSS){ 730 696 static int count = 0; ··· 1832 1764 ACPI_DEVICE_NOTIFY, 1833 1765 acpi_video_device_notify); 1834 1766 backlight_device_unregister(device->backlight); 1767 + if (device->cdev) { 1768 + sysfs_remove_link(&device->dev->dev.kobj, 1769 + "thermal_cooling"); 1770 + sysfs_remove_link(&device->cdev->device.kobj, 1771 + "device"); 1772 + thermal_cooling_device_unregister(device->cdev); 1773 + device->cdev = NULL; 1774 + } 1835 1775 video_output_unregister(device->output_dev); 1836 1776 1837 1777 return 0;
+9
drivers/misc/Kconfig
··· 251 251 252 252 If unsure, say N. 253 253 254 + config INTEL_MENLOW 255 + tristate "Thermal Management driver for Intel menlow platform" 256 + depends on ACPI_THERMAL 257 + ---help--- 258 + ACPI thermal management enhancement driver on 259 + Intel Menlow platform. 260 + 261 + If unsure, say N. 262 + 254 263 endif # MISC_DEVICES
+1
drivers/misc/Makefile
··· 17 17 obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o 18 18 obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o 19 19 obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o 20 + obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
+526
drivers/misc/intel_menlow.c
··· 1 + /* 2 + * intel_menlow.c - Intel menlow Driver for thermal management extension 3 + * 4 + * Copyright (C) 2008 Intel Corp 5 + * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 6 + * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 7 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; version 2 of the License. 12 + * 13 + * This program is distributed in the hope that it will be useful, but 14 + * WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 + * General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License along 19 + * with this program; if not, write to the Free Software Foundation, Inc., 20 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 21 + * 22 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 + * 24 + * This driver creates the sys I/F for programming the sensors. 25 + * It also implements the driver for intel menlow memory controller (hardware 26 + * id is INT0002) which makes use of the platform specific ACPI methods 27 + * to get/set bandwidth. 28 + */ 29 + 30 + #include <linux/kernel.h> 31 + #include <linux/module.h> 32 + #include <linux/init.h> 33 + #include <linux/types.h> 34 + #include <linux/pci.h> 35 + #include <linux/pm.h> 36 + 37 + #include <linux/thermal.h> 38 + #include <acpi/acpi_bus.h> 39 + #include <acpi/acpi_drivers.h> 40 + 41 + MODULE_AUTHOR("Thomas Sujith"); 42 + MODULE_AUTHOR("Zhang Rui"); 43 + MODULE_DESCRIPTION("Intel Menlow platform specific driver"); 44 + MODULE_LICENSE("GPL"); 45 + 46 + /* 47 + * Memory controller device control 48 + */ 49 + 50 + #define MEMORY_GET_BANDWIDTH "GTHS" 51 + #define MEMORY_SET_BANDWIDTH "STHS" 52 + #define MEMORY_ARG_CUR_BANDWIDTH 1 53 + #define MEMORY_ARG_MAX_BANDWIDTH 0 54 + 55 + static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev, 56 + unsigned long *max_state) 57 + { 58 + struct acpi_device *device = cdev->devdata; 59 + acpi_handle handle = device->handle; 60 + unsigned long value; 61 + struct acpi_object_list arg_list; 62 + union acpi_object arg; 63 + acpi_status status = AE_OK; 64 + 65 + arg_list.count = 1; 66 + arg_list.pointer = &arg; 67 + arg.type = ACPI_TYPE_INTEGER; 68 + arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; 69 + status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, 70 + &arg_list, &value); 71 + if (ACPI_FAILURE(status)) 72 + return -EFAULT; 73 + 74 + *max_state = value - 1; 75 + return 0; 76 + } 77 + 78 + static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev, 79 + char *buf) 80 + { 81 + unsigned long value; 82 + if (memory_get_int_max_bandwidth(cdev, &value)) 83 + return -EINVAL; 84 + 85 + return sprintf(buf, "%ld\n", value); 86 + } 87 + 88 + static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, 89 + char *buf) 90 + { 91 + struct acpi_device *device = cdev->devdata; 92 + acpi_handle handle = device->handle; 93 + unsigned long value; 94 + struct acpi_object_list arg_list; 95 + union acpi_object arg; 96 + acpi_status status = AE_OK; 97 + 98 + arg_list.count = 1; 99 + arg_list.pointer = &arg; 100 + arg.type = ACPI_TYPE_INTEGER; 101 + arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; 102 + status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, 103 + &arg_list, &value); 104 + if (ACPI_FAILURE(status)) 105 + return -EFAULT; 106 + 107 + return sprintf(buf, "%ld\n", value); 108 + } 109 + 110 + static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, 111 + unsigned int state) 112 + { 113 + struct acpi_device *device = cdev->devdata; 114 + acpi_handle handle = device->handle; 115 + struct acpi_object_list arg_list; 116 + union acpi_object arg; 117 + acpi_status status; 118 + int temp; 119 + unsigned long max_state; 120 + 121 + if (memory_get_int_max_bandwidth(cdev, &max_state)) 122 + return -EFAULT; 123 + 124 + if (max_state < 0 || state > max_state) 125 + return -EINVAL; 126 + 127 + arg_list.count = 1; 128 + arg_list.pointer = &arg; 129 + arg.type = ACPI_TYPE_INTEGER; 130 + arg.integer.value = state; 131 + 132 + status = 133 + acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, 134 + (unsigned long *)&temp); 135 + 136 + printk(KERN_INFO 137 + "Bandwidth value was %d: status is %d\n", state, status); 138 + if (ACPI_FAILURE(status)) 139 + return -EFAULT; 140 + 141 + return 0; 142 + } 143 + 144 + static struct thermal_cooling_device_ops memory_cooling_ops = { 145 + .get_max_state = memory_get_max_bandwidth, 146 + .get_cur_state = memory_get_cur_bandwidth, 147 + .set_cur_state = memory_set_cur_bandwidth, 148 + }; 149 + 150 + /* 151 + * Memory Device Management 152 + */ 153 + static int intel_menlow_memory_add(struct acpi_device *device) 154 + { 155 + int result = -ENODEV; 156 + acpi_status status = AE_OK; 157 + acpi_handle dummy; 158 + struct thermal_cooling_device *cdev; 159 + 160 + if (!device) 161 + return -EINVAL; 162 + 163 + status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy); 164 + if (ACPI_FAILURE(status)) 165 + goto end; 166 + 167 + status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy); 168 + if (ACPI_FAILURE(status)) 169 + goto end; 170 + 171 + cdev = thermal_cooling_device_register("Memory controller", device, 172 + &memory_cooling_ops); 173 + acpi_driver_data(device) = cdev; 174 + if (!cdev) 175 + result = -ENODEV; 176 + else { 177 + result = sysfs_create_link(&device->dev.kobj, 178 + &cdev->device.kobj, "thermal_cooling"); 179 + if (result) 180 + goto unregister; 181 + 182 + result = sysfs_create_link(&cdev->device.kobj, 183 + &device->dev.kobj, "device"); 184 + if (result) { 185 + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 186 + goto unregister; 187 + } 188 + } 189 + 190 + end: 191 + return result; 192 + 193 + unregister: 194 + thermal_cooling_device_unregister(cdev); 195 + return result; 196 + 197 + } 198 + 199 + static int intel_menlow_memory_remove(struct acpi_device *device, int type) 200 + { 201 + struct thermal_cooling_device *cdev = acpi_driver_data(device); 202 + 203 + if (!device || !cdev) 204 + return -EINVAL; 205 + 206 + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 207 + sysfs_remove_link(&cdev->device.kobj, "device"); 208 + thermal_cooling_device_unregister(cdev); 209 + 210 + return 0; 211 + } 212 + 213 + const static struct acpi_device_id intel_menlow_memory_ids[] = { 214 + {"INT0002", 0}, 215 + {"", 0}, 216 + }; 217 + 218 + static struct acpi_driver intel_menlow_memory_driver = { 219 + .name = "intel_menlow_thermal_control", 220 + .ids = intel_menlow_memory_ids, 221 + .ops = { 222 + .add = intel_menlow_memory_add, 223 + .remove = intel_menlow_memory_remove, 224 + }, 225 + }; 226 + 227 + /* 228 + * Sensor control on menlow platform 229 + */ 230 + 231 + #define THERMAL_AUX0 0 232 + #define THERMAL_AUX1 1 233 + #define GET_AUX0 "GAX0" 234 + #define GET_AUX1 "GAX1" 235 + #define SET_AUX0 "SAX0" 236 + #define SET_AUX1 "SAX1" 237 + 238 + struct intel_menlow_attribute { 239 + struct device_attribute attr; 240 + struct device *device; 241 + acpi_handle handle; 242 + struct list_head node; 243 + }; 244 + 245 + static LIST_HEAD(intel_menlow_attr_list); 246 + static DEFINE_MUTEX(intel_menlow_attr_lock); 247 + 248 + /* 249 + * sensor_get_auxtrip - get the current auxtrip value from sensor 250 + * @name: Thermalzone name 251 + * @auxtype : AUX0/AUX1 252 + * @buf: syfs buffer 253 + */ 254 + static int sensor_get_auxtrip(acpi_handle handle, int index, int *value) 255 + { 256 + acpi_status status; 257 + 258 + if ((index != 0 && index != 1) || !value) 259 + return -EINVAL; 260 + 261 + status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, 262 + NULL, (unsigned long *)value); 263 + if (ACPI_FAILURE(status)) 264 + return -EIO; 265 + 266 + return 0; 267 + } 268 + 269 + /* 270 + * sensor_set_auxtrip - set the new auxtrip value to sensor 271 + * @name: Thermalzone name 272 + * @auxtype : AUX0/AUX1 273 + * @buf: syfs buffer 274 + */ 275 + static int sensor_set_auxtrip(acpi_handle handle, int index, int value) 276 + { 277 + acpi_status status; 278 + union acpi_object arg = { 279 + ACPI_TYPE_INTEGER 280 + }; 281 + struct acpi_object_list args = { 282 + 1, &arg 283 + }; 284 + int temp; 285 + 286 + if (index != 0 && index != 1) 287 + return -EINVAL; 288 + 289 + status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, 290 + NULL, (unsigned long *)&temp); 291 + if (ACPI_FAILURE(status)) 292 + return -EIO; 293 + if ((index && value < temp) || (!index && value > temp)) 294 + return -EINVAL; 295 + 296 + arg.integer.value = value; 297 + status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, 298 + &args, (unsigned long *)&temp); 299 + if (ACPI_FAILURE(status)) 300 + return -EIO; 301 + 302 + /* do we need to check the return value of SAX0/SAX1 ? */ 303 + 304 + return 0; 305 + } 306 + 307 + #define to_intel_menlow_attr(_attr) \ 308 + container_of(_attr, struct intel_menlow_attribute, attr) 309 + 310 + static ssize_t aux0_show(struct device *dev, 311 + struct device_attribute *dev_attr, char *buf) 312 + { 313 + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 314 + int value; 315 + int result; 316 + 317 + result = sensor_get_auxtrip(attr->handle, 0, &value); 318 + 319 + return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); 320 + } 321 + 322 + static ssize_t aux1_show(struct device *dev, 323 + struct device_attribute *dev_attr, char *buf) 324 + { 325 + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 326 + int value; 327 + int result; 328 + 329 + result = sensor_get_auxtrip(attr->handle, 1, &value); 330 + 331 + return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); 332 + } 333 + 334 + static ssize_t aux0_store(struct device *dev, 335 + struct device_attribute *dev_attr, 336 + const char *buf, size_t count) 337 + { 338 + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 339 + int value; 340 + int result; 341 + 342 + /*Sanity check; should be a positive integer */ 343 + if (!sscanf(buf, "%d", &value)) 344 + return -EINVAL; 345 + 346 + if (value < 0) 347 + return -EINVAL; 348 + 349 + result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); 350 + return result ? result : count; 351 + } 352 + 353 + static ssize_t aux1_store(struct device *dev, 354 + struct device_attribute *dev_attr, 355 + const char *buf, size_t count) 356 + { 357 + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 358 + int value; 359 + int result; 360 + 361 + /*Sanity check; should be a positive integer */ 362 + if (!sscanf(buf, "%d", &value)) 363 + return -EINVAL; 364 + 365 + if (value < 0) 366 + return -EINVAL; 367 + 368 + result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); 369 + return result ? result : count; 370 + } 371 + 372 + /* BIOS can enable/disable the thermal user application in dabney platform */ 373 + #define BIOS_ENABLED "\\_TZ.GSTS" 374 + static ssize_t bios_enabled_show(struct device *dev, 375 + struct device_attribute *attr, char *buf) 376 + { 377 + acpi_status status; 378 + unsigned long bios_enabled; 379 + 380 + status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); 381 + if (ACPI_FAILURE(status)) 382 + return -ENODEV; 383 + 384 + return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); 385 + } 386 + 387 + static int intel_menlow_add_one_attribute(char *name, int mode, void *show, 388 + void *store, struct device *dev, 389 + acpi_handle handle) 390 + { 391 + struct intel_menlow_attribute *attr; 392 + int result; 393 + 394 + attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); 395 + if (!attr) 396 + return -ENOMEM; 397 + 398 + attr->attr.attr.name = name; 399 + attr->attr.attr.mode = mode; 400 + attr->attr.show = show; 401 + attr->attr.store = store; 402 + attr->device = dev; 403 + attr->handle = handle; 404 + 405 + result = device_create_file(dev, &attr->attr); 406 + if (result) 407 + return result; 408 + 409 + mutex_lock(&intel_menlow_attr_lock); 410 + list_add_tail(&attr->node, &intel_menlow_attr_list); 411 + mutex_unlock(&intel_menlow_attr_lock); 412 + 413 + return 0; 414 + } 415 + 416 + static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, 417 + void *context, void **rv) 418 + { 419 + acpi_status status; 420 + acpi_handle dummy; 421 + struct thermal_zone_device *thermal; 422 + int result; 423 + 424 + result = acpi_bus_get_private_data(handle, (void **)&thermal); 425 + if (result) 426 + return 0; 427 + 428 + /* _TZ must have the AUX0/1 methods */ 429 + status = acpi_get_handle(handle, GET_AUX0, &dummy); 430 + if (ACPI_FAILURE(status)) 431 + goto not_found; 432 + 433 + status = acpi_get_handle(handle, SET_AUX0, &dummy); 434 + if (ACPI_FAILURE(status)) 435 + goto not_found; 436 + 437 + result = intel_menlow_add_one_attribute("aux0", 0644, 438 + aux0_show, aux0_store, 439 + &thermal->device, handle); 440 + if (result) 441 + return AE_ERROR; 442 + 443 + status = acpi_get_handle(handle, GET_AUX1, &dummy); 444 + if (ACPI_FAILURE(status)) 445 + goto not_found; 446 + 447 + status = acpi_get_handle(handle, SET_AUX1, &dummy); 448 + if (ACPI_FAILURE(status)) 449 + goto not_found; 450 + 451 + result = intel_menlow_add_one_attribute("aux1", 0644, 452 + aux1_show, aux1_store, 453 + &thermal->device, handle); 454 + if (result) 455 + return AE_ERROR; 456 + 457 + /* 458 + * create the "dabney_enabled" attribute which means the user app 459 + * should be loaded or not 460 + */ 461 + 462 + result = intel_menlow_add_one_attribute("bios_enabled", 0444, 463 + bios_enabled_show, NULL, 464 + &thermal->device, handle); 465 + if (result) 466 + return AE_ERROR; 467 + 468 + not_found: 469 + if (status == AE_NOT_FOUND) 470 + return AE_OK; 471 + else 472 + return status; 473 + } 474 + 475 + static void intel_menlow_unregister_sensor(void) 476 + { 477 + struct intel_menlow_attribute *pos, *next; 478 + 479 + mutex_lock(&intel_menlow_attr_lock); 480 + list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { 481 + list_del(&pos->node); 482 + device_remove_file(pos->device, &pos->attr); 483 + kfree(pos); 484 + } 485 + mutex_unlock(&intel_menlow_attr_lock); 486 + 487 + return; 488 + } 489 + 490 + static int __init intel_menlow_module_init(void) 491 + { 492 + int result = -ENODEV; 493 + acpi_status status; 494 + unsigned long enable; 495 + 496 + if (acpi_disabled) 497 + return result; 498 + 499 + /* Looking for the \_TZ.GSTS method */ 500 + status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); 501 + if (ACPI_FAILURE(status) || !enable) 502 + return -ENODEV; 503 + 504 + /* Looking for ACPI device MEM0 with hardware id INT0002 */ 505 + result = acpi_bus_register_driver(&intel_menlow_memory_driver); 506 + if (result) 507 + return result; 508 + 509 + /* Looking for sensors in each ACPI thermal zone */ 510 + status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, 511 + ACPI_UINT32_MAX, 512 + intel_menlow_register_sensor, NULL, NULL); 513 + if (ACPI_FAILURE(status)) 514 + return -ENODEV; 515 + 516 + return 0; 517 + } 518 + 519 + static void __exit intel_menlow_module_exit(void) 520 + { 521 + acpi_bus_unregister_driver(&intel_menlow_memory_driver); 522 + intel_menlow_unregister_sensor(); 523 + } 524 + 525 + module_init(intel_menlow_module_init); 526 + module_exit(intel_menlow_module_exit);
+15
drivers/thermal/Kconfig
··· 1 + # 2 + # Generic thermal sysfs drivers configuration 3 + # 4 + 5 + menuconfig THERMAL 6 + bool "Generic Thermal sysfs driver" 7 + default y 8 + help 9 + Generic Thermal Sysfs driver offers a generic mechanism for 10 + thermal management. Usually it's made up of one or more thermal 11 + zone and cooling device. 12 + each thermal zone contains its own temperature, trip points, 13 + cooling devices. 14 + All platforms with ACPI thermal support can use this driver. 15 + If you want this support, you should say Y here
+5
drivers/thermal/Makefile
··· 1 + # 2 + # Makefile for sensor chip drivers. 3 + # 4 + 5 + obj-$(CONFIG_THERMAL) += thermal.o
+714
drivers/thermal/thermal.c
··· 1 + /* 2 + * thermal.c - Generic Thermal Management Sysfs support. 3 + * 4 + * Copyright (C) 2008 Intel Corp 5 + * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 6 + * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 7 + * 8 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License as published by 12 + * the Free Software Foundation; version 2 of the License. 13 + * 14 + * This program is distributed in the hope that it will be useful, but 15 + * WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 + * General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along 20 + * with this program; if not, write to the Free Software Foundation, Inc., 21 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 22 + * 23 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 + */ 25 + 26 + #include <linux/module.h> 27 + #include <linux/device.h> 28 + #include <linux/err.h> 29 + #include <linux/kdev_t.h> 30 + #include <linux/idr.h> 31 + #include <linux/thermal.h> 32 + #include <linux/spinlock.h> 33 + 34 + MODULE_AUTHOR("Zhang Rui") 35 + MODULE_DESCRIPTION("Generic thermal management sysfs support"); 36 + MODULE_LICENSE("GPL"); 37 + 38 + #define PREFIX "Thermal: " 39 + 40 + struct thermal_cooling_device_instance { 41 + int id; 42 + char name[THERMAL_NAME_LENGTH]; 43 + struct thermal_zone_device *tz; 44 + struct thermal_cooling_device *cdev; 45 + int trip; 46 + char attr_name[THERMAL_NAME_LENGTH]; 47 + struct device_attribute attr; 48 + struct list_head node; 49 + }; 50 + 51 + static DEFINE_IDR(thermal_tz_idr); 52 + static DEFINE_IDR(thermal_cdev_idr); 53 + static DEFINE_MUTEX(thermal_idr_lock); 54 + 55 + static LIST_HEAD(thermal_tz_list); 56 + static LIST_HEAD(thermal_cdev_list); 57 + static DEFINE_MUTEX(thermal_list_lock); 58 + 59 + static int get_idr(struct idr *idr, struct mutex *lock, int *id) 60 + { 61 + int err; 62 + 63 + again: 64 + if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) 65 + return -ENOMEM; 66 + 67 + if (lock) 68 + mutex_lock(lock); 69 + err = idr_get_new(idr, NULL, id); 70 + if (lock) 71 + mutex_unlock(lock); 72 + if (unlikely(err == -EAGAIN)) 73 + goto again; 74 + else if (unlikely(err)) 75 + return err; 76 + 77 + *id = *id & MAX_ID_MASK; 78 + return 0; 79 + } 80 + 81 + static void release_idr(struct idr *idr, struct mutex *lock, int id) 82 + { 83 + if (lock) 84 + mutex_lock(lock); 85 + idr_remove(idr, id); 86 + if (lock) 87 + mutex_unlock(lock); 88 + } 89 + 90 + /* sys I/F for thermal zone */ 91 + 92 + #define to_thermal_zone(_dev) \ 93 + container_of(_dev, struct thermal_zone_device, device) 94 + 95 + static ssize_t 96 + type_show(struct device *dev, struct device_attribute *attr, char *buf) 97 + { 98 + struct thermal_zone_device *tz = to_thermal_zone(dev); 99 + 100 + return sprintf(buf, "%s\n", tz->type); 101 + } 102 + 103 + static ssize_t 104 + temp_show(struct device *dev, struct device_attribute *attr, char *buf) 105 + { 106 + struct thermal_zone_device *tz = to_thermal_zone(dev); 107 + 108 + if (!tz->ops->get_temp) 109 + return -EPERM; 110 + 111 + return tz->ops->get_temp(tz, buf); 112 + } 113 + 114 + static ssize_t 115 + mode_show(struct device *dev, struct device_attribute *attr, char *buf) 116 + { 117 + struct thermal_zone_device *tz = to_thermal_zone(dev); 118 + 119 + if (!tz->ops->get_mode) 120 + return -EPERM; 121 + 122 + return tz->ops->get_mode(tz, buf); 123 + } 124 + 125 + static ssize_t 126 + mode_store(struct device *dev, struct device_attribute *attr, 127 + const char *buf, size_t count) 128 + { 129 + struct thermal_zone_device *tz = to_thermal_zone(dev); 130 + int result; 131 + 132 + if (!tz->ops->set_mode) 133 + return -EPERM; 134 + 135 + result = tz->ops->set_mode(tz, buf); 136 + if (result) 137 + return result; 138 + 139 + return count; 140 + } 141 + 142 + static ssize_t 143 + trip_point_type_show(struct device *dev, struct device_attribute *attr, 144 + char *buf) 145 + { 146 + struct thermal_zone_device *tz = to_thermal_zone(dev); 147 + int trip; 148 + 149 + if (!tz->ops->get_trip_type) 150 + return -EPERM; 151 + 152 + if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) 153 + return -EINVAL; 154 + 155 + return tz->ops->get_trip_type(tz, trip, buf); 156 + } 157 + 158 + static ssize_t 159 + trip_point_temp_show(struct device *dev, struct device_attribute *attr, 160 + char *buf) 161 + { 162 + struct thermal_zone_device *tz = to_thermal_zone(dev); 163 + int trip; 164 + 165 + if (!tz->ops->get_trip_temp) 166 + return -EPERM; 167 + 168 + if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) 169 + return -EINVAL; 170 + 171 + return tz->ops->get_trip_temp(tz, trip, buf); 172 + } 173 + 174 + static DEVICE_ATTR(type, 0444, type_show, NULL); 175 + static DEVICE_ATTR(temp, 0444, temp_show, NULL); 176 + static DEVICE_ATTR(mode, 0644, mode_show, mode_store); 177 + 178 + static struct device_attribute trip_point_attrs[] = { 179 + __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), 180 + __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), 181 + __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), 182 + __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), 183 + __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), 184 + __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), 185 + __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), 186 + __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), 187 + __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), 188 + __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), 189 + __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), 190 + __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), 191 + __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), 192 + __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), 193 + __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), 194 + __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), 195 + __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), 196 + __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), 197 + __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), 198 + __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), 199 + }; 200 + 201 + #define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ 202 + do { \ 203 + result = device_create_file(_dev, \ 204 + &trip_point_attrs[_index * 2]); \ 205 + if (result) \ 206 + break; \ 207 + result = device_create_file(_dev, \ 208 + &trip_point_attrs[_index * 2 + 1]); \ 209 + } while (0) 210 + 211 + #define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ 212 + do { \ 213 + device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ 214 + device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ 215 + } while (0) 216 + 217 + /* sys I/F for cooling device */ 218 + #define to_cooling_device(_dev) \ 219 + container_of(_dev, struct thermal_cooling_device, device) 220 + 221 + static ssize_t 222 + thermal_cooling_device_type_show(struct device *dev, 223 + struct device_attribute *attr, char *buf) 224 + { 225 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 226 + 227 + return sprintf(buf, "%s\n", cdev->type); 228 + } 229 + 230 + static ssize_t 231 + thermal_cooling_device_max_state_show(struct device *dev, 232 + struct device_attribute *attr, char *buf) 233 + { 234 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 235 + 236 + return cdev->ops->get_max_state(cdev, buf); 237 + } 238 + 239 + static ssize_t 240 + thermal_cooling_device_cur_state_show(struct device *dev, 241 + struct device_attribute *attr, char *buf) 242 + { 243 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 244 + 245 + return cdev->ops->get_cur_state(cdev, buf); 246 + } 247 + 248 + static ssize_t 249 + thermal_cooling_device_cur_state_store(struct device *dev, 250 + struct device_attribute *attr, 251 + const char *buf, size_t count) 252 + { 253 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 254 + int state; 255 + int result; 256 + 257 + if (!sscanf(buf, "%d\n", &state)) 258 + return -EINVAL; 259 + 260 + if (state < 0) 261 + return -EINVAL; 262 + 263 + result = cdev->ops->set_cur_state(cdev, state); 264 + if (result) 265 + return result; 266 + return count; 267 + } 268 + 269 + static struct device_attribute dev_attr_cdev_type = 270 + __ATTR(type, 0444, thermal_cooling_device_type_show, NULL); 271 + static DEVICE_ATTR(max_state, 0444, 272 + thermal_cooling_device_max_state_show, NULL); 273 + static DEVICE_ATTR(cur_state, 0644, 274 + thermal_cooling_device_cur_state_show, 275 + thermal_cooling_device_cur_state_store); 276 + 277 + static ssize_t 278 + thermal_cooling_device_trip_point_show(struct device *dev, 279 + struct device_attribute *attr, char *buf) 280 + { 281 + struct thermal_cooling_device_instance *instance; 282 + 283 + instance = 284 + container_of(attr, struct thermal_cooling_device_instance, attr); 285 + 286 + if (instance->trip == THERMAL_TRIPS_NONE) 287 + return sprintf(buf, "-1\n"); 288 + else 289 + return sprintf(buf, "%d\n", instance->trip); 290 + } 291 + 292 + /* Device management */ 293 + 294 + /** 295 + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 296 + * this function is usually called in the thermal zone device .bind callback. 297 + * @tz: thermal zone device 298 + * @trip: indicates which trip point the cooling devices is 299 + * associated with in this thermal zone. 300 + * @cdev: thermal cooling device 301 + */ 302 + int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, 303 + int trip, 304 + struct thermal_cooling_device *cdev) 305 + { 306 + struct thermal_cooling_device_instance *dev; 307 + struct thermal_cooling_device_instance *pos; 308 + int result; 309 + 310 + if (trip >= tz->trips || 311 + (trip < 0 && trip != THERMAL_TRIPS_NONE)) 312 + return -EINVAL; 313 + 314 + if (!tz || !cdev) 315 + return -EINVAL; 316 + 317 + dev = 318 + kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL); 319 + if (!dev) 320 + return -ENOMEM; 321 + dev->tz = tz; 322 + dev->cdev = cdev; 323 + dev->trip = trip; 324 + result = get_idr(&tz->idr, &tz->lock, &dev->id); 325 + if (result) 326 + goto free_mem; 327 + 328 + sprintf(dev->name, "cdev%d", dev->id); 329 + result = 330 + sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); 331 + if (result) 332 + goto release_idr; 333 + 334 + sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); 335 + dev->attr.attr.name = dev->attr_name; 336 + dev->attr.attr.mode = 0444; 337 + dev->attr.show = thermal_cooling_device_trip_point_show; 338 + result = device_create_file(&tz->device, &dev->attr); 339 + if (result) 340 + goto remove_symbol_link; 341 + 342 + mutex_lock(&tz->lock); 343 + list_for_each_entry(pos, &tz->cooling_devices, node) 344 + if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { 345 + result = -EEXIST; 346 + break; 347 + } 348 + if (!result) 349 + list_add_tail(&dev->node, &tz->cooling_devices); 350 + mutex_unlock(&tz->lock); 351 + 352 + if (!result) 353 + return 0; 354 + 355 + device_remove_file(&tz->device, &dev->attr); 356 + remove_symbol_link: 357 + sysfs_remove_link(&tz->device.kobj, dev->name); 358 + release_idr: 359 + release_idr(&tz->idr, &tz->lock, dev->id); 360 + free_mem: 361 + kfree(dev); 362 + return result; 363 + } 364 + EXPORT_SYMBOL(thermal_zone_bind_cooling_device); 365 + 366 + /** 367 + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone 368 + * this function is usually called in the thermal zone device .unbind callback. 369 + * @tz: thermal zone device 370 + * @trip: indicates which trip point the cooling devices is 371 + * associated with in this thermal zone. 372 + * @cdev: thermal cooling device 373 + */ 374 + int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, 375 + int trip, 376 + struct thermal_cooling_device *cdev) 377 + { 378 + struct thermal_cooling_device_instance *pos, *next; 379 + 380 + mutex_lock(&tz->lock); 381 + list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { 382 + if (pos->tz == tz && pos->trip == trip 383 + && pos->cdev == cdev) { 384 + list_del(&pos->node); 385 + mutex_unlock(&tz->lock); 386 + goto unbind; 387 + } 388 + } 389 + mutex_unlock(&tz->lock); 390 + 391 + return -ENODEV; 392 + 393 + unbind: 394 + device_remove_file(&tz->device, &pos->attr); 395 + sysfs_remove_link(&tz->device.kobj, pos->name); 396 + release_idr(&tz->idr, &tz->lock, pos->id); 397 + kfree(pos); 398 + return 0; 399 + } 400 + EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); 401 + 402 + static void thermal_release(struct device *dev) 403 + { 404 + struct thermal_zone_device *tz; 405 + struct thermal_cooling_device *cdev; 406 + 407 + if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) { 408 + tz = to_thermal_zone(dev); 409 + kfree(tz); 410 + } else { 411 + cdev = to_cooling_device(dev); 412 + kfree(cdev); 413 + } 414 + } 415 + 416 + static struct class thermal_class = { 417 + .name = "thermal", 418 + .dev_release = thermal_release, 419 + }; 420 + 421 + /** 422 + * thermal_cooling_device_register - register a new thermal cooling device 423 + * @type: the thermal cooling device type. 424 + * @devdata: device private data. 425 + * @ops: standard thermal cooling devices callbacks. 426 + */ 427 + struct thermal_cooling_device *thermal_cooling_device_register(char *type, 428 + void *devdata, struct thermal_cooling_device_ops *ops) 429 + { 430 + struct thermal_cooling_device *cdev; 431 + struct thermal_zone_device *pos; 432 + int result; 433 + 434 + if (strlen(type) >= THERMAL_NAME_LENGTH) 435 + return NULL; 436 + 437 + if (!ops || !ops->get_max_state || !ops->get_cur_state || 438 + !ops->set_cur_state) 439 + return NULL; 440 + 441 + cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); 442 + if (!cdev) 443 + return NULL; 444 + 445 + result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); 446 + if (result) { 447 + kfree(cdev); 448 + return NULL; 449 + } 450 + 451 + strcpy(cdev->type, type); 452 + cdev->ops = ops; 453 + cdev->device.class = &thermal_class; 454 + cdev->devdata = devdata; 455 + sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id); 456 + result = device_register(&cdev->device); 457 + if (result) { 458 + release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 459 + kfree(cdev); 460 + return NULL; 461 + } 462 + 463 + /* sys I/F */ 464 + if (type) { 465 + result = device_create_file(&cdev->device, 466 + &dev_attr_cdev_type); 467 + if (result) 468 + goto unregister; 469 + } 470 + 471 + result = device_create_file(&cdev->device, &dev_attr_max_state); 472 + if (result) 473 + goto unregister; 474 + 475 + result = device_create_file(&cdev->device, &dev_attr_cur_state); 476 + if (result) 477 + goto unregister; 478 + 479 + mutex_lock(&thermal_list_lock); 480 + list_add(&cdev->node, &thermal_cdev_list); 481 + list_for_each_entry(pos, &thermal_tz_list, node) { 482 + if (!pos->ops->bind) 483 + continue; 484 + result = pos->ops->bind(pos, cdev); 485 + if (result) 486 + break; 487 + 488 + } 489 + mutex_unlock(&thermal_list_lock); 490 + 491 + if (!result) 492 + return cdev; 493 + 494 + unregister: 495 + release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 496 + device_unregister(&cdev->device); 497 + return NULL; 498 + } 499 + EXPORT_SYMBOL(thermal_cooling_device_register); 500 + 501 + /** 502 + * thermal_cooling_device_unregister - removes the registered thermal cooling device 503 + * 504 + * @cdev: the thermal cooling device to remove. 505 + * 506 + * thermal_cooling_device_unregister() must be called when the device is no 507 + * longer needed. 508 + */ 509 + void thermal_cooling_device_unregister(struct 510 + thermal_cooling_device 511 + *cdev) 512 + { 513 + struct thermal_zone_device *tz; 514 + struct thermal_cooling_device *pos = NULL; 515 + 516 + if (!cdev) 517 + return; 518 + 519 + mutex_lock(&thermal_list_lock); 520 + list_for_each_entry(pos, &thermal_cdev_list, node) 521 + if (pos == cdev) 522 + break; 523 + if (pos != cdev) { 524 + /* thermal cooling device not found */ 525 + mutex_unlock(&thermal_list_lock); 526 + return; 527 + } 528 + list_del(&cdev->node); 529 + list_for_each_entry(tz, &thermal_tz_list, node) { 530 + if (!tz->ops->unbind) 531 + continue; 532 + tz->ops->unbind(tz, cdev); 533 + } 534 + mutex_unlock(&thermal_list_lock); 535 + if (cdev->type[0]) 536 + device_remove_file(&cdev->device, 537 + &dev_attr_cdev_type); 538 + device_remove_file(&cdev->device, &dev_attr_max_state); 539 + device_remove_file(&cdev->device, &dev_attr_cur_state); 540 + 541 + release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 542 + device_unregister(&cdev->device); 543 + return; 544 + } 545 + EXPORT_SYMBOL(thermal_cooling_device_unregister); 546 + 547 + /** 548 + * thermal_zone_device_register - register a new thermal zone device 549 + * @type: the thermal zone device type 550 + * @trips: the number of trip points the thermal zone support 551 + * @devdata: private device data 552 + * @ops: standard thermal zone device callbacks 553 + * 554 + * thermal_zone_device_unregister() must be called when the device is no 555 + * longer needed. 556 + */ 557 + struct thermal_zone_device *thermal_zone_device_register(char *type, 558 + int trips, void *devdata, 559 + struct thermal_zone_device_ops *ops) 560 + { 561 + struct thermal_zone_device *tz; 562 + struct thermal_cooling_device *pos; 563 + int result; 564 + int count; 565 + 566 + if (strlen(type) >= THERMAL_NAME_LENGTH) 567 + return NULL; 568 + 569 + if (trips > THERMAL_MAX_TRIPS || trips < 0) 570 + return NULL; 571 + 572 + if (!ops || !ops->get_temp) 573 + return NULL; 574 + 575 + tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); 576 + if (!tz) 577 + return NULL; 578 + 579 + INIT_LIST_HEAD(&tz->cooling_devices); 580 + idr_init(&tz->idr); 581 + mutex_init(&tz->lock); 582 + result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id); 583 + if (result) { 584 + kfree(tz); 585 + return NULL; 586 + } 587 + 588 + strcpy(tz->type, type); 589 + tz->ops = ops; 590 + tz->device.class = &thermal_class; 591 + tz->devdata = devdata; 592 + tz->trips = trips; 593 + sprintf(tz->device.bus_id, "thermal_zone%d", tz->id); 594 + result = device_register(&tz->device); 595 + if (result) { 596 + release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 597 + kfree(tz); 598 + return NULL; 599 + } 600 + 601 + /* sys I/F */ 602 + if (type) { 603 + result = device_create_file(&tz->device, &dev_attr_type); 604 + if (result) 605 + goto unregister; 606 + } 607 + 608 + result = device_create_file(&tz->device, &dev_attr_temp); 609 + if (result) 610 + goto unregister; 611 + 612 + if (ops->get_mode) { 613 + result = device_create_file(&tz->device, &dev_attr_mode); 614 + if (result) 615 + goto unregister; 616 + } 617 + 618 + for (count = 0; count < trips; count++) { 619 + TRIP_POINT_ATTR_ADD(&tz->device, count, result); 620 + if (result) 621 + goto unregister; 622 + } 623 + 624 + mutex_lock(&thermal_list_lock); 625 + list_add_tail(&tz->node, &thermal_tz_list); 626 + if (ops->bind) 627 + list_for_each_entry(pos, &thermal_cdev_list, node) { 628 + result = ops->bind(tz, pos); 629 + if (result) 630 + break; 631 + } 632 + mutex_unlock(&thermal_list_lock); 633 + 634 + if (!result) 635 + return tz; 636 + 637 + unregister: 638 + release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 639 + device_unregister(&tz->device); 640 + return NULL; 641 + } 642 + EXPORT_SYMBOL(thermal_zone_device_register); 643 + 644 + /** 645 + * thermal_device_unregister - removes the registered thermal zone device 646 + * 647 + * @tz: the thermal zone device to remove 648 + */ 649 + void thermal_zone_device_unregister(struct thermal_zone_device *tz) 650 + { 651 + struct thermal_cooling_device *cdev; 652 + struct thermal_zone_device *pos = NULL; 653 + int count; 654 + 655 + if (!tz) 656 + return; 657 + 658 + mutex_lock(&thermal_list_lock); 659 + list_for_each_entry(pos, &thermal_tz_list, node) 660 + if (pos == tz) 661 + break; 662 + if (pos != tz) { 663 + /* thermal zone device not found */ 664 + mutex_unlock(&thermal_list_lock); 665 + return; 666 + } 667 + list_del(&tz->node); 668 + if (tz->ops->unbind) 669 + list_for_each_entry(cdev, &thermal_cdev_list, node) 670 + tz->ops->unbind(tz, cdev); 671 + mutex_unlock(&thermal_list_lock); 672 + 673 + if (tz->type[0]) 674 + device_remove_file(&tz->device, &dev_attr_type); 675 + device_remove_file(&tz->device, &dev_attr_temp); 676 + if (tz->ops->get_mode) 677 + device_remove_file(&tz->device, &dev_attr_mode); 678 + 679 + for (count = 0; count < tz->trips; count++) 680 + TRIP_POINT_ATTR_REMOVE(&tz->device, count); 681 + 682 + release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 683 + idr_destroy(&tz->idr); 684 + mutex_destroy(&tz->lock); 685 + device_unregister(&tz->device); 686 + return; 687 + } 688 + EXPORT_SYMBOL(thermal_zone_device_unregister); 689 + 690 + static int __init thermal_init(void) 691 + { 692 + int result = 0; 693 + 694 + result = class_register(&thermal_class); 695 + if (result) { 696 + idr_destroy(&thermal_tz_idr); 697 + idr_destroy(&thermal_cdev_idr); 698 + mutex_destroy(&thermal_idr_lock); 699 + mutex_destroy(&thermal_list_lock); 700 + } 701 + return result; 702 + } 703 + 704 + static void __exit thermal_exit(void) 705 + { 706 + class_unregister(&thermal_class); 707 + idr_destroy(&thermal_tz_idr); 708 + idr_destroy(&thermal_cdev_idr); 709 + mutex_destroy(&thermal_idr_lock); 710 + mutex_destroy(&thermal_list_lock); 711 + } 712 + 713 + subsys_initcall(thermal_init); 714 + module_exit(thermal_exit);
+2
include/acpi/acpi_bus.h
··· 321 321 322 322 extern struct kobject *acpi_kobj; 323 323 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); 324 + void acpi_bus_private_data_handler(acpi_handle, u32, void *); 325 + int acpi_bus_get_private_data(acpi_handle, void **); 324 326 /* 325 327 * External Functions 326 328 */
+3 -3
include/acpi/processor.h
··· 4 4 #include <linux/kernel.h> 5 5 #include <linux/cpu.h> 6 6 #include <linux/cpuidle.h> 7 - 7 + #include <linux/thermal.h> 8 8 #include <asm/acpi.h> 9 9 10 10 #define ACPI_PROCESSOR_BUSY_METRIC 10 ··· 219 219 struct acpi_processor_performance *performance; 220 220 struct acpi_processor_throttling throttling; 221 221 struct acpi_processor_limit limit; 222 - 222 + struct thermal_cooling_device *cdev; 223 223 /* the _PDC objects for this processor, if any */ 224 224 struct acpi_object_list *pdc; 225 225 }; ··· 331 331 /* in processor_thermal.c */ 332 332 int acpi_processor_get_limit_info(struct acpi_processor *pr); 333 333 extern struct file_operations acpi_processor_limit_fops; 334 - 334 + extern struct thermal_cooling_device_ops processor_cooling_ops; 335 335 #ifdef CONFIG_CPU_FREQ 336 336 void acpi_thermal_cpufreq_init(void); 337 337 void acpi_thermal_cpufreq_exit(void);
+94
include/linux/thermal.h
··· 1 + /* 2 + * thermal.h ($Revision: 0 $) 3 + * 4 + * Copyright (C) 2008 Intel Corp 5 + * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 6 + * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 7 + * 8 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; version 2 of the License. 12 + * 13 + * This program is distributed in the hope that it will be useful, but 14 + * WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 + * General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License along 19 + * with this program; if not, write to the Free Software Foundation, Inc., 20 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 21 + * 22 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 + */ 24 + 25 + #ifndef __THERMAL_H__ 26 + #define __THERMAL_H__ 27 + 28 + #include <linux/idr.h> 29 + #include <linux/device.h> 30 + 31 + struct thermal_zone_device; 32 + struct thermal_cooling_device; 33 + 34 + struct thermal_zone_device_ops { 35 + int (*bind) (struct thermal_zone_device *, 36 + struct thermal_cooling_device *); 37 + int (*unbind) (struct thermal_zone_device *, 38 + struct thermal_cooling_device *); 39 + int (*get_temp) (struct thermal_zone_device *, char *); 40 + int (*get_mode) (struct thermal_zone_device *, char *); 41 + int (*set_mode) (struct thermal_zone_device *, const char *); 42 + int (*get_trip_type) (struct thermal_zone_device *, int, char *); 43 + int (*get_trip_temp) (struct thermal_zone_device *, int, char *); 44 + }; 45 + 46 + struct thermal_cooling_device_ops { 47 + int (*get_max_state) (struct thermal_cooling_device *, char *); 48 + int (*get_cur_state) (struct thermal_cooling_device *, char *); 49 + int (*set_cur_state) (struct thermal_cooling_device *, unsigned int); 50 + }; 51 + 52 + #define THERMAL_TRIPS_NONE -1 53 + #define THERMAL_MAX_TRIPS 10 54 + #define THERMAL_NAME_LENGTH 20 55 + struct thermal_cooling_device { 56 + int id; 57 + char type[THERMAL_NAME_LENGTH]; 58 + struct device device; 59 + void *devdata; 60 + struct thermal_cooling_device_ops *ops; 61 + struct list_head node; 62 + }; 63 + 64 + #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ 65 + ((long)t-2732+5)/10 : ((long)t-2732-5)/10) 66 + #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) 67 + 68 + struct thermal_zone_device { 69 + int id; 70 + char type[THERMAL_NAME_LENGTH]; 71 + struct device device; 72 + void *devdata; 73 + int trips; 74 + struct thermal_zone_device_ops *ops; 75 + struct list_head cooling_devices; 76 + struct idr idr; 77 + struct mutex lock; /* protect cooling devices list */ 78 + struct list_head node; 79 + }; 80 + 81 + struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, 82 + struct thermal_zone_device_ops *); 83 + void thermal_zone_device_unregister(struct thermal_zone_device *); 84 + 85 + int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, 86 + struct thermal_cooling_device *); 87 + int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, 88 + struct thermal_cooling_device *); 89 + 90 + struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, 91 + struct thermal_cooling_device_ops *); 92 + void thermal_cooling_device_unregister(struct thermal_cooling_device *); 93 + 94 + #endif /* __THERMAL_H__ */