ia64/linux-2.6.18-xen.hg

view drivers/acpi/thermal.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
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; either version 2 of the License, or (at
12 * your option) any later version.
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 * This driver fully implements the ACPI thermal policy as described in the
26 * ACPI 2.0 Specification.
27 *
28 * TBD: 1. Implement passive cooling hysteresis.
29 * 2. Enhance passive cooling (CPU) states/limit interface to support
30 * concepts of 'multiple limiters', upper/lower limits, etc.
31 *
32 */
34 #include <linux/kernel.h>
35 #include <linux/module.h>
36 #include <linux/init.h>
37 #include <linux/types.h>
38 #include <linux/proc_fs.h>
39 #include <linux/sched.h>
40 #include <linux/kmod.h>
41 #include <linux/seq_file.h>
42 #include <asm/uaccess.h>
44 #include <acpi/acpi_bus.h>
45 #include <acpi/acpi_drivers.h>
47 #define ACPI_THERMAL_COMPONENT 0x04000000
48 #define ACPI_THERMAL_CLASS "thermal_zone"
49 #define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver"
50 #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
51 #define ACPI_THERMAL_FILE_STATE "state"
52 #define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
53 #define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points"
54 #define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode"
55 #define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency"
56 #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
57 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
58 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
59 #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
60 #define ACPI_THERMAL_NOTIFY_HOT 0xF1
61 #define ACPI_THERMAL_MODE_ACTIVE 0x00
62 #define ACPI_THERMAL_MODE_PASSIVE 0x01
63 #define ACPI_THERMAL_MODE_CRITICAL 0xff
64 #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
66 #define ACPI_THERMAL_MAX_ACTIVE 10
67 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
69 #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
70 #define CELSIUS_TO_KELVIN(t) ((t+273)*10)
72 #define _COMPONENT ACPI_THERMAL_COMPONENT
73 ACPI_MODULE_NAME("acpi_thermal")
75 MODULE_AUTHOR("Paul Diefenbaugh");
76 MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
77 MODULE_LICENSE("GPL");
79 static int tzp;
80 module_param(tzp, int, 0);
81 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
83 static int acpi_thermal_add(struct acpi_device *device);
84 static int acpi_thermal_remove(struct acpi_device *device, int type);
85 static int acpi_thermal_resume(struct acpi_device *device, int state);
86 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
87 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
88 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
89 static ssize_t acpi_thermal_write_trip_points(struct file *,
90 const char __user *, size_t,
91 loff_t *);
92 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
93 static ssize_t acpi_thermal_write_cooling_mode(struct file *,
94 const char __user *, size_t,
95 loff_t *);
96 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
97 static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
98 size_t, loff_t *);
100 static struct acpi_driver acpi_thermal_driver = {
101 .name = ACPI_THERMAL_DRIVER_NAME,
102 .class = ACPI_THERMAL_CLASS,
103 .ids = ACPI_THERMAL_HID,
104 .ops = {
105 .add = acpi_thermal_add,
106 .remove = acpi_thermal_remove,
107 .resume = acpi_thermal_resume,
108 },
109 };
111 struct acpi_thermal_state {
112 u8 critical:1;
113 u8 hot:1;
114 u8 passive:1;
115 u8 active:1;
116 u8 reserved:4;
117 int active_index;
118 };
120 struct acpi_thermal_state_flags {
121 u8 valid:1;
122 u8 enabled:1;
123 u8 reserved:6;
124 };
126 struct acpi_thermal_critical {
127 struct acpi_thermal_state_flags flags;
128 unsigned long temperature;
129 };
131 struct acpi_thermal_hot {
132 struct acpi_thermal_state_flags flags;
133 unsigned long temperature;
134 };
136 struct acpi_thermal_passive {
137 struct acpi_thermal_state_flags flags;
138 unsigned long temperature;
139 unsigned long tc1;
140 unsigned long tc2;
141 unsigned long tsp;
142 struct acpi_handle_list devices;
143 };
145 struct acpi_thermal_active {
146 struct acpi_thermal_state_flags flags;
147 unsigned long temperature;
148 struct acpi_handle_list devices;
149 };
151 struct acpi_thermal_trips {
152 struct acpi_thermal_critical critical;
153 struct acpi_thermal_hot hot;
154 struct acpi_thermal_passive passive;
155 struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
156 };
158 struct acpi_thermal_flags {
159 u8 cooling_mode:1; /* _SCP */
160 u8 devices:1; /* _TZD */
161 u8 reserved:6;
162 };
164 struct acpi_thermal {
165 struct acpi_device * device;
166 acpi_bus_id name;
167 unsigned long temperature;
168 unsigned long last_temperature;
169 unsigned long polling_frequency;
170 u8 cooling_mode;
171 volatile u8 zombie;
172 struct acpi_thermal_flags flags;
173 struct acpi_thermal_state state;
174 struct acpi_thermal_trips trips;
175 struct acpi_handle_list devices;
176 struct timer_list timer;
177 };
179 static const struct file_operations acpi_thermal_state_fops = {
180 .open = acpi_thermal_state_open_fs,
181 .read = seq_read,
182 .llseek = seq_lseek,
183 .release = single_release,
184 };
186 static const struct file_operations acpi_thermal_temp_fops = {
187 .open = acpi_thermal_temp_open_fs,
188 .read = seq_read,
189 .llseek = seq_lseek,
190 .release = single_release,
191 };
193 static const struct file_operations acpi_thermal_trip_fops = {
194 .open = acpi_thermal_trip_open_fs,
195 .read = seq_read,
196 .write = acpi_thermal_write_trip_points,
197 .llseek = seq_lseek,
198 .release = single_release,
199 };
201 static const struct file_operations acpi_thermal_cooling_fops = {
202 .open = acpi_thermal_cooling_open_fs,
203 .read = seq_read,
204 .write = acpi_thermal_write_cooling_mode,
205 .llseek = seq_lseek,
206 .release = single_release,
207 };
209 static const struct file_operations acpi_thermal_polling_fops = {
210 .open = acpi_thermal_polling_open_fs,
211 .read = seq_read,
212 .write = acpi_thermal_write_polling,
213 .llseek = seq_lseek,
214 .release = single_release,
215 };
217 /* --------------------------------------------------------------------------
218 Thermal Zone Management
219 -------------------------------------------------------------------------- */
221 static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
222 {
223 acpi_status status = AE_OK;
226 if (!tz)
227 return -EINVAL;
229 tz->last_temperature = tz->temperature;
231 status =
232 acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
233 if (ACPI_FAILURE(status))
234 return -ENODEV;
236 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
237 tz->temperature));
239 return 0;
240 }
242 static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
243 {
244 acpi_status status = AE_OK;
247 if (!tz)
248 return -EINVAL;
250 status =
251 acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
252 &tz->polling_frequency);
253 if (ACPI_FAILURE(status))
254 return -ENODEV;
256 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
257 tz->polling_frequency));
259 return 0;
260 }
262 static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
263 {
265 if (!tz)
266 return -EINVAL;
268 tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
270 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
271 "Polling frequency set to %lu seconds\n",
272 tz->polling_frequency));
274 return 0;
275 }
277 static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
278 {
279 acpi_status status = AE_OK;
280 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
281 struct acpi_object_list arg_list = { 1, &arg0 };
282 acpi_handle handle = NULL;
285 if (!tz)
286 return -EINVAL;
288 status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
289 if (ACPI_FAILURE(status)) {
290 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
291 return -ENODEV;
292 }
294 arg0.integer.value = mode;
296 status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
297 if (ACPI_FAILURE(status))
298 return -ENODEV;
300 tz->cooling_mode = mode;
302 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
303 mode ? "passive" : "active"));
305 return 0;
306 }
308 static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
309 {
310 acpi_status status = AE_OK;
311 int i = 0;
314 if (!tz)
315 return -EINVAL;
317 /* Critical Shutdown (required) */
319 status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
320 &tz->trips.critical.temperature);
321 if (ACPI_FAILURE(status)) {
322 tz->trips.critical.flags.valid = 0;
323 ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
324 return -ENODEV;
325 } else {
326 tz->trips.critical.flags.valid = 1;
327 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
328 "Found critical threshold [%lu]\n",
329 tz->trips.critical.temperature));
330 }
332 /* Critical Sleep (optional) */
334 status =
335 acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
336 &tz->trips.hot.temperature);
337 if (ACPI_FAILURE(status)) {
338 tz->trips.hot.flags.valid = 0;
339 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
340 } else {
341 tz->trips.hot.flags.valid = 1;
342 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
343 tz->trips.hot.temperature));
344 }
346 /* Passive: Processors (optional) */
348 status =
349 acpi_evaluate_integer(tz->device->handle, "_PSV", NULL,
350 &tz->trips.passive.temperature);
351 if (ACPI_FAILURE(status)) {
352 tz->trips.passive.flags.valid = 0;
353 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
354 } else {
355 tz->trips.passive.flags.valid = 1;
357 status =
358 acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
359 &tz->trips.passive.tc1);
360 if (ACPI_FAILURE(status))
361 tz->trips.passive.flags.valid = 0;
363 status =
364 acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
365 &tz->trips.passive.tc2);
366 if (ACPI_FAILURE(status))
367 tz->trips.passive.flags.valid = 0;
369 status =
370 acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
371 &tz->trips.passive.tsp);
372 if (ACPI_FAILURE(status))
373 tz->trips.passive.flags.valid = 0;
375 status =
376 acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
377 &tz->trips.passive.devices);
378 if (ACPI_FAILURE(status))
379 tz->trips.passive.flags.valid = 0;
381 if (!tz->trips.passive.flags.valid)
382 printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
383 else
384 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
385 "Found passive threshold [%lu]\n",
386 tz->trips.passive.temperature));
387 }
389 /* Active: Fans, etc. (optional) */
391 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
393 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
395 status =
396 acpi_evaluate_integer(tz->device->handle, name, NULL,
397 &tz->trips.active[i].temperature);
398 if (ACPI_FAILURE(status))
399 break;
401 name[2] = 'L';
402 status =
403 acpi_evaluate_reference(tz->device->handle, name, NULL,
404 &tz->trips.active[i].devices);
405 if (ACPI_SUCCESS(status)) {
406 tz->trips.active[i].flags.valid = 1;
407 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
408 "Found active threshold [%d]:[%lu]\n",
409 i, tz->trips.active[i].temperature));
410 } else
411 ACPI_EXCEPTION((AE_INFO, status,
412 "Invalid active threshold [%d]", i));
413 }
415 return 0;
416 }
418 static int acpi_thermal_get_devices(struct acpi_thermal *tz)
419 {
420 acpi_status status = AE_OK;
423 if (!tz)
424 return -EINVAL;
426 status =
427 acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
428 if (ACPI_FAILURE(status))
429 return -ENODEV;
431 return 0;
432 }
434 static int acpi_thermal_call_usermode(char *path)
435 {
436 char *argv[2] = { NULL, NULL };
437 char *envp[3] = { NULL, NULL, NULL };
440 if (!path)
441 return -EINVAL;
443 argv[0] = path;
445 /* minimal command environment */
446 envp[0] = "HOME=/";
447 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
449 call_usermodehelper(argv[0], argv, envp, 0);
451 return 0;
452 }
454 static int acpi_thermal_critical(struct acpi_thermal *tz)
455 {
456 if (!tz || !tz->trips.critical.flags.valid)
457 return -EINVAL;
459 if (tz->temperature >= tz->trips.critical.temperature) {
460 printk(KERN_WARNING PREFIX "Critical trip point\n");
461 tz->trips.critical.flags.enabled = 1;
462 } else if (tz->trips.critical.flags.enabled)
463 tz->trips.critical.flags.enabled = 0;
465 printk(KERN_EMERG
466 "Critical temperature reached (%ld C), shutting down.\n",
467 KELVIN_TO_CELSIUS(tz->temperature));
468 acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
469 tz->trips.critical.flags.enabled);
471 acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
473 return 0;
474 }
476 static int acpi_thermal_hot(struct acpi_thermal *tz)
477 {
478 if (!tz || !tz->trips.hot.flags.valid)
479 return -EINVAL;
481 if (tz->temperature >= tz->trips.hot.temperature) {
482 printk(KERN_WARNING PREFIX "Hot trip point\n");
483 tz->trips.hot.flags.enabled = 1;
484 } else if (tz->trips.hot.flags.enabled)
485 tz->trips.hot.flags.enabled = 0;
487 acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
488 tz->trips.hot.flags.enabled);
490 /* TBD: Call user-mode "sleep(S4)" function */
492 return 0;
493 }
495 static void acpi_thermal_passive(struct acpi_thermal *tz)
496 {
497 int result = 1;
498 struct acpi_thermal_passive *passive = NULL;
499 int trend = 0;
500 int i = 0;
503 if (!tz || !tz->trips.passive.flags.valid)
504 return;
506 passive = &(tz->trips.passive);
508 /*
509 * Above Trip?
510 * -----------
511 * Calculate the thermal trend (using the passive cooling equation)
512 * and modify the performance limit for all passive cooling devices
513 * accordingly. Note that we assume symmetry.
514 */
515 if (tz->temperature >= passive->temperature) {
516 trend =
517 (passive->tc1 * (tz->temperature - tz->last_temperature)) +
518 (passive->tc2 * (tz->temperature - passive->temperature));
519 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
520 "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
521 trend, passive->tc1, tz->temperature,
522 tz->last_temperature, passive->tc2,
523 tz->temperature, passive->temperature));
524 passive->flags.enabled = 1;
525 /* Heating up? */
526 if (trend > 0)
527 for (i = 0; i < passive->devices.count; i++)
528 acpi_processor_set_thermal_limit(passive->
529 devices.
530 handles[i],
531 ACPI_PROCESSOR_LIMIT_INCREMENT);
532 /* Cooling off? */
533 else if (trend < 0) {
534 for (i = 0; i < passive->devices.count; i++)
535 /*
536 * assume that we are on highest
537 * freq/lowest thrott and can leave
538 * passive mode, even in error case
539 */
540 if (!acpi_processor_set_thermal_limit
541 (passive->devices.handles[i],
542 ACPI_PROCESSOR_LIMIT_DECREMENT))
543 result = 0;
544 /*
545 * Leave cooling mode, even if the temp might
546 * higher than trip point This is because some
547 * machines might have long thermal polling
548 * frequencies (tsp) defined. We will fall back
549 * into passive mode in next cycle (probably quicker)
550 */
551 if (result) {
552 passive->flags.enabled = 0;
553 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
554 "Disabling passive cooling, still above threshold,"
555 " but we are cooling down\n"));
556 }
557 }
558 return;
559 }
561 /*
562 * Below Trip?
563 * -----------
564 * Implement passive cooling hysteresis to slowly increase performance
565 * and avoid thrashing around the passive trip point. Note that we
566 * assume symmetry.
567 */
568 if (!passive->flags.enabled)
569 return;
570 for (i = 0; i < passive->devices.count; i++)
571 if (!acpi_processor_set_thermal_limit
572 (passive->devices.handles[i],
573 ACPI_PROCESSOR_LIMIT_DECREMENT))
574 result = 0;
575 if (result) {
576 passive->flags.enabled = 0;
577 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
578 "Disabling passive cooling (zone is cool)\n"));
579 }
580 }
582 static void acpi_thermal_active(struct acpi_thermal *tz)
583 {
584 int result = 0;
585 struct acpi_thermal_active *active = NULL;
586 int i = 0;
587 int j = 0;
588 unsigned long maxtemp = 0;
591 if (!tz)
592 return;
594 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
595 active = &(tz->trips.active[i]);
596 if (!active || !active->flags.valid)
597 break;
598 if (tz->temperature >= active->temperature) {
599 /*
600 * Above Threshold?
601 * ----------------
602 * If not already enabled, turn ON all cooling devices
603 * associated with this active threshold.
604 */
605 if (active->temperature > maxtemp)
606 tz->state.active_index = i;
607 maxtemp = active->temperature;
608 if (active->flags.enabled)
609 continue;
610 for (j = 0; j < active->devices.count; j++) {
611 result =
612 acpi_bus_set_power(active->devices.
613 handles[j],
614 ACPI_STATE_D0);
615 if (result) {
616 printk(KERN_WARNING PREFIX
617 "Unable to turn cooling device [%p] 'on'\n",
618 active->devices.
619 handles[j]);
620 continue;
621 }
622 active->flags.enabled = 1;
623 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
624 "Cooling device [%p] now 'on'\n",
625 active->devices.handles[j]));
626 }
627 continue;
628 }
629 if (!active->flags.enabled)
630 continue;
631 /*
632 * Below Threshold?
633 * ----------------
634 * Turn OFF all cooling devices associated with this
635 * threshold.
636 */
637 for (j = 0; j < active->devices.count; j++) {
638 result = acpi_bus_set_power(active->devices.handles[j],
639 ACPI_STATE_D3);
640 if (result) {
641 printk(KERN_WARNING PREFIX
642 "Unable to turn cooling device [%p] 'off'\n",
643 active->devices.handles[j]);
644 continue;
645 }
646 active->flags.enabled = 0;
647 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
648 "Cooling device [%p] now 'off'\n",
649 active->devices.handles[j]));
650 }
651 }
652 }
654 static void acpi_thermal_check(void *context);
656 static void acpi_thermal_run(unsigned long data)
657 {
658 struct acpi_thermal *tz = (struct acpi_thermal *)data;
659 if (!tz->zombie)
660 acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
661 }
663 static void acpi_thermal_check(void *data)
664 {
665 int result = 0;
666 struct acpi_thermal *tz = (struct acpi_thermal *)data;
667 unsigned long sleep_time = 0;
668 int i = 0;
669 struct acpi_thermal_state state;
672 if (!tz) {
673 printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
674 return;
675 }
677 state = tz->state;
679 result = acpi_thermal_get_temperature(tz);
680 if (result)
681 return;
683 memset(&tz->state, 0, sizeof(tz->state));
685 /*
686 * Check Trip Points
687 * -----------------
688 * Compare the current temperature to the trip point values to see
689 * if we've entered one of the thermal policy states. Note that
690 * this function determines when a state is entered, but the
691 * individual policy decides when it is exited (e.g. hysteresis).
692 */
693 if (tz->trips.critical.flags.valid)
694 state.critical |=
695 (tz->temperature >= tz->trips.critical.temperature);
696 if (tz->trips.hot.flags.valid)
697 state.hot |= (tz->temperature >= tz->trips.hot.temperature);
698 if (tz->trips.passive.flags.valid)
699 state.passive |=
700 (tz->temperature >= tz->trips.passive.temperature);
701 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
702 if (tz->trips.active[i].flags.valid)
703 state.active |=
704 (tz->temperature >=
705 tz->trips.active[i].temperature);
707 /*
708 * Invoke Policy
709 * -------------
710 * Separated from the above check to allow individual policy to
711 * determine when to exit a given state.
712 */
713 if (state.critical)
714 acpi_thermal_critical(tz);
715 if (state.hot)
716 acpi_thermal_hot(tz);
717 if (state.passive)
718 acpi_thermal_passive(tz);
719 if (state.active)
720 acpi_thermal_active(tz);
722 /*
723 * Calculate State
724 * ---------------
725 * Again, separated from the above two to allow independent policy
726 * decisions.
727 */
728 tz->state.critical = tz->trips.critical.flags.enabled;
729 tz->state.hot = tz->trips.hot.flags.enabled;
730 tz->state.passive = tz->trips.passive.flags.enabled;
731 tz->state.active = 0;
732 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
733 tz->state.active |= tz->trips.active[i].flags.enabled;
735 /*
736 * Calculate Sleep Time
737 * --------------------
738 * If we're in the passive state, use _TSP's value. Otherwise
739 * use the default polling frequency (e.g. _TZP). If no polling
740 * frequency is specified then we'll wait forever (at least until
741 * a thermal event occurs). Note that _TSP and _TZD values are
742 * given in 1/10th seconds (we must covert to milliseconds).
743 */
744 if (tz->state.passive)
745 sleep_time = tz->trips.passive.tsp * 100;
746 else if (tz->polling_frequency > 0)
747 sleep_time = tz->polling_frequency * 100;
749 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
750 tz->name, tz->temperature, sleep_time));
752 /*
753 * Schedule Next Poll
754 * ------------------
755 */
756 if (!sleep_time) {
757 if (timer_pending(&(tz->timer)))
758 del_timer(&(tz->timer));
759 } else {
760 if (timer_pending(&(tz->timer)))
761 mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
762 else {
763 tz->timer.data = (unsigned long)tz;
764 tz->timer.function = acpi_thermal_run;
765 tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
766 add_timer(&(tz->timer));
767 }
768 }
770 return;
771 }
773 /* --------------------------------------------------------------------------
774 FS Interface (/proc)
775 -------------------------------------------------------------------------- */
777 static struct proc_dir_entry *acpi_thermal_dir;
779 static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
780 {
781 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
784 if (!tz)
785 goto end;
787 seq_puts(seq, "state: ");
789 if (!tz->state.critical && !tz->state.hot && !tz->state.passive
790 && !tz->state.active)
791 seq_puts(seq, "ok\n");
792 else {
793 if (tz->state.critical)
794 seq_puts(seq, "critical ");
795 if (tz->state.hot)
796 seq_puts(seq, "hot ");
797 if (tz->state.passive)
798 seq_puts(seq, "passive ");
799 if (tz->state.active)
800 seq_printf(seq, "active[%d]", tz->state.active_index);
801 seq_puts(seq, "\n");
802 }
804 end:
805 return 0;
806 }
808 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
809 {
810 return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
811 }
813 static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
814 {
815 int result = 0;
816 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
819 if (!tz)
820 goto end;
822 result = acpi_thermal_get_temperature(tz);
823 if (result)
824 goto end;
826 seq_printf(seq, "temperature: %ld C\n",
827 KELVIN_TO_CELSIUS(tz->temperature));
829 end:
830 return 0;
831 }
833 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
834 {
835 return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
836 }
838 static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
839 {
840 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
841 int i = 0;
842 int j = 0;
845 if (!tz)
846 goto end;
848 if (tz->trips.critical.flags.valid)
849 seq_printf(seq, "critical (S5): %ld C\n",
850 KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
852 if (tz->trips.hot.flags.valid)
853 seq_printf(seq, "hot (S4): %ld C\n",
854 KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
856 if (tz->trips.passive.flags.valid) {
857 seq_printf(seq,
858 "passive: %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
859 KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
860 tz->trips.passive.tc1, tz->trips.passive.tc2,
861 tz->trips.passive.tsp);
862 for (j = 0; j < tz->trips.passive.devices.count; j++) {
864 seq_printf(seq, "0x%p ",
865 tz->trips.passive.devices.handles[j]);
866 }
867 seq_puts(seq, "\n");
868 }
870 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
871 if (!(tz->trips.active[i].flags.valid))
872 break;
873 seq_printf(seq, "active[%d]: %ld C: devices=",
874 i,
875 KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
876 for (j = 0; j < tz->trips.active[i].devices.count; j++)
877 seq_printf(seq, "0x%p ",
878 tz->trips.active[i].devices.handles[j]);
879 seq_puts(seq, "\n");
880 }
882 end:
883 return 0;
884 }
886 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
887 {
888 return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
889 }
891 static ssize_t
892 acpi_thermal_write_trip_points(struct file *file,
893 const char __user * buffer,
894 size_t count, loff_t * ppos)
895 {
896 struct seq_file *m = (struct seq_file *)file->private_data;
897 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
899 char *limit_string;
900 int num, critical, hot, passive;
901 int *active;
902 int i = 0;
905 limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
906 if (!limit_string)
907 return -ENOMEM;
909 memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
911 active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
912 if (!active) {
913 kfree(limit_string);
914 return -ENOMEM;
915 }
917 if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
918 count = -EINVAL;
919 goto end;
920 }
922 if (copy_from_user(limit_string, buffer, count)) {
923 count = -EFAULT;
924 goto end;
925 }
927 limit_string[count] = '\0';
929 num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
930 &critical, &hot, &passive,
931 &active[0], &active[1], &active[2], &active[3], &active[4],
932 &active[5], &active[6], &active[7], &active[8],
933 &active[9]);
934 if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
935 count = -EINVAL;
936 goto end;
937 }
939 tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
940 tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
941 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
942 for (i = 0; i < num - 3; i++) {
943 if (!(tz->trips.active[i].flags.valid))
944 break;
945 tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
946 }
948 end:
949 kfree(active);
950 kfree(limit_string);
951 return count;
952 }
954 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
955 {
956 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
959 if (!tz)
960 goto end;
962 if (!tz->flags.cooling_mode) {
963 seq_puts(seq, "<setting not supported>\n");
964 }
966 if (tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL)
967 seq_printf(seq, "cooling mode: critical\n");
968 else
969 seq_printf(seq, "cooling mode: %s\n",
970 tz->cooling_mode ? "passive" : "active");
972 end:
973 return 0;
974 }
976 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
977 {
978 return single_open(file, acpi_thermal_cooling_seq_show,
979 PDE(inode)->data);
980 }
982 static ssize_t
983 acpi_thermal_write_cooling_mode(struct file *file,
984 const char __user * buffer,
985 size_t count, loff_t * ppos)
986 {
987 struct seq_file *m = (struct seq_file *)file->private_data;
988 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
989 int result = 0;
990 char mode_string[12] = { '\0' };
993 if (!tz || (count > sizeof(mode_string) - 1))
994 return -EINVAL;
996 if (!tz->flags.cooling_mode)
997 return -ENODEV;
999 if (copy_from_user(mode_string, buffer, count))
1000 return -EFAULT;
1002 mode_string[count] = '\0';
1004 result = acpi_thermal_set_cooling_mode(tz,
1005 simple_strtoul(mode_string, NULL,
1006 0));
1007 if (result)
1008 return result;
1010 acpi_thermal_check(tz);
1012 return count;
1015 static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
1017 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
1020 if (!tz)
1021 goto end;
1023 if (!tz->polling_frequency) {
1024 seq_puts(seq, "<polling disabled>\n");
1025 goto end;
1028 seq_printf(seq, "polling frequency: %lu seconds\n",
1029 (tz->polling_frequency / 10));
1031 end:
1032 return 0;
1035 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
1037 return single_open(file, acpi_thermal_polling_seq_show,
1038 PDE(inode)->data);
1041 static ssize_t
1042 acpi_thermal_write_polling(struct file *file,
1043 const char __user * buffer,
1044 size_t count, loff_t * ppos)
1046 struct seq_file *m = (struct seq_file *)file->private_data;
1047 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
1048 int result = 0;
1049 char polling_string[12] = { '\0' };
1050 int seconds = 0;
1053 if (!tz || (count > sizeof(polling_string) - 1))
1054 return -EINVAL;
1056 if (copy_from_user(polling_string, buffer, count))
1057 return -EFAULT;
1059 polling_string[count] = '\0';
1061 seconds = simple_strtoul(polling_string, NULL, 0);
1063 result = acpi_thermal_set_polling(tz, seconds);
1064 if (result)
1065 return result;
1067 acpi_thermal_check(tz);
1069 return count;
1072 static int acpi_thermal_add_fs(struct acpi_device *device)
1074 struct proc_dir_entry *entry = NULL;
1077 if (!acpi_device_dir(device)) {
1078 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1079 acpi_thermal_dir);
1080 if (!acpi_device_dir(device))
1081 return -ENODEV;
1082 acpi_device_dir(device)->owner = THIS_MODULE;
1085 /* 'state' [R] */
1086 entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
1087 S_IRUGO, acpi_device_dir(device));
1088 if (!entry)
1089 return -ENODEV;
1090 else {
1091 entry->proc_fops = &acpi_thermal_state_fops;
1092 entry->data = acpi_driver_data(device);
1093 entry->owner = THIS_MODULE;
1096 /* 'temperature' [R] */
1097 entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1098 S_IRUGO, acpi_device_dir(device));
1099 if (!entry)
1100 return -ENODEV;
1101 else {
1102 entry->proc_fops = &acpi_thermal_temp_fops;
1103 entry->data = acpi_driver_data(device);
1104 entry->owner = THIS_MODULE;
1107 /* 'trip_points' [R/W] */
1108 entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1109 S_IFREG | S_IRUGO | S_IWUSR,
1110 acpi_device_dir(device));
1111 if (!entry)
1112 return -ENODEV;
1113 else {
1114 entry->proc_fops = &acpi_thermal_trip_fops;
1115 entry->data = acpi_driver_data(device);
1116 entry->owner = THIS_MODULE;
1119 /* 'cooling_mode' [R/W] */
1120 entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1121 S_IFREG | S_IRUGO | S_IWUSR,
1122 acpi_device_dir(device));
1123 if (!entry)
1124 return -ENODEV;
1125 else {
1126 entry->proc_fops = &acpi_thermal_cooling_fops;
1127 entry->data = acpi_driver_data(device);
1128 entry->owner = THIS_MODULE;
1131 /* 'polling_frequency' [R/W] */
1132 entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1133 S_IFREG | S_IRUGO | S_IWUSR,
1134 acpi_device_dir(device));
1135 if (!entry)
1136 return -ENODEV;
1137 else {
1138 entry->proc_fops = &acpi_thermal_polling_fops;
1139 entry->data = acpi_driver_data(device);
1140 entry->owner = THIS_MODULE;
1143 return 0;
1146 static int acpi_thermal_remove_fs(struct acpi_device *device)
1149 if (acpi_device_dir(device)) {
1150 remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1151 acpi_device_dir(device));
1152 remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1153 acpi_device_dir(device));
1154 remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1155 acpi_device_dir(device));
1156 remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1157 acpi_device_dir(device));
1158 remove_proc_entry(ACPI_THERMAL_FILE_STATE,
1159 acpi_device_dir(device));
1160 remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
1161 acpi_device_dir(device) = NULL;
1164 return 0;
1167 /* --------------------------------------------------------------------------
1168 Driver Interface
1169 -------------------------------------------------------------------------- */
1171 static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
1173 struct acpi_thermal *tz = (struct acpi_thermal *)data;
1174 struct acpi_device *device = NULL;
1177 if (!tz)
1178 return;
1180 device = tz->device;
1182 switch (event) {
1183 case ACPI_THERMAL_NOTIFY_TEMPERATURE:
1184 acpi_thermal_check(tz);
1185 break;
1186 case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1187 acpi_thermal_get_trip_points(tz);
1188 acpi_thermal_check(tz);
1189 acpi_bus_generate_event(device, event, 0);
1190 break;
1191 case ACPI_THERMAL_NOTIFY_DEVICES:
1192 if (tz->flags.devices)
1193 acpi_thermal_get_devices(tz);
1194 acpi_bus_generate_event(device, event, 0);
1195 break;
1196 default:
1197 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1198 "Unsupported event [0x%x]\n", event));
1199 break;
1202 return;
1205 static int acpi_thermal_get_info(struct acpi_thermal *tz)
1207 int result = 0;
1210 if (!tz)
1211 return -EINVAL;
1213 /* Get temperature [_TMP] (required) */
1214 result = acpi_thermal_get_temperature(tz);
1215 if (result)
1216 return result;
1218 /* Get trip points [_CRT, _PSV, etc.] (required) */
1219 result = acpi_thermal_get_trip_points(tz);
1220 if (result)
1221 return result;
1223 /* Set the cooling mode [_SCP] to active cooling (default) */
1224 result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1225 if (!result)
1226 tz->flags.cooling_mode = 1;
1227 else {
1228 /* Oh,we have not _SCP method.
1229 Generally show cooling_mode by _ACx, _PSV,spec 12.2 */
1230 tz->flags.cooling_mode = 0;
1231 if (tz->trips.active[0].flags.valid
1232 && tz->trips.passive.flags.valid) {
1233 if (tz->trips.passive.temperature >
1234 tz->trips.active[0].temperature)
1235 tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1236 else
1237 tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1238 } else if (!tz->trips.active[0].flags.valid
1239 && tz->trips.passive.flags.valid) {
1240 tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1241 } else if (tz->trips.active[0].flags.valid
1242 && !tz->trips.passive.flags.valid) {
1243 tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1244 } else {
1245 /* _ACx and _PSV are optional, but _CRT is required */
1246 tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL;
1250 /* Get default polling frequency [_TZP] (optional) */
1251 if (tzp)
1252 tz->polling_frequency = tzp;
1253 else
1254 acpi_thermal_get_polling_frequency(tz);
1256 /* Get devices in this thermal zone [_TZD] (optional) */
1257 result = acpi_thermal_get_devices(tz);
1258 if (!result)
1259 tz->flags.devices = 1;
1261 return 0;
1264 static int acpi_thermal_add(struct acpi_device *device)
1266 int result = 0;
1267 acpi_status status = AE_OK;
1268 struct acpi_thermal *tz = NULL;
1271 if (!device)
1272 return -EINVAL;
1274 tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1275 if (!tz)
1276 return -ENOMEM;
1277 memset(tz, 0, sizeof(struct acpi_thermal));
1279 tz->device = device;
1280 strcpy(tz->name, device->pnp.bus_id);
1281 strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1282 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1283 acpi_driver_data(device) = tz;
1285 result = acpi_thermal_get_info(tz);
1286 if (result)
1287 goto end;
1289 result = acpi_thermal_add_fs(device);
1290 if (result)
1291 goto end;
1293 init_timer(&tz->timer);
1295 acpi_thermal_check(tz);
1297 status = acpi_install_notify_handler(device->handle,
1298 ACPI_DEVICE_NOTIFY,
1299 acpi_thermal_notify, tz);
1300 if (ACPI_FAILURE(status)) {
1301 result = -ENODEV;
1302 goto end;
1305 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1306 acpi_device_name(device), acpi_device_bid(device),
1307 KELVIN_TO_CELSIUS(tz->temperature));
1309 end:
1310 if (result) {
1311 acpi_thermal_remove_fs(device);
1312 kfree(tz);
1315 return result;
1318 static int acpi_thermal_remove(struct acpi_device *device, int type)
1320 acpi_status status = AE_OK;
1321 struct acpi_thermal *tz = NULL;
1324 if (!device || !acpi_driver_data(device))
1325 return -EINVAL;
1327 tz = (struct acpi_thermal *)acpi_driver_data(device);
1329 /* avoid timer adding new defer task */
1330 tz->zombie = 1;
1331 /* wait for running timer (on other CPUs) finish */
1332 del_timer_sync(&(tz->timer));
1333 /* synchronize deferred task */
1334 acpi_os_wait_events_complete(NULL);
1335 /* deferred task may reinsert timer */
1336 del_timer_sync(&(tz->timer));
1338 status = acpi_remove_notify_handler(device->handle,
1339 ACPI_DEVICE_NOTIFY,
1340 acpi_thermal_notify);
1342 /* Terminate policy */
1343 if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
1344 tz->trips.passive.flags.enabled = 0;
1345 acpi_thermal_passive(tz);
1347 if (tz->trips.active[0].flags.valid
1348 && tz->trips.active[0].flags.enabled) {
1349 tz->trips.active[0].flags.enabled = 0;
1350 acpi_thermal_active(tz);
1353 acpi_thermal_remove_fs(device);
1355 kfree(tz);
1356 return 0;
1359 static int acpi_thermal_resume(struct acpi_device *device, int state)
1361 struct acpi_thermal *tz = NULL;
1362 int i;
1364 if (!device || !acpi_driver_data(device))
1365 return -EINVAL;
1367 tz = (struct acpi_thermal *)acpi_driver_data(device);
1369 acpi_thermal_get_temperature(tz);
1371 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1372 if (tz->trips.active[i].flags.valid) {
1373 tz->temperature = tz->trips.active[i].temperature;
1374 tz->trips.active[i].flags.enabled = 0;
1376 acpi_thermal_active(tz);
1378 tz->state.active |= tz->trips.active[i].flags.enabled;
1379 tz->state.active_index = i;
1383 acpi_thermal_check(tz);
1385 return AE_OK;
1388 static int __init acpi_thermal_init(void)
1390 int result = 0;
1393 acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
1394 if (!acpi_thermal_dir)
1395 return -ENODEV;
1396 acpi_thermal_dir->owner = THIS_MODULE;
1398 result = acpi_bus_register_driver(&acpi_thermal_driver);
1399 if (result < 0) {
1400 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1401 return -ENODEV;
1404 return 0;
1407 static void __exit acpi_thermal_exit(void)
1410 acpi_bus_unregister_driver(&acpi_thermal_driver);
1412 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1414 return;
1417 module_init(acpi_thermal_init);
1418 module_exit(acpi_thermal_exit);