linux/drivers/acpi/thermal.c
<<
>>
Prefs
   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 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  20 *
  21 *  This driver fully implements the ACPI thermal policy as described in the
  22 *  ACPI 2.0 Specification.
  23 *
  24 *  TBD: 1. Implement passive cooling hysteresis.
  25 *       2. Enhance passive cooling (CPU) states/limit interface to support
  26 *          concepts of 'multiple limiters', upper/lower limits, etc.
  27 *
  28 */
  29
  30#include <linux/kernel.h>
  31#include <linux/module.h>
  32#include <linux/dmi.h>
  33#include <linux/init.h>
  34#include <linux/slab.h>
  35#include <linux/types.h>
  36#include <linux/jiffies.h>
  37#include <linux/kmod.h>
  38#include <linux/reboot.h>
  39#include <linux/device.h>
  40#include <linux/thermal.h>
  41#include <linux/acpi.h>
  42#include <linux/workqueue.h>
  43#include <linux/uaccess.h>
  44
  45#define PREFIX "ACPI: "
  46
  47#define ACPI_THERMAL_CLASS              "thermal_zone"
  48#define ACPI_THERMAL_DEVICE_NAME        "Thermal Zone"
  49#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
  50#define ACPI_THERMAL_NOTIFY_THRESHOLDS  0x81
  51#define ACPI_THERMAL_NOTIFY_DEVICES     0x82
  52#define ACPI_THERMAL_NOTIFY_CRITICAL    0xF0
  53#define ACPI_THERMAL_NOTIFY_HOT         0xF1
  54#define ACPI_THERMAL_MODE_ACTIVE        0x00
  55
  56#define ACPI_THERMAL_MAX_ACTIVE 10
  57#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
  58
  59#define _COMPONENT              ACPI_THERMAL_COMPONENT
  60ACPI_MODULE_NAME("thermal");
  61
  62MODULE_AUTHOR("Paul Diefenbaugh");
  63MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
  64MODULE_LICENSE("GPL");
  65
  66static int act;
  67module_param(act, int, 0644);
  68MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
  69
  70static int crt;
  71module_param(crt, int, 0644);
  72MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
  73
  74static int tzp;
  75module_param(tzp, int, 0444);
  76MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
  77
  78static int nocrt;
  79module_param(nocrt, int, 0);
  80MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
  81
  82static int off;
  83module_param(off, int, 0);
  84MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
  85
  86static int psv;
  87module_param(psv, int, 0644);
  88MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
  89
  90static struct workqueue_struct *acpi_thermal_pm_queue;
  91
  92static int acpi_thermal_add(struct acpi_device *device);
  93static int acpi_thermal_remove(struct acpi_device *device);
  94static void acpi_thermal_notify(struct acpi_device *device, u32 event);
  95
  96static const struct acpi_device_id  thermal_device_ids[] = {
  97        {ACPI_THERMAL_HID, 0},
  98        {"", 0},
  99};
 100MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 101
 102#ifdef CONFIG_PM_SLEEP
 103static int acpi_thermal_suspend(struct device *dev);
 104static int acpi_thermal_resume(struct device *dev);
 105#else
 106#define acpi_thermal_suspend NULL
 107#define acpi_thermal_resume NULL
 108#endif
 109static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
 110
 111static struct acpi_driver acpi_thermal_driver = {
 112        .name = "thermal",
 113        .class = ACPI_THERMAL_CLASS,
 114        .ids = thermal_device_ids,
 115        .ops = {
 116                .add = acpi_thermal_add,
 117                .remove = acpi_thermal_remove,
 118                .notify = acpi_thermal_notify,
 119                },
 120        .drv.pm = &acpi_thermal_pm,
 121};
 122
 123struct acpi_thermal_state {
 124        u8 critical:1;
 125        u8 hot:1;
 126        u8 passive:1;
 127        u8 active:1;
 128        u8 reserved:4;
 129        int active_index;
 130};
 131
 132struct acpi_thermal_state_flags {
 133        u8 valid:1;
 134        u8 enabled:1;
 135        u8 reserved:6;
 136};
 137
 138struct acpi_thermal_critical {
 139        struct acpi_thermal_state_flags flags;
 140        unsigned long temperature;
 141};
 142
 143struct acpi_thermal_hot {
 144        struct acpi_thermal_state_flags flags;
 145        unsigned long temperature;
 146};
 147
 148struct acpi_thermal_passive {
 149        struct acpi_thermal_state_flags flags;
 150        unsigned long temperature;
 151        unsigned long tc1;
 152        unsigned long tc2;
 153        unsigned long tsp;
 154        struct acpi_handle_list devices;
 155};
 156
 157struct acpi_thermal_active {
 158        struct acpi_thermal_state_flags flags;
 159        unsigned long temperature;
 160        struct acpi_handle_list devices;
 161};
 162
 163struct acpi_thermal_trips {
 164        struct acpi_thermal_critical critical;
 165        struct acpi_thermal_hot hot;
 166        struct acpi_thermal_passive passive;
 167        struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
 168};
 169
 170struct acpi_thermal_flags {
 171        u8 cooling_mode:1;      /* _SCP */
 172        u8 devices:1;           /* _TZD */
 173        u8 reserved:6;
 174};
 175
 176struct acpi_thermal {
 177        struct acpi_device * device;
 178        acpi_bus_id name;
 179        unsigned long temperature;
 180        unsigned long last_temperature;
 181        unsigned long polling_frequency;
 182        volatile u8 zombie;
 183        struct acpi_thermal_flags flags;
 184        struct acpi_thermal_state state;
 185        struct acpi_thermal_trips trips;
 186        struct acpi_handle_list devices;
 187        struct thermal_zone_device *thermal_zone;
 188        int tz_enabled;
 189        int kelvin_offset;
 190        struct work_struct thermal_check_work;
 191};
 192
 193/* --------------------------------------------------------------------------
 194                             Thermal Zone Management
 195   -------------------------------------------------------------------------- */
 196
 197static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
 198{
 199        acpi_status status = AE_OK;
 200        unsigned long long tmp;
 201
 202        if (!tz)
 203                return -EINVAL;
 204
 205        tz->last_temperature = tz->temperature;
 206
 207        status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
 208        if (ACPI_FAILURE(status))
 209                return -ENODEV;
 210
 211        tz->temperature = tmp;
 212        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
 213                          tz->temperature));
 214
 215        return 0;
 216}
 217
 218static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
 219{
 220        acpi_status status = AE_OK;
 221        unsigned long long tmp;
 222
 223        if (!tz)
 224                return -EINVAL;
 225
 226        status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
 227        if (ACPI_FAILURE(status))
 228                return -ENODEV;
 229
 230        tz->polling_frequency = tmp;
 231        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
 232                          tz->polling_frequency));
 233
 234        return 0;
 235}
 236
 237static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
 238{
 239        if (!tz)
 240                return -EINVAL;
 241
 242        if (!acpi_has_method(tz->device->handle, "_SCP")) {
 243                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
 244                return -ENODEV;
 245        } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
 246                                                           "_SCP", mode))) {
 247                return -ENODEV;
 248        }
 249
 250        return 0;
 251}
 252
 253#define ACPI_TRIPS_CRITICAL     0x01
 254#define ACPI_TRIPS_HOT          0x02
 255#define ACPI_TRIPS_PASSIVE      0x04
 256#define ACPI_TRIPS_ACTIVE       0x08
 257#define ACPI_TRIPS_DEVICES      0x10
 258
 259#define ACPI_TRIPS_REFRESH_THRESHOLDS   (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
 260#define ACPI_TRIPS_REFRESH_DEVICES      ACPI_TRIPS_DEVICES
 261
 262#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT |    \
 263                              ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |  \
 264                              ACPI_TRIPS_DEVICES)
 265
 266/*
 267 * This exception is thrown out in two cases:
 268 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
 269 *   when re-evaluating the AML code.
 270 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
 271 *   We need to re-bind the cooling devices of a thermal zone when this occurs.
 272 */
 273#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str)        \
 274do {    \
 275        if (flags != ACPI_TRIPS_INIT)   \
 276                ACPI_EXCEPTION((AE_INFO, AE_ERROR,      \
 277                "ACPI thermal trip point %s changed\n"  \
 278                "Please send acpidump to linux-acpi@vger.kernel.org", str)); \
 279} while (0)
 280
 281static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 282{
 283        acpi_status status = AE_OK;
 284        unsigned long long tmp;
 285        struct acpi_handle_list devices;
 286        int valid = 0;
 287        int i;
 288
 289        /* Critical Shutdown */
 290        if (flag & ACPI_TRIPS_CRITICAL) {
 291                status = acpi_evaluate_integer(tz->device->handle,
 292                                "_CRT", NULL, &tmp);
 293                tz->trips.critical.temperature = tmp;
 294                /*
 295                 * Treat freezing temperatures as invalid as well; some
 296                 * BIOSes return really low values and cause reboots at startup.
 297                 * Below zero (Celsius) values clearly aren't right for sure..
 298                 * ... so lets discard those as invalid.
 299                 */
 300                if (ACPI_FAILURE(status)) {
 301                        tz->trips.critical.flags.valid = 0;
 302                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 303                                          "No critical threshold\n"));
 304                } else if (tmp <= 2732) {
 305                        pr_warn(FW_BUG "Invalid critical threshold (%llu)\n",
 306                                tmp);
 307                        tz->trips.critical.flags.valid = 0;
 308                } else {
 309                        tz->trips.critical.flags.valid = 1;
 310                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 311                                          "Found critical threshold [%lu]\n",
 312                                          tz->trips.critical.temperature));
 313                }
 314                if (tz->trips.critical.flags.valid == 1) {
 315                        if (crt == -1) {
 316                                tz->trips.critical.flags.valid = 0;
 317                        } else if (crt > 0) {
 318                                unsigned long crt_k = CELSIUS_TO_DECI_KELVIN(crt);
 319                                /*
 320                                 * Allow override critical threshold
 321                                 */
 322                                if (crt_k > tz->trips.critical.temperature)
 323                                        pr_warn(PREFIX "Critical threshold %d C\n",
 324                                                crt);
 325                                tz->trips.critical.temperature = crt_k;
 326                        }
 327                }
 328        }
 329
 330        /* Critical Sleep (optional) */
 331        if (flag & ACPI_TRIPS_HOT) {
 332                status = acpi_evaluate_integer(tz->device->handle,
 333                                "_HOT", NULL, &tmp);
 334                if (ACPI_FAILURE(status)) {
 335                        tz->trips.hot.flags.valid = 0;
 336                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 337                                        "No hot threshold\n"));
 338                } else {
 339                        tz->trips.hot.temperature = tmp;
 340                        tz->trips.hot.flags.valid = 1;
 341                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 342                                        "Found hot threshold [%lu]\n",
 343                                        tz->trips.hot.temperature));
 344                }
 345        }
 346
 347        /* Passive (optional) */
 348        if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
 349                (flag == ACPI_TRIPS_INIT)) {
 350                valid = tz->trips.passive.flags.valid;
 351                if (psv == -1) {
 352                        status = AE_SUPPORT;
 353                } else if (psv > 0) {
 354                        tmp = CELSIUS_TO_DECI_KELVIN(psv);
 355                        status = AE_OK;
 356                } else {
 357                        status = acpi_evaluate_integer(tz->device->handle,
 358                                "_PSV", NULL, &tmp);
 359                }
 360
 361                if (ACPI_FAILURE(status))
 362                        tz->trips.passive.flags.valid = 0;
 363                else {
 364                        tz->trips.passive.temperature = tmp;
 365                        tz->trips.passive.flags.valid = 1;
 366                        if (flag == ACPI_TRIPS_INIT) {
 367                                status = acpi_evaluate_integer(
 368                                                tz->device->handle, "_TC1",
 369                                                NULL, &tmp);
 370                                if (ACPI_FAILURE(status))
 371                                        tz->trips.passive.flags.valid = 0;
 372                                else
 373                                        tz->trips.passive.tc1 = tmp;
 374                                status = acpi_evaluate_integer(
 375                                                tz->device->handle, "_TC2",
 376                                                NULL, &tmp);
 377                                if (ACPI_FAILURE(status))
 378                                        tz->trips.passive.flags.valid = 0;
 379                                else
 380                                        tz->trips.passive.tc2 = tmp;
 381                                status = acpi_evaluate_integer(
 382                                                tz->device->handle, "_TSP",
 383                                                NULL, &tmp);
 384                                if (ACPI_FAILURE(status))
 385                                        tz->trips.passive.flags.valid = 0;
 386                                else
 387                                        tz->trips.passive.tsp = tmp;
 388                        }
 389                }
 390        }
 391        if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
 392                memset(&devices, 0, sizeof(struct acpi_handle_list));
 393                status = acpi_evaluate_reference(tz->device->handle, "_PSL",
 394                                                        NULL, &devices);
 395                if (ACPI_FAILURE(status)) {
 396                        pr_warn(PREFIX "Invalid passive threshold\n");
 397                        tz->trips.passive.flags.valid = 0;
 398                }
 399                else
 400                        tz->trips.passive.flags.valid = 1;
 401
 402                if (memcmp(&tz->trips.passive.devices, &devices,
 403                                sizeof(struct acpi_handle_list))) {
 404                        memcpy(&tz->trips.passive.devices, &devices,
 405                                sizeof(struct acpi_handle_list));
 406                        ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 407                }
 408        }
 409        if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
 410                if (valid != tz->trips.passive.flags.valid)
 411                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
 412        }
 413
 414        /* Active (optional) */
 415        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
 416                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
 417                valid = tz->trips.active[i].flags.valid;
 418
 419                if (act == -1)
 420                        break; /* disable all active trip points */
 421
 422                if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
 423                        tz->trips.active[i].flags.valid)) {
 424                        status = acpi_evaluate_integer(tz->device->handle,
 425                                                        name, NULL, &tmp);
 426                        if (ACPI_FAILURE(status)) {
 427                                tz->trips.active[i].flags.valid = 0;
 428                                if (i == 0)
 429                                        break;
 430                                if (act <= 0)
 431                                        break;
 432                                if (i == 1)
 433                                        tz->trips.active[0].temperature =
 434                                                CELSIUS_TO_DECI_KELVIN(act);
 435                                else
 436                                        /*
 437                                         * Don't allow override higher than
 438                                         * the next higher trip point
 439                                         */
 440                                        tz->trips.active[i - 1].temperature =
 441                                                (tz->trips.active[i - 2].temperature <
 442                                                CELSIUS_TO_DECI_KELVIN(act) ?
 443                                                tz->trips.active[i - 2].temperature :
 444                                                CELSIUS_TO_DECI_KELVIN(act));
 445                                break;
 446                        } else {
 447                                tz->trips.active[i].temperature = tmp;
 448                                tz->trips.active[i].flags.valid = 1;
 449                        }
 450                }
 451
 452                name[2] = 'L';
 453                if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
 454                        memset(&devices, 0, sizeof(struct acpi_handle_list));
 455                        status = acpi_evaluate_reference(tz->device->handle,
 456                                                name, NULL, &devices);
 457                        if (ACPI_FAILURE(status)) {
 458                                pr_warn(PREFIX "Invalid active%d threshold\n",
 459                                        i);
 460                                tz->trips.active[i].flags.valid = 0;
 461                        }
 462                        else
 463                                tz->trips.active[i].flags.valid = 1;
 464
 465                        if (memcmp(&tz->trips.active[i].devices, &devices,
 466                                        sizeof(struct acpi_handle_list))) {
 467                                memcpy(&tz->trips.active[i].devices, &devices,
 468                                        sizeof(struct acpi_handle_list));
 469                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 470                        }
 471                }
 472                if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
 473                        if (valid != tz->trips.active[i].flags.valid)
 474                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
 475
 476                if (!tz->trips.active[i].flags.valid)
 477                        break;
 478        }
 479
 480        if ((flag & ACPI_TRIPS_DEVICES)
 481            && acpi_has_method(tz->device->handle, "_TZD")) {
 482                memset(&devices, 0, sizeof(devices));
 483                status = acpi_evaluate_reference(tz->device->handle, "_TZD",
 484                                                NULL, &devices);
 485                if (ACPI_SUCCESS(status)
 486                    && memcmp(&tz->devices, &devices, sizeof(devices))) {
 487                        tz->devices = devices;
 488                        ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 489                }
 490        }
 491
 492        return 0;
 493}
 494
 495static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 496{
 497        int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
 498
 499        if (ret)
 500                return ret;
 501
 502        valid = tz->trips.critical.flags.valid |
 503                tz->trips.hot.flags.valid |
 504                tz->trips.passive.flags.valid;
 505
 506        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
 507                valid |= tz->trips.active[i].flags.valid;
 508
 509        if (!valid) {
 510                pr_warn(FW_BUG "No valid trip found\n");
 511                return -ENODEV;
 512        }
 513        return 0;
 514}
 515
 516static void acpi_thermal_check(void *data)
 517{
 518        struct acpi_thermal *tz = data;
 519
 520        if (!tz->tz_enabled)
 521                return;
 522
 523        thermal_zone_device_update(tz->thermal_zone,
 524                                   THERMAL_EVENT_UNSPECIFIED);
 525}
 526
 527/* sys I/F for generic thermal sysfs support */
 528
 529static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 530{
 531        struct acpi_thermal *tz = thermal->devdata;
 532        int result;
 533
 534        if (!tz)
 535                return -EINVAL;
 536
 537        result = acpi_thermal_get_temperature(tz);
 538        if (result)
 539                return result;
 540
 541        *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(tz->temperature,
 542                                                        tz->kelvin_offset);
 543        return 0;
 544}
 545
 546static int thermal_get_mode(struct thermal_zone_device *thermal,
 547                                enum thermal_device_mode *mode)
 548{
 549        struct acpi_thermal *tz = thermal->devdata;
 550
 551        if (!tz)
 552                return -EINVAL;
 553
 554        *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
 555                THERMAL_DEVICE_DISABLED;
 556
 557        return 0;
 558}
 559
 560static int thermal_set_mode(struct thermal_zone_device *thermal,
 561                                enum thermal_device_mode mode)
 562{
 563        struct acpi_thermal *tz = thermal->devdata;
 564        int enable;
 565
 566        if (!tz)
 567                return -EINVAL;
 568
 569        /*
 570         * enable/disable thermal management from ACPI thermal driver
 571         */
 572        if (mode == THERMAL_DEVICE_ENABLED)
 573                enable = 1;
 574        else if (mode == THERMAL_DEVICE_DISABLED) {
 575                enable = 0;
 576                pr_warn("thermal zone will be disabled\n");
 577        } else
 578                return -EINVAL;
 579
 580        if (enable != tz->tz_enabled) {
 581                tz->tz_enabled = enable;
 582                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 583                        "%s kernel ACPI thermal control\n",
 584                        tz->tz_enabled ? "Enable" : "Disable"));
 585                acpi_thermal_check(tz);
 586        }
 587        return 0;
 588}
 589
 590static int thermal_get_trip_type(struct thermal_zone_device *thermal,
 591                                 int trip, enum thermal_trip_type *type)
 592{
 593        struct acpi_thermal *tz = thermal->devdata;
 594        int i;
 595
 596        if (!tz || trip < 0)
 597                return -EINVAL;
 598
 599        if (tz->trips.critical.flags.valid) {
 600                if (!trip) {
 601                        *type = THERMAL_TRIP_CRITICAL;
 602                        return 0;
 603                }
 604                trip--;
 605        }
 606
 607        if (tz->trips.hot.flags.valid) {
 608                if (!trip) {
 609                        *type = THERMAL_TRIP_HOT;
 610                        return 0;
 611                }
 612                trip--;
 613        }
 614
 615        if (tz->trips.passive.flags.valid) {
 616                if (!trip) {
 617                        *type = THERMAL_TRIP_PASSIVE;
 618                        return 0;
 619                }
 620                trip--;
 621        }
 622
 623        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 624                tz->trips.active[i].flags.valid; i++) {
 625                if (!trip) {
 626                        *type = THERMAL_TRIP_ACTIVE;
 627                        return 0;
 628                }
 629                trip--;
 630        }
 631
 632        return -EINVAL;
 633}
 634
 635static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
 636                                 int trip, int *temp)
 637{
 638        struct acpi_thermal *tz = thermal->devdata;
 639        int i;
 640
 641        if (!tz || trip < 0)
 642                return -EINVAL;
 643
 644        if (tz->trips.critical.flags.valid) {
 645                if (!trip) {
 646                        *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 647                                tz->trips.critical.temperature,
 648                                tz->kelvin_offset);
 649                        return 0;
 650                }
 651                trip--;
 652        }
 653
 654        if (tz->trips.hot.flags.valid) {
 655                if (!trip) {
 656                        *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 657                                tz->trips.hot.temperature,
 658                                tz->kelvin_offset);
 659                        return 0;
 660                }
 661                trip--;
 662        }
 663
 664        if (tz->trips.passive.flags.valid) {
 665                if (!trip) {
 666                        *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 667                                tz->trips.passive.temperature,
 668                                tz->kelvin_offset);
 669                        return 0;
 670                }
 671                trip--;
 672        }
 673
 674        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 675                tz->trips.active[i].flags.valid; i++) {
 676                if (!trip) {
 677                        *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 678                                tz->trips.active[i].temperature,
 679                                tz->kelvin_offset);
 680                        return 0;
 681                }
 682                trip--;
 683        }
 684
 685        return -EINVAL;
 686}
 687
 688static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
 689                                int *temperature)
 690{
 691        struct acpi_thermal *tz = thermal->devdata;
 692
 693        if (tz->trips.critical.flags.valid) {
 694                *temperature = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 695                                tz->trips.critical.temperature,
 696                                tz->kelvin_offset);
 697                return 0;
 698        } else
 699                return -EINVAL;
 700}
 701
 702static int thermal_get_trend(struct thermal_zone_device *thermal,
 703                                int trip, enum thermal_trend *trend)
 704{
 705        struct acpi_thermal *tz = thermal->devdata;
 706        enum thermal_trip_type type;
 707        int i;
 708
 709        if (thermal_get_trip_type(thermal, trip, &type))
 710                return -EINVAL;
 711
 712        if (type == THERMAL_TRIP_ACTIVE) {
 713                int trip_temp;
 714                int temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
 715                                        tz->temperature, tz->kelvin_offset);
 716                if (thermal_get_trip_temp(thermal, trip, &trip_temp))
 717                        return -EINVAL;
 718
 719                if (temp > trip_temp) {
 720                        *trend = THERMAL_TREND_RAISING;
 721                        return 0;
 722                } else {
 723                        /* Fall back on default trend */
 724                        return -EINVAL;
 725                }
 726        }
 727
 728        /*
 729         * tz->temperature has already been updated by generic thermal layer,
 730         * before this callback being invoked
 731         */
 732        i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
 733                + (tz->trips.passive.tc2
 734                * (tz->temperature - tz->trips.passive.temperature));
 735
 736        if (i > 0)
 737                *trend = THERMAL_TREND_RAISING;
 738        else if (i < 0)
 739                *trend = THERMAL_TREND_DROPPING;
 740        else
 741                *trend = THERMAL_TREND_STABLE;
 742        return 0;
 743}
 744
 745
 746static int thermal_notify(struct thermal_zone_device *thermal, int trip,
 747                           enum thermal_trip_type trip_type)
 748{
 749        u8 type = 0;
 750        struct acpi_thermal *tz = thermal->devdata;
 751
 752        if (trip_type == THERMAL_TRIP_CRITICAL)
 753                type = ACPI_THERMAL_NOTIFY_CRITICAL;
 754        else if (trip_type == THERMAL_TRIP_HOT)
 755                type = ACPI_THERMAL_NOTIFY_HOT;
 756        else
 757                return 0;
 758
 759        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
 760                                        dev_name(&tz->device->dev), type, 1);
 761
 762        if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
 763                return 1;
 764
 765        return 0;
 766}
 767
 768static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 769                                        struct thermal_cooling_device *cdev,
 770                                        bool bind)
 771{
 772        struct acpi_device *device = cdev->devdata;
 773        struct acpi_thermal *tz = thermal->devdata;
 774        struct acpi_device *dev;
 775        acpi_status status;
 776        acpi_handle handle;
 777        int i;
 778        int j;
 779        int trip = -1;
 780        int result = 0;
 781
 782        if (tz->trips.critical.flags.valid)
 783                trip++;
 784
 785        if (tz->trips.hot.flags.valid)
 786                trip++;
 787
 788        if (tz->trips.passive.flags.valid) {
 789                trip++;
 790                for (i = 0; i < tz->trips.passive.devices.count;
 791                    i++) {
 792                        handle = tz->trips.passive.devices.handles[i];
 793                        status = acpi_bus_get_device(handle, &dev);
 794                        if (ACPI_FAILURE(status) || dev != device)
 795                                continue;
 796                        if (bind)
 797                                result =
 798                                        thermal_zone_bind_cooling_device
 799                                        (thermal, trip, cdev,
 800                                         THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
 801                                         THERMAL_WEIGHT_DEFAULT);
 802                        else
 803                                result =
 804                                        thermal_zone_unbind_cooling_device
 805                                        (thermal, trip, cdev);
 806                        if (result)
 807                                goto failed;
 808                }
 809        }
 810
 811        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
 812                if (!tz->trips.active[i].flags.valid)
 813                        break;
 814                trip++;
 815                for (j = 0;
 816                    j < tz->trips.active[i].devices.count;
 817                    j++) {
 818                        handle = tz->trips.active[i].devices.handles[j];
 819                        status = acpi_bus_get_device(handle, &dev);
 820                        if (ACPI_FAILURE(status) || dev != device)
 821                                continue;
 822                        if (bind)
 823                                result = thermal_zone_bind_cooling_device
 824                                        (thermal, trip, cdev,
 825                                         THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
 826                                         THERMAL_WEIGHT_DEFAULT);
 827                        else
 828                                result = thermal_zone_unbind_cooling_device
 829                                        (thermal, trip, cdev);
 830                        if (result)
 831                                goto failed;
 832                }
 833        }
 834
 835        for (i = 0; i < tz->devices.count; i++) {
 836                handle = tz->devices.handles[i];
 837                status = acpi_bus_get_device(handle, &dev);
 838                if (ACPI_SUCCESS(status) && (dev == device)) {
 839                        if (bind)
 840                                result = thermal_zone_bind_cooling_device
 841                                                (thermal, THERMAL_TRIPS_NONE,
 842                                                 cdev, THERMAL_NO_LIMIT,
 843                                                 THERMAL_NO_LIMIT,
 844                                                 THERMAL_WEIGHT_DEFAULT);
 845                        else
 846                                result = thermal_zone_unbind_cooling_device
 847                                                (thermal, THERMAL_TRIPS_NONE,
 848                                                 cdev);
 849                        if (result)
 850                                goto failed;
 851                }
 852        }
 853
 854failed:
 855        return result;
 856}
 857
 858static int
 859acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
 860                                        struct thermal_cooling_device *cdev)
 861{
 862        return acpi_thermal_cooling_device_cb(thermal, cdev, true);
 863}
 864
 865static int
 866acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
 867                                        struct thermal_cooling_device *cdev)
 868{
 869        return acpi_thermal_cooling_device_cb(thermal, cdev, false);
 870}
 871
 872static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 873        .bind = acpi_thermal_bind_cooling_device,
 874        .unbind = acpi_thermal_unbind_cooling_device,
 875        .get_temp = thermal_get_temp,
 876        .get_mode = thermal_get_mode,
 877        .set_mode = thermal_set_mode,
 878        .get_trip_type = thermal_get_trip_type,
 879        .get_trip_temp = thermal_get_trip_temp,
 880        .get_crit_temp = thermal_get_crit_temp,
 881        .get_trend = thermal_get_trend,
 882        .notify = thermal_notify,
 883};
 884
 885static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 886{
 887        int trips = 0;
 888        int result;
 889        acpi_status status;
 890        int i;
 891
 892        if (tz->trips.critical.flags.valid)
 893                trips++;
 894
 895        if (tz->trips.hot.flags.valid)
 896                trips++;
 897
 898        if (tz->trips.passive.flags.valid)
 899                trips++;
 900
 901        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 902                        tz->trips.active[i].flags.valid; i++, trips++);
 903
 904        if (tz->trips.passive.flags.valid)
 905                tz->thermal_zone =
 906                        thermal_zone_device_register("acpitz", trips, 0, tz,
 907                                                &acpi_thermal_zone_ops, NULL,
 908                                                     tz->trips.passive.tsp*100,
 909                                                     tz->polling_frequency*100);
 910        else
 911                tz->thermal_zone =
 912                        thermal_zone_device_register("acpitz", trips, 0, tz,
 913                                                &acpi_thermal_zone_ops, NULL,
 914                                                0, tz->polling_frequency*100);
 915        if (IS_ERR(tz->thermal_zone))
 916                return -ENODEV;
 917
 918        result = sysfs_create_link(&tz->device->dev.kobj,
 919                                   &tz->thermal_zone->device.kobj, "thermal_zone");
 920        if (result)
 921                return result;
 922
 923        result = sysfs_create_link(&tz->thermal_zone->device.kobj,
 924                                   &tz->device->dev.kobj, "device");
 925        if (result)
 926                return result;
 927
 928        status =  acpi_bus_attach_private_data(tz->device->handle,
 929                                               tz->thermal_zone);
 930        if (ACPI_FAILURE(status))
 931                return -ENODEV;
 932
 933        tz->tz_enabled = 1;
 934
 935        dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 936                 tz->thermal_zone->id);
 937        return 0;
 938}
 939
 940static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
 941{
 942        sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
 943        sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
 944        thermal_zone_device_unregister(tz->thermal_zone);
 945        tz->thermal_zone = NULL;
 946        acpi_bus_detach_private_data(tz->device->handle);
 947}
 948
 949
 950/* --------------------------------------------------------------------------
 951                                 Driver Interface
 952   -------------------------------------------------------------------------- */
 953
 954static void acpi_thermal_notify(struct acpi_device *device, u32 event)
 955{
 956        struct acpi_thermal *tz = acpi_driver_data(device);
 957
 958
 959        if (!tz)
 960                return;
 961
 962        switch (event) {
 963        case ACPI_THERMAL_NOTIFY_TEMPERATURE:
 964                acpi_thermal_check(tz);
 965                break;
 966        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
 967                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
 968                acpi_thermal_check(tz);
 969                acpi_bus_generate_netlink_event(device->pnp.device_class,
 970                                                  dev_name(&device->dev), event, 0);
 971                break;
 972        case ACPI_THERMAL_NOTIFY_DEVICES:
 973                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
 974                acpi_thermal_check(tz);
 975                acpi_bus_generate_netlink_event(device->pnp.device_class,
 976                                                  dev_name(&device->dev), event, 0);
 977                break;
 978        default:
 979                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 980                                  "Unsupported event [0x%x]\n", event));
 981                break;
 982        }
 983}
 984
 985/*
 986 * On some platforms, the AML code has dependency about
 987 * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
 988 * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
 989 *    /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
 990 * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
 991 *    if _TMP has never been evaluated.
 992 *
 993 * As this dependency is totally transparent to OS, evaluate
 994 * all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
 995 * _TMP, before they are actually used.
 996 */
 997static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
 998{
 999        acpi_handle handle = tz->device->handle;
1000        unsigned long long value;
1001        int i;
1002
1003        acpi_evaluate_integer(handle, "_CRT", NULL, &value);
1004        acpi_evaluate_integer(handle, "_HOT", NULL, &value);
1005        acpi_evaluate_integer(handle, "_PSV", NULL, &value);
1006        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1007                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
1008                acpi_status status;
1009
1010                status = acpi_evaluate_integer(handle, name, NULL, &value);
1011                if (status == AE_NOT_FOUND)
1012                        break;
1013        }
1014        acpi_evaluate_integer(handle, "_TMP", NULL, &value);
1015}
1016
1017static int acpi_thermal_get_info(struct acpi_thermal *tz)
1018{
1019        int result = 0;
1020
1021
1022        if (!tz)
1023                return -EINVAL;
1024
1025        acpi_thermal_aml_dependency_fix(tz);
1026
1027        /* Get trip points [_CRT, _PSV, etc.] (required) */
1028        result = acpi_thermal_get_trip_points(tz);
1029        if (result)
1030                return result;
1031
1032        /* Get temperature [_TMP] (required) */
1033        result = acpi_thermal_get_temperature(tz);
1034        if (result)
1035                return result;
1036
1037        /* Set the cooling mode [_SCP] to active cooling (default) */
1038        result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1039        if (!result)
1040                tz->flags.cooling_mode = 1;
1041
1042        /* Get default polling frequency [_TZP] (optional) */
1043        if (tzp)
1044                tz->polling_frequency = tzp;
1045        else
1046                acpi_thermal_get_polling_frequency(tz);
1047
1048        return 0;
1049}
1050
1051/*
1052 * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
1053 * handles temperature values with a single decimal place. As a consequence,
1054 * some implementations use an offset of 273.1 and others use an offset of
1055 * 273.2. Try to find out which one is being used, to present the most
1056 * accurate and visually appealing number.
1057 *
1058 * The heuristic below should work for all ACPI thermal zones which have a
1059 * critical trip point with a value being a multiple of 0.5 degree Celsius.
1060 */
1061static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
1062{
1063        if (tz->trips.critical.flags.valid &&
1064            (tz->trips.critical.temperature % 5) == 1)
1065                tz->kelvin_offset = 2731;
1066        else
1067                tz->kelvin_offset = 2732;
1068}
1069
1070static void acpi_thermal_check_fn(struct work_struct *work)
1071{
1072        struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
1073                                               thermal_check_work);
1074        acpi_thermal_check(tz);
1075}
1076
1077static int acpi_thermal_add(struct acpi_device *device)
1078{
1079        int result = 0;
1080        struct acpi_thermal *tz = NULL;
1081
1082
1083        if (!device)
1084                return -EINVAL;
1085
1086        tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1087        if (!tz)
1088                return -ENOMEM;
1089
1090        tz->device = device;
1091        strcpy(tz->name, device->pnp.bus_id);
1092        strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1093        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1094        device->driver_data = tz;
1095
1096        result = acpi_thermal_get_info(tz);
1097        if (result)
1098                goto free_memory;
1099
1100        acpi_thermal_guess_offset(tz);
1101
1102        result = acpi_thermal_register_thermal_zone(tz);
1103        if (result)
1104                goto free_memory;
1105
1106        INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
1107
1108        pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
1109                acpi_device_bid(device), DECI_KELVIN_TO_CELSIUS(tz->temperature));
1110        goto end;
1111
1112free_memory:
1113        kfree(tz);
1114end:
1115        return result;
1116}
1117
1118static int acpi_thermal_remove(struct acpi_device *device)
1119{
1120        struct acpi_thermal *tz = NULL;
1121
1122        if (!device || !acpi_driver_data(device))
1123                return -EINVAL;
1124
1125        flush_workqueue(acpi_thermal_pm_queue);
1126        tz = acpi_driver_data(device);
1127
1128        acpi_thermal_unregister_thermal_zone(tz);
1129        kfree(tz);
1130        return 0;
1131}
1132
1133#ifdef CONFIG_PM_SLEEP
1134static int acpi_thermal_suspend(struct device *dev)
1135{
1136        /* Make sure the previously queued thermal check work has been done */
1137        flush_workqueue(acpi_thermal_pm_queue);
1138        return 0;
1139}
1140
1141static int acpi_thermal_resume(struct device *dev)
1142{
1143        struct acpi_thermal *tz;
1144        int i, j, power_state, result;
1145
1146        if (!dev)
1147                return -EINVAL;
1148
1149        tz = acpi_driver_data(to_acpi_device(dev));
1150        if (!tz)
1151                return -EINVAL;
1152
1153        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1154                if (!(&tz->trips.active[i]))
1155                        break;
1156                if (!tz->trips.active[i].flags.valid)
1157                        break;
1158                tz->trips.active[i].flags.enabled = 1;
1159                for (j = 0; j < tz->trips.active[i].devices.count; j++) {
1160                        result = acpi_bus_update_power(
1161                                        tz->trips.active[i].devices.handles[j],
1162                                        &power_state);
1163                        if (result || (power_state != ACPI_STATE_D0)) {
1164                                tz->trips.active[i].flags.enabled = 0;
1165                                break;
1166                        }
1167                }
1168                tz->state.active |= tz->trips.active[i].flags.enabled;
1169        }
1170
1171        queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
1172
1173        return AE_OK;
1174}
1175#endif
1176
1177static int thermal_act(const struct dmi_system_id *d) {
1178
1179        if (act == 0) {
1180                pr_notice(PREFIX "%s detected: "
1181                          "disabling all active thermal trip points\n", d->ident);
1182                act = -1;
1183        }
1184        return 0;
1185}
1186static int thermal_nocrt(const struct dmi_system_id *d) {
1187
1188        pr_notice(PREFIX "%s detected: "
1189                  "disabling all critical thermal trip point actions.\n", d->ident);
1190        nocrt = 1;
1191        return 0;
1192}
1193static int thermal_tzp(const struct dmi_system_id *d) {
1194
1195        if (tzp == 0) {
1196                pr_notice(PREFIX "%s detected: "
1197                          "enabling thermal zone polling\n", d->ident);
1198                tzp = 300;      /* 300 dS = 30 Seconds */
1199        }
1200        return 0;
1201}
1202static int thermal_psv(const struct dmi_system_id *d) {
1203
1204        if (psv == 0) {
1205                pr_notice(PREFIX "%s detected: "
1206                          "disabling all passive thermal trip points\n", d->ident);
1207                psv = -1;
1208        }
1209        return 0;
1210}
1211
1212static struct dmi_system_id thermal_dmi_table[] __initdata = {
1213        /*
1214         * Award BIOS on this AOpen makes thermal control almost worthless.
1215         * http://bugzilla.kernel.org/show_bug.cgi?id=8842
1216         */
1217        {
1218         .callback = thermal_act,
1219         .ident = "AOpen i915GMm-HFS",
1220         .matches = {
1221                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1222                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1223                },
1224        },
1225        {
1226         .callback = thermal_psv,
1227         .ident = "AOpen i915GMm-HFS",
1228         .matches = {
1229                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1230                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1231                },
1232        },
1233        {
1234         .callback = thermal_tzp,
1235         .ident = "AOpen i915GMm-HFS",
1236         .matches = {
1237                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1238                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1239                },
1240        },
1241        {
1242         .callback = thermal_nocrt,
1243         .ident = "Gigabyte GA-7ZX",
1244         .matches = {
1245                DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
1246                DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
1247                },
1248        },
1249        {}
1250};
1251
1252static int __init acpi_thermal_init(void)
1253{
1254        int result = 0;
1255
1256        dmi_check_system(thermal_dmi_table);
1257
1258        if (off) {
1259                pr_notice(PREFIX "thermal control disabled\n");
1260                return -ENODEV;
1261        }
1262
1263        acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
1264                                                WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
1265        if (!acpi_thermal_pm_queue)
1266                return -ENODEV;
1267
1268        result = acpi_bus_register_driver(&acpi_thermal_driver);
1269        if (result < 0) {
1270                destroy_workqueue(acpi_thermal_pm_queue);
1271                return -ENODEV;
1272        }
1273
1274        return 0;
1275}
1276
1277static void __exit acpi_thermal_exit(void)
1278{
1279        acpi_bus_unregister_driver(&acpi_thermal_driver);
1280        destroy_workqueue(acpi_thermal_pm_queue);
1281
1282        return;
1283}
1284
1285module_init(acpi_thermal_init);
1286module_exit(acpi_thermal_exit);
1287
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.