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