diff options
Diffstat (limited to 'drivers/acpi/thermal.c')
| -rw-r--r-- | drivers/acpi/thermal.c | 338 |
1 files changed, 222 insertions, 116 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 5a27b0a3131..112817e963e 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -41,20 +41,15 @@ #include <linux/kmod.h> #include <linux/reboot.h> #include <linux/device.h> -#include <asm/uaccess.h> #include <linux/thermal.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> +#include <linux/workqueue.h> +#include <asm/uaccess.h> #define PREFIX "ACPI: " #define ACPI_THERMAL_CLASS "thermal_zone" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" -#define ACPI_THERMAL_FILE_STATE "state" -#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" -#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" -#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" -#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82 @@ -96,9 +91,10 @@ static int psv; module_param(psv, int, 0644); MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); +static struct workqueue_struct *acpi_thermal_pm_queue; + static int acpi_thermal_add(struct acpi_device *device); -static int acpi_thermal_remove(struct acpi_device *device, int type); -static int acpi_thermal_resume(struct acpi_device *device); +static int acpi_thermal_remove(struct acpi_device *device); static void acpi_thermal_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id thermal_device_ids[] = { @@ -107,6 +103,15 @@ static const struct acpi_device_id thermal_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, thermal_device_ids); +#ifdef CONFIG_PM_SLEEP +static int acpi_thermal_suspend(struct device *dev); +static int acpi_thermal_resume(struct device *dev); +#else +#define acpi_thermal_suspend NULL +#define acpi_thermal_resume NULL +#endif +static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume); + static struct acpi_driver acpi_thermal_driver = { .name = "thermal", .class = ACPI_THERMAL_CLASS, @@ -114,9 +119,9 @@ static struct acpi_driver acpi_thermal_driver = { .ops = { .add = acpi_thermal_add, .remove = acpi_thermal_remove, - .resume = acpi_thermal_resume, .notify = acpi_thermal_notify, }, + .drv.pm = &acpi_thermal_pm, }; struct acpi_thermal_state { @@ -186,7 +191,7 @@ struct acpi_thermal { struct thermal_zone_device *thermal_zone; int tz_enabled; int kelvin_offset; - struct mutex lock; + struct work_struct thermal_check_work; }; /* -------------------------------------------------------------------------- @@ -235,26 +240,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) { - acpi_status status = AE_OK; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg0 }; - acpi_handle handle = NULL; - - if (!tz) return -EINVAL; - status = acpi_get_handle(tz->device->handle, "_SCP", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(tz->device->handle, "_SCP")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); return -ENODEV; - } - - arg0.integer.value = mode; - - status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); - if (ACPI_FAILURE(status)) + } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle, + "_SCP", mode))) { return -ENODEV; + } return 0; } @@ -284,7 +279,7 @@ do { \ if (flags != ACPI_TRIPS_INIT) \ ACPI_EXCEPTION((AE_INFO, AE_ERROR, \ "ACPI thermal trip point %s changed\n" \ - "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \ + "Please send acpidump to linux-acpi@vger.kernel.org", str)); \ } while (0) static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) @@ -311,8 +306,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No critical threshold\n")); } else if (tmp <= 2732) { - printk(KERN_WARNING FW_BUG "Invalid critical threshold " - "(%llu)\n", tmp); + pr_warn(FW_BUG "Invalid critical threshold (%llu)\n", + tmp); tz->trips.critical.flags.valid = 0; } else { tz->trips.critical.flags.valid = 1; @@ -329,8 +324,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) * Allow override critical threshold */ if (crt_k > tz->trips.critical.temperature) - printk(KERN_WARNING PREFIX - "Critical threshold %d C\n", crt); + pr_warn(PREFIX "Critical threshold %d C\n", + crt); tz->trips.critical.temperature = crt_k; } } @@ -349,7 +344,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) tz->trips.hot.flags.valid = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", - tz->trips.critical.temperature)); + tz->trips.hot.temperature)); } } @@ -402,8 +397,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) status = acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, &devices); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING PREFIX - "Invalid passive threshold\n"); + pr_warn(PREFIX "Invalid passive threshold\n"); tz->trips.passive.flags.valid = 0; } else @@ -465,8 +459,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) status = acpi_evaluate_reference(tz->device->handle, name, NULL, &devices); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING PREFIX - "Invalid active%d threshold\n", i); + pr_warn(PREFIX "Invalid active%d threshold\n", + i); tz->trips.active[i].flags.valid = 0; } else @@ -487,14 +481,14 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; } - if (flag & ACPI_TRIPS_DEVICES) { - memset(&devices, 0, sizeof(struct acpi_handle_list)); + if ((flag & ACPI_TRIPS_DEVICES) + && acpi_has_method(tz->device->handle, "_TZD")) { + memset(&devices, 0, sizeof(devices)); status = acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &devices); - if (memcmp(&tz->devices, &devices, - sizeof(struct acpi_handle_list))) { - memcpy(&tz->devices, &devices, - sizeof(struct acpi_handle_list)); + if (ACPI_SUCCESS(status) + && memcmp(&tz->devices, &devices, sizeof(devices))) { + tz->devices = devices; ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); } } @@ -517,7 +511,7 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) valid |= tz->trips.active[i].flags.valid; if (!valid) { - printk(KERN_WARNING FW_BUG "No valid trip found\n"); + pr_warn(FW_BUG "No valid trip found\n"); return -ENODEV; } return 0; @@ -527,6 +521,9 @@ static void acpi_thermal_check(void *data) { struct acpi_thermal *tz = data; + if (!tz->tz_enabled) + return; + thermal_zone_device_update(tz->thermal_zone); } @@ -550,8 +547,6 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, return 0; } -static const char enabled[] = "kernel"; -static const char disabled[] = "user"; static int thermal_get_mode(struct thermal_zone_device *thermal, enum thermal_device_mode *mode) { @@ -580,16 +575,17 @@ static int thermal_set_mode(struct thermal_zone_device *thermal, */ if (mode == THERMAL_DEVICE_ENABLED) enable = 1; - else if (mode == THERMAL_DEVICE_DISABLED) + else if (mode == THERMAL_DEVICE_DISABLED) { enable = 0; - else + pr_warn("thermal zone will be disabled\n"); + } else return -EINVAL; if (enable != tz->tz_enabled) { tz->tz_enabled = enable; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "%s ACPI thermal control\n", - tz->tz_enabled ? enabled : disabled)); + "%s kernel ACPI thermal control\n", + tz->tz_enabled ? "Enable" : "Disable")); acpi_thermal_check(tz); } return 0; @@ -706,6 +702,50 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal, return -EINVAL; } +static int thermal_get_trend(struct thermal_zone_device *thermal, + int trip, enum thermal_trend *trend) +{ + struct acpi_thermal *tz = thermal->devdata; + enum thermal_trip_type type; + int i; + + if (thermal_get_trip_type(thermal, trip, &type)) + return -EINVAL; + + if (type == THERMAL_TRIP_ACTIVE) { + unsigned long trip_temp; + unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature, + tz->kelvin_offset); + if (thermal_get_trip_temp(thermal, trip, &trip_temp)) + return -EINVAL; + + if (temp > trip_temp) { + *trend = THERMAL_TREND_RAISING; + return 0; + } else { + /* Fall back on default trend */ + return -EINVAL; + } + } + + /* + * tz->temperature has already been updated by generic thermal layer, + * before this callback being invoked + */ + i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature)) + + (tz->trips.passive.tc2 + * (tz->temperature - tz->trips.passive.temperature)); + + if (i > 0) + *trend = THERMAL_TREND_RAISING; + else if (i < 0) + *trend = THERMAL_TREND_DROPPING; + else + *trend = THERMAL_TREND_STABLE; + return 0; +} + + static int thermal_notify(struct thermal_zone_device *thermal, int trip, enum thermal_trip_type trip_type) { @@ -719,7 +759,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip, else return 0; - acpi_bus_generate_proc_event(tz->device, type, 1); acpi_bus_generate_netlink_event(tz->device->pnp.device_class, dev_name(&tz->device->dev), type, 1); @@ -729,11 +768,9 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip, return 0; } -typedef int (*cb)(struct thermal_zone_device *, int, - struct thermal_cooling_device *); static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev, - cb action) + bool bind) { struct acpi_device *device = cdev->devdata; struct acpi_thermal *tz = thermal->devdata; @@ -757,11 +794,19 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, i++) { handle = tz->trips.passive.devices.handles[i]; status = acpi_bus_get_device(handle, &dev); - if (ACPI_SUCCESS(status) && (dev == device)) { - result = action(thermal, trip, cdev); - if (result) - goto failed; - } + if (ACPI_FAILURE(status) || dev != device) + continue; + if (bind) + result = + thermal_zone_bind_cooling_device + (thermal, trip, cdev, + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); + else + result = + thermal_zone_unbind_cooling_device + (thermal, trip, cdev); + if (result) + goto failed; } } @@ -774,11 +819,17 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, j++) { handle = tz->trips.active[i].devices.handles[j]; status = acpi_bus_get_device(handle, &dev); - if (ACPI_SUCCESS(status) && (dev == device)) { - result = action(thermal, trip, cdev); - if (result) - goto failed; - } + if (ACPI_FAILURE(status) || dev != device) + continue; + if (bind) + result = thermal_zone_bind_cooling_device + (thermal, trip, cdev, + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); + else + result = thermal_zone_unbind_cooling_device + (thermal, trip, cdev); + if (result) + goto failed; } } @@ -786,7 +837,15 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, handle = tz->devices.handles[i]; status = acpi_bus_get_device(handle, &dev); if (ACPI_SUCCESS(status) && (dev == device)) { - result = action(thermal, -1, cdev); + if (bind) + result = thermal_zone_bind_cooling_device + (thermal, THERMAL_TRIPS_NONE, + cdev, THERMAL_NO_LIMIT, + THERMAL_NO_LIMIT); + else + result = thermal_zone_unbind_cooling_device + (thermal, THERMAL_TRIPS_NONE, + cdev); if (result) goto failed; } @@ -800,16 +859,14 @@ static int acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { - return acpi_thermal_cooling_device_cb(thermal, cdev, - thermal_zone_bind_cooling_device); + return acpi_thermal_cooling_device_cb(thermal, cdev, true); } static int acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { - return acpi_thermal_cooling_device_cb(thermal, cdev, - thermal_zone_unbind_cooling_device); + return acpi_thermal_cooling_device_cb(thermal, cdev, false); } static struct thermal_zone_device_ops acpi_thermal_zone_ops = { @@ -821,6 +878,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .get_trip_type = thermal_get_trip_type, .get_trip_temp = thermal_get_trip_temp, .get_crit_temp = thermal_get_crit_temp, + .get_trend = thermal_get_trend, .notify = thermal_notify, }; @@ -845,18 +903,15 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (tz->trips.passive.flags.valid) tz->thermal_zone = - thermal_zone_device_register("acpitz", trips, tz, - &acpi_thermal_zone_ops, - tz->trips.passive.tc1, - tz->trips.passive.tc2, + thermal_zone_device_register("acpitz", trips, 0, tz, + &acpi_thermal_zone_ops, NULL, tz->trips.passive.tsp*100, tz->polling_frequency*100); else tz->thermal_zone = - thermal_zone_device_register("acpitz", trips, tz, - &acpi_thermal_zone_ops, - 0, 0, 0, - tz->polling_frequency*100); + thermal_zone_device_register("acpitz", trips, 0, tz, + &acpi_thermal_zone_ops, NULL, + 0, tz->polling_frequency*100); if (IS_ERR(tz->thermal_zone)) return -ENODEV; @@ -870,14 +925,10 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (result) return result; - status = acpi_attach_data(tz->device->handle, - acpi_bus_private_data_handler, - tz->thermal_zone); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Error attaching device data\n"); + status = acpi_bus_attach_private_data(tz->device->handle, + tz->thermal_zone); + if (ACPI_FAILURE(status)) return -ENODEV; - } tz->tz_enabled = 1; @@ -892,7 +943,7 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); thermal_zone_device_unregister(tz->thermal_zone); tz->thermal_zone = NULL; - acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); + acpi_bus_detach_private_data(tz->device->handle); } @@ -915,14 +966,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; @@ -933,6 +982,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) } } +/* + * On some platforms, the AML code has dependency about + * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx. + * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after + * /_CRT/_HOT/_PSV/_ACx, or else system will be power off. + * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0 + * if _TMP has never been evaluated. + * + * As this dependency is totally transparent to OS, evaluate + * all of them once, in the order of _CRT/_HOT/_PSV/_ACx, + * _TMP, before they are actually used. + */ +static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz) +{ + acpi_handle handle = tz->device->handle; + unsigned long long value; + int i; + + acpi_evaluate_integer(handle, "_CRT", NULL, &value); + acpi_evaluate_integer(handle, "_HOT", NULL, &value); + acpi_evaluate_integer(handle, "_PSV", NULL, &value); + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; + acpi_status status; + + status = acpi_evaluate_integer(handle, name, NULL, &value); + if (status == AE_NOT_FOUND) + break; + } + acpi_evaluate_integer(handle, "_TMP", NULL, &value); +} + static int acpi_thermal_get_info(struct acpi_thermal *tz) { int result = 0; @@ -941,16 +1022,18 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) if (!tz) return -EINVAL; - /* Get temperature [_TMP] (required) */ - result = acpi_thermal_get_temperature(tz); - if (result) - return result; + acpi_thermal_aml_dependency_fix(tz); /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) return result; + /* Get temperature [_TMP] (required) */ + result = acpi_thermal_get_temperature(tz); + if (result) + return result; + /* Set the cooling mode [_SCP] to active cooling (default) */ result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); if (!result) @@ -984,6 +1067,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz) tz->kelvin_offset = 2732; } +static void acpi_thermal_check_fn(struct work_struct *work) +{ + struct acpi_thermal *tz = container_of(work, struct acpi_thermal, + thermal_check_work); + acpi_thermal_check(tz); +} + static int acpi_thermal_add(struct acpi_device *device) { int result = 0; @@ -1002,8 +1092,6 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); device->driver_data = tz; - mutex_init(&tz->lock); - result = acpi_thermal_get_info(tz); if (result) @@ -1015,9 +1103,10 @@ static int acpi_thermal_add(struct acpi_device *device) if (result) goto free_memory; - printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", - acpi_device_name(device), acpi_device_bid(device), - KELVIN_TO_CELSIUS(tz->temperature)); + INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); + + pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), + acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); goto end; free_memory: @@ -1026,31 +1115,40 @@ end: return result; } -static int acpi_thermal_remove(struct acpi_device *device, int type) +static int acpi_thermal_remove(struct acpi_device *device) { struct acpi_thermal *tz = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; + flush_workqueue(acpi_thermal_pm_queue); tz = acpi_driver_data(device); acpi_thermal_unregister_thermal_zone(tz); - mutex_destroy(&tz->lock); kfree(tz); return 0; } -static int acpi_thermal_resume(struct acpi_device *device) +#ifdef CONFIG_PM_SLEEP +static int acpi_thermal_suspend(struct device *dev) { - struct acpi_thermal *tz = NULL; - int i, j, power_state, result; + /* Make sure the previously queued thermal check work has been done */ + flush_workqueue(acpi_thermal_pm_queue); + return 0; +} +static int acpi_thermal_resume(struct device *dev) +{ + struct acpi_thermal *tz; + int i, j, power_state, result; - if (!device || !acpi_driver_data(device)) + if (!dev) return -EINVAL; - tz = acpi_driver_data(device); + tz = acpi_driver_data(to_acpi_device(dev)); + if (!tz) + return -EINVAL; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { if (!(&tz->trips.active[i])) @@ -1059,8 +1157,9 @@ static int acpi_thermal_resume(struct acpi_device *device) break; tz->trips.active[i].flags.enabled = 1; for (j = 0; j < tz->trips.active[i].devices.count; j++) { - result = acpi_bus_get_power(tz->trips.active[i].devices. - handles[j], &power_state); + result = acpi_bus_update_power( + tz->trips.active[i].devices.handles[j], + &power_state); if (result || (power_state != ACPI_STATE_D0)) { tz->trips.active[i].flags.enabled = 0; break; @@ -1069,32 +1168,33 @@ static int acpi_thermal_resume(struct acpi_device *device) tz->state.active |= tz->trips.active[i].flags.enabled; } - acpi_thermal_check(tz); + queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); return AE_OK; } +#endif static int thermal_act(const struct dmi_system_id *d) { if (act == 0) { - printk(KERN_NOTICE "ACPI: %s detected: " - "disabling all active thermal trip points\n", d->ident); + pr_notice(PREFIX "%s detected: " + "disabling all active thermal trip points\n", d->ident); act = -1; } return 0; } static int thermal_nocrt(const struct dmi_system_id *d) { - printk(KERN_NOTICE "ACPI: %s detected: " - "disabling all critical thermal trip point actions.\n", d->ident); + pr_notice(PREFIX "%s detected: " + "disabling all critical thermal trip point actions.\n", d->ident); nocrt = 1; return 0; } static int thermal_tzp(const struct dmi_system_id *d) { if (tzp == 0) { - printk(KERN_NOTICE "ACPI: %s detected: " - "enabling thermal zone polling\n", d->ident); + pr_notice(PREFIX "%s detected: " + "enabling thermal zone polling\n", d->ident); tzp = 300; /* 300 dS = 30 Seconds */ } return 0; @@ -1102,8 +1202,8 @@ static int thermal_tzp(const struct dmi_system_id *d) { static int thermal_psv(const struct dmi_system_id *d) { if (psv == 0) { - printk(KERN_NOTICE "ACPI: %s detected: " - "disabling all passive thermal trip points\n", d->ident); + pr_notice(PREFIX "%s detected: " + "disabling all passive thermal trip points\n", d->ident); psv = -1; } return 0; @@ -1156,21 +1256,27 @@ static int __init acpi_thermal_init(void) dmi_check_system(thermal_dmi_table); if (off) { - printk(KERN_NOTICE "ACPI: thermal control disabled\n"); + pr_notice(PREFIX "thermal control disabled\n"); return -ENODEV; } + acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm"); + if (!acpi_thermal_pm_queue) + return -ENODEV; + result = acpi_bus_register_driver(&acpi_thermal_driver); - if (result < 0) + if (result < 0) { + destroy_workqueue(acpi_thermal_pm_queue); return -ENODEV; + } return 0; } static void __exit acpi_thermal_exit(void) { - acpi_bus_unregister_driver(&acpi_thermal_driver); + destroy_workqueue(acpi_thermal_pm_queue); return; } |
