0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #define pr_fmt(fmt) "ACPI: thermal: " fmt
0017
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <linux/dmi.h>
0021 #include <linux/init.h>
0022 #include <linux/slab.h>
0023 #include <linux/types.h>
0024 #include <linux/jiffies.h>
0025 #include <linux/kmod.h>
0026 #include <linux/reboot.h>
0027 #include <linux/device.h>
0028 #include <linux/thermal.h>
0029 #include <linux/acpi.h>
0030 #include <linux/workqueue.h>
0031 #include <linux/uaccess.h>
0032 #include <linux/units.h>
0033
0034 #define ACPI_THERMAL_CLASS "thermal_zone"
0035 #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
0036 #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
0037 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
0038 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
0039 #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
0040 #define ACPI_THERMAL_NOTIFY_HOT 0xF1
0041 #define ACPI_THERMAL_MODE_ACTIVE 0x00
0042
0043 #define ACPI_THERMAL_MAX_ACTIVE 10
0044 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
0045
0046 MODULE_AUTHOR("Paul Diefenbaugh");
0047 MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
0048 MODULE_LICENSE("GPL");
0049
0050 static int act;
0051 module_param(act, int, 0644);
0052 MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
0053
0054 static int crt;
0055 module_param(crt, int, 0644);
0056 MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
0057
0058 static int tzp;
0059 module_param(tzp, int, 0444);
0060 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
0061
0062 static int nocrt;
0063 module_param(nocrt, int, 0);
0064 MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
0065
0066 static int off;
0067 module_param(off, int, 0);
0068 MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
0069
0070 static int psv;
0071 module_param(psv, int, 0644);
0072 MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
0073
0074 static struct workqueue_struct *acpi_thermal_pm_queue;
0075
0076 static int acpi_thermal_add(struct acpi_device *device);
0077 static int acpi_thermal_remove(struct acpi_device *device);
0078 static void acpi_thermal_notify(struct acpi_device *device, u32 event);
0079
0080 static const struct acpi_device_id thermal_device_ids[] = {
0081 {ACPI_THERMAL_HID, 0},
0082 {"", 0},
0083 };
0084 MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
0085
0086 #ifdef CONFIG_PM_SLEEP
0087 static int acpi_thermal_suspend(struct device *dev);
0088 static int acpi_thermal_resume(struct device *dev);
0089 #else
0090 #define acpi_thermal_suspend NULL
0091 #define acpi_thermal_resume NULL
0092 #endif
0093 static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
0094
0095 static struct acpi_driver acpi_thermal_driver = {
0096 .name = "thermal",
0097 .class = ACPI_THERMAL_CLASS,
0098 .ids = thermal_device_ids,
0099 .ops = {
0100 .add = acpi_thermal_add,
0101 .remove = acpi_thermal_remove,
0102 .notify = acpi_thermal_notify,
0103 },
0104 .drv.pm = &acpi_thermal_pm,
0105 };
0106
0107 struct acpi_thermal_state {
0108 u8 critical:1;
0109 u8 hot:1;
0110 u8 passive:1;
0111 u8 active:1;
0112 u8 reserved:4;
0113 int active_index;
0114 };
0115
0116 struct acpi_thermal_state_flags {
0117 u8 valid:1;
0118 u8 enabled:1;
0119 u8 reserved:6;
0120 };
0121
0122 struct acpi_thermal_critical {
0123 struct acpi_thermal_state_flags flags;
0124 unsigned long temperature;
0125 };
0126
0127 struct acpi_thermal_hot {
0128 struct acpi_thermal_state_flags flags;
0129 unsigned long temperature;
0130 };
0131
0132 struct acpi_thermal_passive {
0133 struct acpi_thermal_state_flags flags;
0134 unsigned long temperature;
0135 unsigned long tc1;
0136 unsigned long tc2;
0137 unsigned long tsp;
0138 struct acpi_handle_list devices;
0139 };
0140
0141 struct acpi_thermal_active {
0142 struct acpi_thermal_state_flags flags;
0143 unsigned long temperature;
0144 struct acpi_handle_list devices;
0145 };
0146
0147 struct acpi_thermal_trips {
0148 struct acpi_thermal_critical critical;
0149 struct acpi_thermal_hot hot;
0150 struct acpi_thermal_passive passive;
0151 struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
0152 };
0153
0154 struct acpi_thermal_flags {
0155 u8 cooling_mode:1;
0156 u8 devices:1;
0157 u8 reserved:6;
0158 };
0159
0160 struct acpi_thermal {
0161 struct acpi_device * device;
0162 acpi_bus_id name;
0163 unsigned long temperature;
0164 unsigned long last_temperature;
0165 unsigned long polling_frequency;
0166 volatile u8 zombie;
0167 struct acpi_thermal_flags flags;
0168 struct acpi_thermal_state state;
0169 struct acpi_thermal_trips trips;
0170 struct acpi_handle_list devices;
0171 struct thermal_zone_device *thermal_zone;
0172 int kelvin_offset;
0173 struct work_struct thermal_check_work;
0174 struct mutex thermal_check_lock;
0175 refcount_t thermal_check_count;
0176 };
0177
0178
0179
0180
0181
0182 static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
0183 {
0184 acpi_status status = AE_OK;
0185 unsigned long long tmp;
0186
0187 if (!tz)
0188 return -EINVAL;
0189
0190 tz->last_temperature = tz->temperature;
0191
0192 status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
0193 if (ACPI_FAILURE(status))
0194 return -ENODEV;
0195
0196 tz->temperature = tmp;
0197
0198 acpi_handle_debug(tz->device->handle, "Temperature is %lu dK\n",
0199 tz->temperature);
0200
0201 return 0;
0202 }
0203
0204 static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
0205 {
0206 acpi_status status = AE_OK;
0207 unsigned long long tmp;
0208
0209 if (!tz)
0210 return -EINVAL;
0211
0212 status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
0213 if (ACPI_FAILURE(status))
0214 return -ENODEV;
0215
0216 tz->polling_frequency = tmp;
0217 acpi_handle_debug(tz->device->handle, "Polling frequency is %lu dS\n",
0218 tz->polling_frequency);
0219
0220 return 0;
0221 }
0222
0223 static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
0224 {
0225 if (!tz)
0226 return -EINVAL;
0227
0228 if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
0229 "_SCP", mode)))
0230 return -ENODEV;
0231
0232 return 0;
0233 }
0234
0235 #define ACPI_TRIPS_CRITICAL 0x01
0236 #define ACPI_TRIPS_HOT 0x02
0237 #define ACPI_TRIPS_PASSIVE 0x04
0238 #define ACPI_TRIPS_ACTIVE 0x08
0239 #define ACPI_TRIPS_DEVICES 0x10
0240
0241 #define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
0242 #define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
0243
0244 #define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
0245 ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
0246 ACPI_TRIPS_DEVICES)
0247
0248
0249
0250
0251
0252
0253
0254
0255 #define ACPI_THERMAL_TRIPS_EXCEPTION(flags, tz, str) \
0256 do { \
0257 if (flags != ACPI_TRIPS_INIT) \
0258 acpi_handle_info(tz->device->handle, \
0259 "ACPI thermal trip point %s changed\n" \
0260 "Please report to linux-acpi@vger.kernel.org\n", str); \
0261 } while (0)
0262
0263 static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
0264 {
0265 acpi_status status = AE_OK;
0266 unsigned long long tmp;
0267 struct acpi_handle_list devices;
0268 int valid = 0;
0269 int i;
0270
0271
0272 if (flag & ACPI_TRIPS_CRITICAL) {
0273 status = acpi_evaluate_integer(tz->device->handle,
0274 "_CRT", NULL, &tmp);
0275 tz->trips.critical.temperature = tmp;
0276
0277
0278
0279
0280
0281
0282 if (ACPI_FAILURE(status)) {
0283 tz->trips.critical.flags.valid = 0;
0284 acpi_handle_debug(tz->device->handle,
0285 "No critical threshold\n");
0286 } else if (tmp <= 2732) {
0287 pr_info(FW_BUG "Invalid critical threshold (%llu)\n",
0288 tmp);
0289 tz->trips.critical.flags.valid = 0;
0290 } else {
0291 tz->trips.critical.flags.valid = 1;
0292 acpi_handle_debug(tz->device->handle,
0293 "Found critical threshold [%lu]\n",
0294 tz->trips.critical.temperature);
0295 }
0296 if (tz->trips.critical.flags.valid == 1) {
0297 if (crt == -1) {
0298 tz->trips.critical.flags.valid = 0;
0299 } else if (crt > 0) {
0300 unsigned long crt_k = celsius_to_deci_kelvin(crt);
0301
0302
0303
0304
0305 if (crt_k > tz->trips.critical.temperature)
0306 pr_info("Critical threshold %d C\n", crt);
0307
0308 tz->trips.critical.temperature = crt_k;
0309 }
0310 }
0311 }
0312
0313
0314 if (flag & ACPI_TRIPS_HOT) {
0315 status = acpi_evaluate_integer(tz->device->handle,
0316 "_HOT", NULL, &tmp);
0317 if (ACPI_FAILURE(status)) {
0318 tz->trips.hot.flags.valid = 0;
0319 acpi_handle_debug(tz->device->handle,
0320 "No hot threshold\n");
0321 } else {
0322 tz->trips.hot.temperature = tmp;
0323 tz->trips.hot.flags.valid = 1;
0324 acpi_handle_debug(tz->device->handle,
0325 "Found hot threshold [%lu]\n",
0326 tz->trips.hot.temperature);
0327 }
0328 }
0329
0330
0331 if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
0332 (flag == ACPI_TRIPS_INIT)) {
0333 valid = tz->trips.passive.flags.valid;
0334 if (psv == -1) {
0335 status = AE_SUPPORT;
0336 } else if (psv > 0) {
0337 tmp = celsius_to_deci_kelvin(psv);
0338 status = AE_OK;
0339 } else {
0340 status = acpi_evaluate_integer(tz->device->handle,
0341 "_PSV", NULL, &tmp);
0342 }
0343
0344 if (ACPI_FAILURE(status))
0345 tz->trips.passive.flags.valid = 0;
0346 else {
0347 tz->trips.passive.temperature = tmp;
0348 tz->trips.passive.flags.valid = 1;
0349 if (flag == ACPI_TRIPS_INIT) {
0350 status = acpi_evaluate_integer(
0351 tz->device->handle, "_TC1",
0352 NULL, &tmp);
0353 if (ACPI_FAILURE(status))
0354 tz->trips.passive.flags.valid = 0;
0355 else
0356 tz->trips.passive.tc1 = tmp;
0357 status = acpi_evaluate_integer(
0358 tz->device->handle, "_TC2",
0359 NULL, &tmp);
0360 if (ACPI_FAILURE(status))
0361 tz->trips.passive.flags.valid = 0;
0362 else
0363 tz->trips.passive.tc2 = tmp;
0364 status = acpi_evaluate_integer(
0365 tz->device->handle, "_TSP",
0366 NULL, &tmp);
0367 if (ACPI_FAILURE(status))
0368 tz->trips.passive.flags.valid = 0;
0369 else
0370 tz->trips.passive.tsp = tmp;
0371 }
0372 }
0373 }
0374 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
0375 memset(&devices, 0, sizeof(struct acpi_handle_list));
0376 status = acpi_evaluate_reference(tz->device->handle, "_PSL",
0377 NULL, &devices);
0378 if (ACPI_FAILURE(status)) {
0379 acpi_handle_info(tz->device->handle,
0380 "Invalid passive threshold\n");
0381 tz->trips.passive.flags.valid = 0;
0382 }
0383 else
0384 tz->trips.passive.flags.valid = 1;
0385
0386 if (memcmp(&tz->trips.passive.devices, &devices,
0387 sizeof(struct acpi_handle_list))) {
0388 memcpy(&tz->trips.passive.devices, &devices,
0389 sizeof(struct acpi_handle_list));
0390 ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device");
0391 }
0392 }
0393 if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
0394 if (valid != tz->trips.passive.flags.valid)
0395 ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
0396 }
0397
0398
0399 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
0400 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
0401 valid = tz->trips.active[i].flags.valid;
0402
0403 if (act == -1)
0404 break;
0405
0406 if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
0407 tz->trips.active[i].flags.valid)) {
0408 status = acpi_evaluate_integer(tz->device->handle,
0409 name, NULL, &tmp);
0410 if (ACPI_FAILURE(status)) {
0411 tz->trips.active[i].flags.valid = 0;
0412 if (i == 0)
0413 break;
0414 if (act <= 0)
0415 break;
0416 if (i == 1)
0417 tz->trips.active[0].temperature =
0418 celsius_to_deci_kelvin(act);
0419 else
0420
0421
0422
0423
0424 tz->trips.active[i - 1].temperature =
0425 (tz->trips.active[i - 2].temperature <
0426 celsius_to_deci_kelvin(act) ?
0427 tz->trips.active[i - 2].temperature :
0428 celsius_to_deci_kelvin(act));
0429 break;
0430 } else {
0431 tz->trips.active[i].temperature = tmp;
0432 tz->trips.active[i].flags.valid = 1;
0433 }
0434 }
0435
0436 name[2] = 'L';
0437 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
0438 memset(&devices, 0, sizeof(struct acpi_handle_list));
0439 status = acpi_evaluate_reference(tz->device->handle,
0440 name, NULL, &devices);
0441 if (ACPI_FAILURE(status)) {
0442 acpi_handle_info(tz->device->handle,
0443 "Invalid active%d threshold\n", i);
0444 tz->trips.active[i].flags.valid = 0;
0445 }
0446 else
0447 tz->trips.active[i].flags.valid = 1;
0448
0449 if (memcmp(&tz->trips.active[i].devices, &devices,
0450 sizeof(struct acpi_handle_list))) {
0451 memcpy(&tz->trips.active[i].devices, &devices,
0452 sizeof(struct acpi_handle_list));
0453 ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device");
0454 }
0455 }
0456 if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
0457 if (valid != tz->trips.active[i].flags.valid)
0458 ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
0459
0460 if (!tz->trips.active[i].flags.valid)
0461 break;
0462 }
0463
0464 if (flag & ACPI_TRIPS_DEVICES) {
0465 memset(&devices, 0, sizeof(devices));
0466 status = acpi_evaluate_reference(tz->device->handle, "_TZD",
0467 NULL, &devices);
0468 if (ACPI_SUCCESS(status)
0469 && memcmp(&tz->devices, &devices, sizeof(devices))) {
0470 tz->devices = devices;
0471 ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device");
0472 }
0473 }
0474
0475 return 0;
0476 }
0477
0478 static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
0479 {
0480 int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
0481
0482 if (ret)
0483 return ret;
0484
0485 valid = tz->trips.critical.flags.valid |
0486 tz->trips.hot.flags.valid |
0487 tz->trips.passive.flags.valid;
0488
0489 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
0490 valid |= tz->trips.active[i].flags.valid;
0491
0492 if (!valid) {
0493 pr_warn(FW_BUG "No valid trip found\n");
0494 return -ENODEV;
0495 }
0496 return 0;
0497 }
0498
0499
0500
0501 static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
0502 {
0503 struct acpi_thermal *tz = thermal->devdata;
0504 int result;
0505
0506 if (!tz)
0507 return -EINVAL;
0508
0509 result = acpi_thermal_get_temperature(tz);
0510 if (result)
0511 return result;
0512
0513 *temp = deci_kelvin_to_millicelsius_with_offset(tz->temperature,
0514 tz->kelvin_offset);
0515 return 0;
0516 }
0517
0518 static int thermal_get_trip_type(struct thermal_zone_device *thermal,
0519 int trip, enum thermal_trip_type *type)
0520 {
0521 struct acpi_thermal *tz = thermal->devdata;
0522 int i;
0523
0524 if (!tz || trip < 0)
0525 return -EINVAL;
0526
0527 if (tz->trips.critical.flags.valid) {
0528 if (!trip) {
0529 *type = THERMAL_TRIP_CRITICAL;
0530 return 0;
0531 }
0532 trip--;
0533 }
0534
0535 if (tz->trips.hot.flags.valid) {
0536 if (!trip) {
0537 *type = THERMAL_TRIP_HOT;
0538 return 0;
0539 }
0540 trip--;
0541 }
0542
0543 if (tz->trips.passive.flags.valid) {
0544 if (!trip) {
0545 *type = THERMAL_TRIP_PASSIVE;
0546 return 0;
0547 }
0548 trip--;
0549 }
0550
0551 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
0552 tz->trips.active[i].flags.valid; i++) {
0553 if (!trip) {
0554 *type = THERMAL_TRIP_ACTIVE;
0555 return 0;
0556 }
0557 trip--;
0558 }
0559
0560 return -EINVAL;
0561 }
0562
0563 static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
0564 int trip, int *temp)
0565 {
0566 struct acpi_thermal *tz = thermal->devdata;
0567 int i;
0568
0569 if (!tz || trip < 0)
0570 return -EINVAL;
0571
0572 if (tz->trips.critical.flags.valid) {
0573 if (!trip) {
0574 *temp = deci_kelvin_to_millicelsius_with_offset(
0575 tz->trips.critical.temperature,
0576 tz->kelvin_offset);
0577 return 0;
0578 }
0579 trip--;
0580 }
0581
0582 if (tz->trips.hot.flags.valid) {
0583 if (!trip) {
0584 *temp = deci_kelvin_to_millicelsius_with_offset(
0585 tz->trips.hot.temperature,
0586 tz->kelvin_offset);
0587 return 0;
0588 }
0589 trip--;
0590 }
0591
0592 if (tz->trips.passive.flags.valid) {
0593 if (!trip) {
0594 *temp = deci_kelvin_to_millicelsius_with_offset(
0595 tz->trips.passive.temperature,
0596 tz->kelvin_offset);
0597 return 0;
0598 }
0599 trip--;
0600 }
0601
0602 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
0603 tz->trips.active[i].flags.valid; i++) {
0604 if (!trip) {
0605 *temp = deci_kelvin_to_millicelsius_with_offset(
0606 tz->trips.active[i].temperature,
0607 tz->kelvin_offset);
0608 return 0;
0609 }
0610 trip--;
0611 }
0612
0613 return -EINVAL;
0614 }
0615
0616 static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
0617 int *temperature)
0618 {
0619 struct acpi_thermal *tz = thermal->devdata;
0620
0621 if (tz->trips.critical.flags.valid) {
0622 *temperature = deci_kelvin_to_millicelsius_with_offset(
0623 tz->trips.critical.temperature,
0624 tz->kelvin_offset);
0625 return 0;
0626 } else
0627 return -EINVAL;
0628 }
0629
0630 static int thermal_get_trend(struct thermal_zone_device *thermal,
0631 int trip, enum thermal_trend *trend)
0632 {
0633 struct acpi_thermal *tz = thermal->devdata;
0634 enum thermal_trip_type type;
0635 int i;
0636
0637 if (thermal_get_trip_type(thermal, trip, &type))
0638 return -EINVAL;
0639
0640 if (type == THERMAL_TRIP_ACTIVE) {
0641 int trip_temp;
0642 int temp = deci_kelvin_to_millicelsius_with_offset(
0643 tz->temperature, tz->kelvin_offset);
0644 if (thermal_get_trip_temp(thermal, trip, &trip_temp))
0645 return -EINVAL;
0646
0647 if (temp > trip_temp) {
0648 *trend = THERMAL_TREND_RAISING;
0649 return 0;
0650 } else {
0651
0652 return -EINVAL;
0653 }
0654 }
0655
0656
0657
0658
0659
0660 i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
0661 + (tz->trips.passive.tc2
0662 * (tz->temperature - tz->trips.passive.temperature));
0663
0664 if (i > 0)
0665 *trend = THERMAL_TREND_RAISING;
0666 else if (i < 0)
0667 *trend = THERMAL_TREND_DROPPING;
0668 else
0669 *trend = THERMAL_TREND_STABLE;
0670 return 0;
0671 }
0672
0673 static void acpi_thermal_zone_device_hot(struct thermal_zone_device *thermal)
0674 {
0675 struct acpi_thermal *tz = thermal->devdata;
0676
0677 acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
0678 dev_name(&tz->device->dev),
0679 ACPI_THERMAL_NOTIFY_HOT, 1);
0680 }
0681
0682 static void acpi_thermal_zone_device_critical(struct thermal_zone_device *thermal)
0683 {
0684 struct acpi_thermal *tz = thermal->devdata;
0685
0686 acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
0687 dev_name(&tz->device->dev),
0688 ACPI_THERMAL_NOTIFY_CRITICAL, 1);
0689
0690 thermal_zone_device_critical(thermal);
0691 }
0692
0693 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
0694 struct thermal_cooling_device *cdev,
0695 bool bind)
0696 {
0697 struct acpi_device *device = cdev->devdata;
0698 struct acpi_thermal *tz = thermal->devdata;
0699 struct acpi_device *dev;
0700 acpi_handle handle;
0701 int i;
0702 int j;
0703 int trip = -1;
0704 int result = 0;
0705
0706 if (tz->trips.critical.flags.valid)
0707 trip++;
0708
0709 if (tz->trips.hot.flags.valid)
0710 trip++;
0711
0712 if (tz->trips.passive.flags.valid) {
0713 trip++;
0714 for (i = 0; i < tz->trips.passive.devices.count;
0715 i++) {
0716 handle = tz->trips.passive.devices.handles[i];
0717 dev = acpi_fetch_acpi_dev(handle);
0718 if (dev != device)
0719 continue;
0720 if (bind)
0721 result =
0722 thermal_zone_bind_cooling_device
0723 (thermal, trip, cdev,
0724 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
0725 THERMAL_WEIGHT_DEFAULT);
0726 else
0727 result =
0728 thermal_zone_unbind_cooling_device
0729 (thermal, trip, cdev);
0730 if (result)
0731 goto failed;
0732 }
0733 }
0734
0735 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
0736 if (!tz->trips.active[i].flags.valid)
0737 break;
0738 trip++;
0739 for (j = 0;
0740 j < tz->trips.active[i].devices.count;
0741 j++) {
0742 handle = tz->trips.active[i].devices.handles[j];
0743 dev = acpi_fetch_acpi_dev(handle);
0744 if (dev != device)
0745 continue;
0746 if (bind)
0747 result = thermal_zone_bind_cooling_device
0748 (thermal, trip, cdev,
0749 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
0750 THERMAL_WEIGHT_DEFAULT);
0751 else
0752 result = thermal_zone_unbind_cooling_device
0753 (thermal, trip, cdev);
0754 if (result)
0755 goto failed;
0756 }
0757 }
0758
0759 failed:
0760 return result;
0761 }
0762
0763 static int
0764 acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
0765 struct thermal_cooling_device *cdev)
0766 {
0767 return acpi_thermal_cooling_device_cb(thermal, cdev, true);
0768 }
0769
0770 static int
0771 acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
0772 struct thermal_cooling_device *cdev)
0773 {
0774 return acpi_thermal_cooling_device_cb(thermal, cdev, false);
0775 }
0776
0777 static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
0778 .bind = acpi_thermal_bind_cooling_device,
0779 .unbind = acpi_thermal_unbind_cooling_device,
0780 .get_temp = thermal_get_temp,
0781 .get_trip_type = thermal_get_trip_type,
0782 .get_trip_temp = thermal_get_trip_temp,
0783 .get_crit_temp = thermal_get_crit_temp,
0784 .get_trend = thermal_get_trend,
0785 .hot = acpi_thermal_zone_device_hot,
0786 .critical = acpi_thermal_zone_device_critical,
0787 };
0788
0789 static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
0790 {
0791 int trips = 0;
0792 int result;
0793 acpi_status status;
0794 int i;
0795
0796 if (tz->trips.critical.flags.valid)
0797 trips++;
0798
0799 if (tz->trips.hot.flags.valid)
0800 trips++;
0801
0802 if (tz->trips.passive.flags.valid)
0803 trips++;
0804
0805 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
0806 tz->trips.active[i].flags.valid; i++, trips++);
0807
0808 if (tz->trips.passive.flags.valid)
0809 tz->thermal_zone =
0810 thermal_zone_device_register("acpitz", trips, 0, tz,
0811 &acpi_thermal_zone_ops, NULL,
0812 tz->trips.passive.tsp*100,
0813 tz->polling_frequency*100);
0814 else
0815 tz->thermal_zone =
0816 thermal_zone_device_register("acpitz", trips, 0, tz,
0817 &acpi_thermal_zone_ops, NULL,
0818 0, tz->polling_frequency*100);
0819 if (IS_ERR(tz->thermal_zone))
0820 return -ENODEV;
0821
0822 result = sysfs_create_link(&tz->device->dev.kobj,
0823 &tz->thermal_zone->device.kobj, "thermal_zone");
0824 if (result)
0825 goto unregister_tzd;
0826
0827 result = sysfs_create_link(&tz->thermal_zone->device.kobj,
0828 &tz->device->dev.kobj, "device");
0829 if (result)
0830 goto remove_tz_link;
0831
0832 status = acpi_bus_attach_private_data(tz->device->handle,
0833 tz->thermal_zone);
0834 if (ACPI_FAILURE(status)) {
0835 result = -ENODEV;
0836 goto remove_dev_link;
0837 }
0838
0839 result = thermal_zone_device_enable(tz->thermal_zone);
0840 if (result)
0841 goto acpi_bus_detach;
0842
0843 dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
0844 tz->thermal_zone->id);
0845
0846 return 0;
0847
0848 acpi_bus_detach:
0849 acpi_bus_detach_private_data(tz->device->handle);
0850 remove_dev_link:
0851 sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
0852 remove_tz_link:
0853 sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
0854 unregister_tzd:
0855 thermal_zone_device_unregister(tz->thermal_zone);
0856
0857 return result;
0858 }
0859
0860 static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
0861 {
0862 sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
0863 sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
0864 thermal_zone_device_unregister(tz->thermal_zone);
0865 tz->thermal_zone = NULL;
0866 acpi_bus_detach_private_data(tz->device->handle);
0867 }
0868
0869
0870
0871
0872
0873
0874 static void acpi_queue_thermal_check(struct acpi_thermal *tz)
0875 {
0876 if (!work_pending(&tz->thermal_check_work))
0877 queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
0878 }
0879
0880 static void acpi_thermal_notify(struct acpi_device *device, u32 event)
0881 {
0882 struct acpi_thermal *tz = acpi_driver_data(device);
0883
0884
0885 if (!tz)
0886 return;
0887
0888 switch (event) {
0889 case ACPI_THERMAL_NOTIFY_TEMPERATURE:
0890 acpi_queue_thermal_check(tz);
0891 break;
0892 case ACPI_THERMAL_NOTIFY_THRESHOLDS:
0893 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
0894 acpi_queue_thermal_check(tz);
0895 acpi_bus_generate_netlink_event(device->pnp.device_class,
0896 dev_name(&device->dev), event, 0);
0897 break;
0898 case ACPI_THERMAL_NOTIFY_DEVICES:
0899 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
0900 acpi_queue_thermal_check(tz);
0901 acpi_bus_generate_netlink_event(device->pnp.device_class,
0902 dev_name(&device->dev), event, 0);
0903 break;
0904 default:
0905 acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
0906 event);
0907 break;
0908 }
0909 }
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923 static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
0924 {
0925 acpi_handle handle = tz->device->handle;
0926 unsigned long long value;
0927 int i;
0928
0929 acpi_evaluate_integer(handle, "_CRT", NULL, &value);
0930 acpi_evaluate_integer(handle, "_HOT", NULL, &value);
0931 acpi_evaluate_integer(handle, "_PSV", NULL, &value);
0932 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
0933 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
0934 acpi_status status;
0935
0936 status = acpi_evaluate_integer(handle, name, NULL, &value);
0937 if (status == AE_NOT_FOUND)
0938 break;
0939 }
0940 acpi_evaluate_integer(handle, "_TMP", NULL, &value);
0941 }
0942
0943 static int acpi_thermal_get_info(struct acpi_thermal *tz)
0944 {
0945 int result = 0;
0946
0947
0948 if (!tz)
0949 return -EINVAL;
0950
0951 acpi_thermal_aml_dependency_fix(tz);
0952
0953
0954 result = acpi_thermal_get_trip_points(tz);
0955 if (result)
0956 return result;
0957
0958
0959 result = acpi_thermal_get_temperature(tz);
0960 if (result)
0961 return result;
0962
0963
0964 result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
0965 if (!result)
0966 tz->flags.cooling_mode = 1;
0967
0968
0969 if (tzp)
0970 tz->polling_frequency = tzp;
0971 else
0972 acpi_thermal_get_polling_frequency(tz);
0973
0974 return 0;
0975 }
0976
0977
0978
0979
0980
0981
0982
0983
0984
0985
0986
0987 static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
0988 {
0989 if (tz->trips.critical.flags.valid &&
0990 (tz->trips.critical.temperature % 5) == 1)
0991 tz->kelvin_offset = 273100;
0992 else
0993 tz->kelvin_offset = 273200;
0994 }
0995
0996 static void acpi_thermal_check_fn(struct work_struct *work)
0997 {
0998 struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
0999 thermal_check_work);
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009 if (!refcount_dec_not_one(&tz->thermal_check_count))
1010 return;
1011
1012 mutex_lock(&tz->thermal_check_lock);
1013
1014 thermal_zone_device_update(tz->thermal_zone, THERMAL_EVENT_UNSPECIFIED);
1015
1016 refcount_inc(&tz->thermal_check_count);
1017
1018 mutex_unlock(&tz->thermal_check_lock);
1019 }
1020
1021 static int acpi_thermal_add(struct acpi_device *device)
1022 {
1023 int result = 0;
1024 struct acpi_thermal *tz = NULL;
1025
1026
1027 if (!device)
1028 return -EINVAL;
1029
1030 tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1031 if (!tz)
1032 return -ENOMEM;
1033
1034 tz->device = device;
1035 strcpy(tz->name, device->pnp.bus_id);
1036 strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1037 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1038 device->driver_data = tz;
1039
1040 result = acpi_thermal_get_info(tz);
1041 if (result)
1042 goto free_memory;
1043
1044 acpi_thermal_guess_offset(tz);
1045
1046 result = acpi_thermal_register_thermal_zone(tz);
1047 if (result)
1048 goto free_memory;
1049
1050 refcount_set(&tz->thermal_check_count, 3);
1051 mutex_init(&tz->thermal_check_lock);
1052 INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
1053
1054 pr_info("%s [%s] (%ld C)\n", acpi_device_name(device),
1055 acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature));
1056 goto end;
1057
1058 free_memory:
1059 kfree(tz);
1060 end:
1061 return result;
1062 }
1063
1064 static int acpi_thermal_remove(struct acpi_device *device)
1065 {
1066 struct acpi_thermal *tz = NULL;
1067
1068 if (!device || !acpi_driver_data(device))
1069 return -EINVAL;
1070
1071 flush_workqueue(acpi_thermal_pm_queue);
1072 tz = acpi_driver_data(device);
1073
1074 acpi_thermal_unregister_thermal_zone(tz);
1075 kfree(tz);
1076 return 0;
1077 }
1078
1079 #ifdef CONFIG_PM_SLEEP
1080 static int acpi_thermal_suspend(struct device *dev)
1081 {
1082
1083 flush_workqueue(acpi_thermal_pm_queue);
1084 return 0;
1085 }
1086
1087 static int acpi_thermal_resume(struct device *dev)
1088 {
1089 struct acpi_thermal *tz;
1090 int i, j, power_state, result;
1091
1092 if (!dev)
1093 return -EINVAL;
1094
1095 tz = acpi_driver_data(to_acpi_device(dev));
1096 if (!tz)
1097 return -EINVAL;
1098
1099 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1100 if (!tz->trips.active[i].flags.valid)
1101 break;
1102 tz->trips.active[i].flags.enabled = 1;
1103 for (j = 0; j < tz->trips.active[i].devices.count; j++) {
1104 result = acpi_bus_update_power(
1105 tz->trips.active[i].devices.handles[j],
1106 &power_state);
1107 if (result || (power_state != ACPI_STATE_D0)) {
1108 tz->trips.active[i].flags.enabled = 0;
1109 break;
1110 }
1111 }
1112 tz->state.active |= tz->trips.active[i].flags.enabled;
1113 }
1114
1115 acpi_queue_thermal_check(tz);
1116
1117 return AE_OK;
1118 }
1119 #endif
1120
1121 static int thermal_act(const struct dmi_system_id *d) {
1122
1123 if (act == 0) {
1124 pr_notice("%s detected: disabling all active thermal trip points\n",
1125 d->ident);
1126 act = -1;
1127 }
1128 return 0;
1129 }
1130 static int thermal_nocrt(const struct dmi_system_id *d) {
1131
1132 pr_notice("%s detected: disabling all critical thermal trip point actions.\n",
1133 d->ident);
1134 nocrt = 1;
1135 return 0;
1136 }
1137 static int thermal_tzp(const struct dmi_system_id *d) {
1138
1139 if (tzp == 0) {
1140 pr_notice("%s detected: enabling thermal zone polling\n",
1141 d->ident);
1142 tzp = 300;
1143 }
1144 return 0;
1145 }
1146 static int thermal_psv(const struct dmi_system_id *d) {
1147
1148 if (psv == 0) {
1149 pr_notice("%s detected: disabling all passive thermal trip points\n",
1150 d->ident);
1151 psv = -1;
1152 }
1153 return 0;
1154 }
1155
1156 static const struct dmi_system_id thermal_dmi_table[] __initconst = {
1157
1158
1159
1160
1161 {
1162 .callback = thermal_act,
1163 .ident = "AOpen i915GMm-HFS",
1164 .matches = {
1165 DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1166 DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1167 },
1168 },
1169 {
1170 .callback = thermal_psv,
1171 .ident = "AOpen i915GMm-HFS",
1172 .matches = {
1173 DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1174 DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1175 },
1176 },
1177 {
1178 .callback = thermal_tzp,
1179 .ident = "AOpen i915GMm-HFS",
1180 .matches = {
1181 DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1182 DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1183 },
1184 },
1185 {
1186 .callback = thermal_nocrt,
1187 .ident = "Gigabyte GA-7ZX",
1188 .matches = {
1189 DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
1190 DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
1191 },
1192 },
1193 {}
1194 };
1195
1196 static int __init acpi_thermal_init(void)
1197 {
1198 int result = 0;
1199
1200 dmi_check_system(thermal_dmi_table);
1201
1202 if (off) {
1203 pr_notice("thermal control disabled\n");
1204 return -ENODEV;
1205 }
1206
1207 acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
1208 WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
1209 if (!acpi_thermal_pm_queue)
1210 return -ENODEV;
1211
1212 result = acpi_bus_register_driver(&acpi_thermal_driver);
1213 if (result < 0) {
1214 destroy_workqueue(acpi_thermal_pm_queue);
1215 return -ENODEV;
1216 }
1217
1218 return 0;
1219 }
1220
1221 static void __exit acpi_thermal_exit(void)
1222 {
1223 acpi_bus_unregister_driver(&acpi_thermal_driver);
1224 destroy_workqueue(acpi_thermal_pm_queue);
1225
1226 return;
1227 }
1228
1229 module_init(acpi_thermal_init);
1230 module_exit(acpi_thermal_exit);