linux/drivers/thermal/thermal_sys.c
<<
>>
Prefs
   1/*
   2 *  thermal.c - Generic Thermal Management Sysfs support.
   3 *
   4 *  Copyright (C) 2008 Intel Corp
   5 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
   6 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
   7 *
   8 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License as published by
  12 *  the Free Software Foundation; version 2 of the License.
  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
  26#include <linux/module.h>
  27#include <linux/device.h>
  28#include <linux/err.h>
  29#include <linux/kdev_t.h>
  30#include <linux/idr.h>
  31#include <linux/thermal.h>
  32#include <linux/spinlock.h>
  33#include <linux/reboot.h>
  34
  35MODULE_AUTHOR("Zhang Rui");
  36MODULE_DESCRIPTION("Generic thermal management sysfs support");
  37MODULE_LICENSE("GPL");
  38
  39#define PREFIX "Thermal: "
  40
  41struct thermal_cooling_device_instance {
  42        int id;
  43        char name[THERMAL_NAME_LENGTH];
  44        struct thermal_zone_device *tz;
  45        struct thermal_cooling_device *cdev;
  46        int trip;
  47        char attr_name[THERMAL_NAME_LENGTH];
  48        struct device_attribute attr;
  49        struct list_head node;
  50};
  51
  52static DEFINE_IDR(thermal_tz_idr);
  53static DEFINE_IDR(thermal_cdev_idr);
  54static DEFINE_MUTEX(thermal_idr_lock);
  55
  56static LIST_HEAD(thermal_tz_list);
  57static LIST_HEAD(thermal_cdev_list);
  58static DEFINE_MUTEX(thermal_list_lock);
  59
  60static int get_idr(struct idr *idr, struct mutex *lock, int *id)
  61{
  62        int err;
  63
  64      again:
  65        if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
  66                return -ENOMEM;
  67
  68        if (lock)
  69                mutex_lock(lock);
  70        err = idr_get_new(idr, NULL, id);
  71        if (lock)
  72                mutex_unlock(lock);
  73        if (unlikely(err == -EAGAIN))
  74                goto again;
  75        else if (unlikely(err))
  76                return err;
  77
  78        *id = *id & MAX_ID_MASK;
  79        return 0;
  80}
  81
  82static void release_idr(struct idr *idr, struct mutex *lock, int id)
  83{
  84        if (lock)
  85                mutex_lock(lock);
  86        idr_remove(idr, id);
  87        if (lock)
  88                mutex_unlock(lock);
  89}
  90
  91/* sys I/F for thermal zone */
  92
  93#define to_thermal_zone(_dev) \
  94        container_of(_dev, struct thermal_zone_device, device)
  95
  96static ssize_t
  97type_show(struct device *dev, struct device_attribute *attr, char *buf)
  98{
  99        struct thermal_zone_device *tz = to_thermal_zone(dev);
 100
 101        return sprintf(buf, "%s\n", tz->type);
 102}
 103
 104static ssize_t
 105temp_show(struct device *dev, struct device_attribute *attr, char *buf)
 106{
 107        struct thermal_zone_device *tz = to_thermal_zone(dev);
 108        long temperature;
 109        int ret;
 110
 111        if (!tz->ops->get_temp)
 112                return -EPERM;
 113
 114        ret = tz->ops->get_temp(tz, &temperature);
 115
 116        if (ret)
 117                return ret;
 118
 119        return sprintf(buf, "%ld\n", temperature);
 120}
 121
 122static ssize_t
 123mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 124{
 125        struct thermal_zone_device *tz = to_thermal_zone(dev);
 126        enum thermal_device_mode mode;
 127        int result;
 128
 129        if (!tz->ops->get_mode)
 130                return -EPERM;
 131
 132        result = tz->ops->get_mode(tz, &mode);
 133        if (result)
 134                return result;
 135
 136        return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 137                       : "disabled");
 138}
 139
 140static ssize_t
 141mode_store(struct device *dev, struct device_attribute *attr,
 142           const char *buf, size_t count)
 143{
 144        struct thermal_zone_device *tz = to_thermal_zone(dev);
 145        int result;
 146
 147        if (!tz->ops->set_mode)
 148                return -EPERM;
 149
 150        if (!strncmp(buf, "enabled", sizeof("enabled")))
 151                result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
 152        else if (!strncmp(buf, "disabled", sizeof("disabled")))
 153                result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
 154        else
 155                result = -EINVAL;
 156
 157        if (result)
 158                return result;
 159
 160        return count;
 161}
 162
 163static ssize_t
 164trip_point_type_show(struct device *dev, struct device_attribute *attr,
 165                     char *buf)
 166{
 167        struct thermal_zone_device *tz = to_thermal_zone(dev);
 168        enum thermal_trip_type type;
 169        int trip, result;
 170
 171        if (!tz->ops->get_trip_type)
 172                return -EPERM;
 173
 174        if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
 175                return -EINVAL;
 176
 177        result = tz->ops->get_trip_type(tz, trip, &type);
 178        if (result)
 179                return result;
 180
 181        switch (type) {
 182        case THERMAL_TRIP_CRITICAL:
 183                return sprintf(buf, "critical\n");
 184        case THERMAL_TRIP_HOT:
 185                return sprintf(buf, "hot\n");
 186        case THERMAL_TRIP_PASSIVE:
 187                return sprintf(buf, "passive\n");
 188        case THERMAL_TRIP_ACTIVE:
 189                return sprintf(buf, "active\n");
 190        default:
 191                return sprintf(buf, "unknown\n");
 192        }
 193}
 194
 195static ssize_t
 196trip_point_temp_show(struct device *dev, struct device_attribute *attr,
 197                     char *buf)
 198{
 199        struct thermal_zone_device *tz = to_thermal_zone(dev);
 200        int trip, ret;
 201        long temperature;
 202
 203        if (!tz->ops->get_trip_temp)
 204                return -EPERM;
 205
 206        if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 207                return -EINVAL;
 208
 209        ret = tz->ops->get_trip_temp(tz, trip, &temperature);
 210
 211        if (ret)
 212                return ret;
 213
 214        return sprintf(buf, "%ld\n", temperature);
 215}
 216
 217static ssize_t
 218passive_store(struct device *dev, struct device_attribute *attr,
 219                    const char *buf, size_t count)
 220{
 221        struct thermal_zone_device *tz = to_thermal_zone(dev);
 222        struct thermal_cooling_device *cdev = NULL;
 223        int state;
 224
 225        if (!sscanf(buf, "%d\n", &state))
 226                return -EINVAL;
 227
 228        if (state && !tz->forced_passive) {
 229                mutex_lock(&thermal_list_lock);
 230                list_for_each_entry(cdev, &thermal_cdev_list, node) {
 231                        if (!strncmp("Processor", cdev->type,
 232                                     sizeof("Processor")))
 233                                thermal_zone_bind_cooling_device(tz,
 234                                                                 THERMAL_TRIPS_NONE,
 235                                                                 cdev);
 236                }
 237                mutex_unlock(&thermal_list_lock);
 238        } else if (!state && tz->forced_passive) {
 239                mutex_lock(&thermal_list_lock);
 240                list_for_each_entry(cdev, &thermal_cdev_list, node) {
 241                        if (!strncmp("Processor", cdev->type,
 242                                     sizeof("Processor")))
 243                                thermal_zone_unbind_cooling_device(tz,
 244                                                                   THERMAL_TRIPS_NONE,
 245                                                                   cdev);
 246                }
 247                mutex_unlock(&thermal_list_lock);
 248        }
 249
 250        tz->tc1 = 1;
 251        tz->tc2 = 1;
 252
 253        if (!tz->passive_delay)
 254                tz->passive_delay = 1000;
 255
 256        if (!tz->polling_delay)
 257                tz->polling_delay = 10000;
 258
 259        tz->forced_passive = state;
 260
 261        thermal_zone_device_update(tz);
 262
 263        return count;
 264}
 265
 266static ssize_t
 267passive_show(struct device *dev, struct device_attribute *attr,
 268                   char *buf)
 269{
 270        struct thermal_zone_device *tz = to_thermal_zone(dev);
 271
 272        return sprintf(buf, "%d\n", tz->forced_passive);
 273}
 274
 275static DEVICE_ATTR(type, 0444, type_show, NULL);
 276static DEVICE_ATTR(temp, 0444, temp_show, NULL);
 277static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
 278static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
 279                   passive_store);
 280
 281static struct device_attribute trip_point_attrs[] = {
 282        __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
 283        __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
 284        __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
 285        __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
 286        __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
 287        __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
 288        __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
 289        __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
 290        __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
 291        __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
 292        __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
 293        __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
 294        __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
 295        __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
 296        __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
 297        __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
 298        __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
 299        __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
 300        __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
 301        __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
 302        __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL),
 303        __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL),
 304        __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL),
 305        __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
 306};
 307
 308#define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
 309do {    \
 310        result = device_create_file(_dev,       \
 311                                &trip_point_attrs[_index * 2]); \
 312        if (result)     \
 313                break;  \
 314        result = device_create_file(_dev,       \
 315                        &trip_point_attrs[_index * 2 + 1]);     \
 316} while (0)
 317
 318#define TRIP_POINT_ATTR_REMOVE(_dev, _index)    \
 319do {    \
 320        device_remove_file(_dev, &trip_point_attrs[_index * 2]);        \
 321        device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);    \
 322} while (0)
 323
 324/* sys I/F for cooling device */
 325#define to_cooling_device(_dev) \
 326        container_of(_dev, struct thermal_cooling_device, device)
 327
 328static ssize_t
 329thermal_cooling_device_type_show(struct device *dev,
 330                                 struct device_attribute *attr, char *buf)
 331{
 332        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 333
 334        return sprintf(buf, "%s\n", cdev->type);
 335}
 336
 337static ssize_t
 338thermal_cooling_device_max_state_show(struct device *dev,
 339                                      struct device_attribute *attr, char *buf)
 340{
 341        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 342        unsigned long state;
 343        int ret;
 344
 345        ret = cdev->ops->get_max_state(cdev, &state);
 346        if (ret)
 347                return ret;
 348        return sprintf(buf, "%ld\n", state);
 349}
 350
 351static ssize_t
 352thermal_cooling_device_cur_state_show(struct device *dev,
 353                                      struct device_attribute *attr, char *buf)
 354{
 355        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 356        unsigned long state;
 357        int ret;
 358
 359        ret = cdev->ops->get_cur_state(cdev, &state);
 360        if (ret)
 361                return ret;
 362        return sprintf(buf, "%ld\n", state);
 363}
 364
 365static ssize_t
 366thermal_cooling_device_cur_state_store(struct device *dev,
 367                                       struct device_attribute *attr,
 368                                       const char *buf, size_t count)
 369{
 370        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 371        unsigned long state;
 372        int result;
 373
 374        if (!sscanf(buf, "%ld\n", &state))
 375                return -EINVAL;
 376
 377        if (state < 0)
 378                return -EINVAL;
 379
 380        result = cdev->ops->set_cur_state(cdev, state);
 381        if (result)
 382                return result;
 383        return count;
 384}
 385
 386static struct device_attribute dev_attr_cdev_type =
 387__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
 388static DEVICE_ATTR(max_state, 0444,
 389                   thermal_cooling_device_max_state_show, NULL);
 390static DEVICE_ATTR(cur_state, 0644,
 391                   thermal_cooling_device_cur_state_show,
 392                   thermal_cooling_device_cur_state_store);
 393
 394static ssize_t
 395thermal_cooling_device_trip_point_show(struct device *dev,
 396                                       struct device_attribute *attr, char *buf)
 397{
 398        struct thermal_cooling_device_instance *instance;
 399
 400        instance =
 401            container_of(attr, struct thermal_cooling_device_instance, attr);
 402
 403        if (instance->trip == THERMAL_TRIPS_NONE)
 404                return sprintf(buf, "-1\n");
 405        else
 406                return sprintf(buf, "%d\n", instance->trip);
 407}
 408
 409/* Device management */
 410
 411#if defined(CONFIG_THERMAL_HWMON)
 412
 413/* hwmon sys I/F */
 414#include <linux/hwmon.h>
 415static LIST_HEAD(thermal_hwmon_list);
 416
 417static ssize_t
 418name_show(struct device *dev, struct device_attribute *attr, char *buf)
 419{
 420        struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
 421        return sprintf(buf, "%s\n", hwmon->type);
 422}
 423static DEVICE_ATTR(name, 0444, name_show, NULL);
 424
 425static ssize_t
 426temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
 427{
 428        long temperature;
 429        int ret;
 430        struct thermal_hwmon_attr *hwmon_attr
 431                        = container_of(attr, struct thermal_hwmon_attr, attr);
 432        struct thermal_zone_device *tz
 433                        = container_of(hwmon_attr, struct thermal_zone_device,
 434                                       temp_input);
 435
 436        ret = tz->ops->get_temp(tz, &temperature);
 437
 438        if (ret)
 439                return ret;
 440
 441        return sprintf(buf, "%ld\n", temperature);
 442}
 443
 444static ssize_t
 445temp_crit_show(struct device *dev, struct device_attribute *attr,
 446                char *buf)
 447{
 448        struct thermal_hwmon_attr *hwmon_attr
 449                        = container_of(attr, struct thermal_hwmon_attr, attr);
 450        struct thermal_zone_device *tz
 451                        = container_of(hwmon_attr, struct thermal_zone_device,
 452                                       temp_crit);
 453        long temperature;
 454        int ret;
 455
 456        ret = tz->ops->get_trip_temp(tz, 0, &temperature);
 457        if (ret)
 458                return ret;
 459
 460        return sprintf(buf, "%ld\n", temperature);
 461}
 462
 463
 464static int
 465thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 466{
 467        struct thermal_hwmon_device *hwmon;
 468        int new_hwmon_device = 1;
 469        int result;
 470
 471        mutex_lock(&thermal_list_lock);
 472        list_for_each_entry(hwmon, &thermal_hwmon_list, node)
 473                if (!strcmp(hwmon->type, tz->type)) {
 474                        new_hwmon_device = 0;
 475                        mutex_unlock(&thermal_list_lock);
 476                        goto register_sys_interface;
 477                }
 478        mutex_unlock(&thermal_list_lock);
 479
 480        hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
 481        if (!hwmon)
 482                return -ENOMEM;
 483
 484        INIT_LIST_HEAD(&hwmon->tz_list);
 485        strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
 486        hwmon->device = hwmon_device_register(NULL);
 487        if (IS_ERR(hwmon->device)) {
 488                result = PTR_ERR(hwmon->device);
 489                goto free_mem;
 490        }
 491        dev_set_drvdata(hwmon->device, hwmon);
 492        result = device_create_file(hwmon->device, &dev_attr_name);
 493        if (result)
 494                goto unregister_hwmon_device;
 495
 496 register_sys_interface:
 497        tz->hwmon = hwmon;
 498        hwmon->count++;
 499
 500        snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
 501                 "temp%d_input", hwmon->count);
 502        tz->temp_input.attr.attr.name = tz->temp_input.name;
 503        tz->temp_input.attr.attr.mode = 0444;
 504        tz->temp_input.attr.show = temp_input_show;
 505        result = device_create_file(hwmon->device, &tz->temp_input.attr);
 506        if (result)
 507                goto unregister_hwmon_device;
 508
 509        if (tz->ops->get_crit_temp) {
 510                unsigned long temperature;
 511                if (!tz->ops->get_crit_temp(tz, &temperature)) {
 512                        snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
 513                                "temp%d_crit", hwmon->count);
 514                        tz->temp_crit.attr.attr.name = tz->temp_crit.name;
 515                        tz->temp_crit.attr.attr.mode = 0444;
 516                        tz->temp_crit.attr.show = temp_crit_show;
 517                        result = device_create_file(hwmon->device,
 518                                                    &tz->temp_crit.attr);
 519                        if (result)
 520                                goto unregister_hwmon_device;
 521                }
 522        }
 523
 524        mutex_lock(&thermal_list_lock);
 525        if (new_hwmon_device)
 526                list_add_tail(&hwmon->node, &thermal_hwmon_list);
 527        list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
 528        mutex_unlock(&thermal_list_lock);
 529
 530        return 0;
 531
 532 unregister_hwmon_device:
 533        device_remove_file(hwmon->device, &tz->temp_crit.attr);
 534        device_remove_file(hwmon->device, &tz->temp_input.attr);
 535        if (new_hwmon_device) {
 536                device_remove_file(hwmon->device, &dev_attr_name);
 537                hwmon_device_unregister(hwmon->device);
 538        }
 539 free_mem:
 540        if (new_hwmon_device)
 541                kfree(hwmon);
 542
 543        return result;
 544}
 545
 546static void
 547thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 548{
 549        struct thermal_hwmon_device *hwmon = tz->hwmon;
 550
 551        tz->hwmon = NULL;
 552        device_remove_file(hwmon->device, &tz->temp_input.attr);
 553        device_remove_file(hwmon->device, &tz->temp_crit.attr);
 554
 555        mutex_lock(&thermal_list_lock);
 556        list_del(&tz->hwmon_node);
 557        if (!list_empty(&hwmon->tz_list)) {
 558                mutex_unlock(&thermal_list_lock);
 559                return;
 560        }
 561        list_del(&hwmon->node);
 562        mutex_unlock(&thermal_list_lock);
 563
 564        device_remove_file(hwmon->device, &dev_attr_name);
 565        hwmon_device_unregister(hwmon->device);
 566        kfree(hwmon);
 567}
 568#else
 569static int
 570thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 571{
 572        return 0;
 573}
 574
 575static void
 576thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 577{
 578}
 579#endif
 580
 581static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 582                                            int delay)
 583{
 584        cancel_delayed_work(&(tz->poll_queue));
 585
 586        if (!delay)
 587                return;
 588
 589        if (delay > 1000)
 590                schedule_delayed_work(&(tz->poll_queue),
 591                                      round_jiffies(msecs_to_jiffies(delay)));
 592        else
 593                schedule_delayed_work(&(tz->poll_queue),
 594                                      msecs_to_jiffies(delay));
 595}
 596
 597static void thermal_zone_device_passive(struct thermal_zone_device *tz,
 598                                        int temp, int trip_temp, int trip)
 599{
 600        int trend = 0;
 601        struct thermal_cooling_device_instance *instance;
 602        struct thermal_cooling_device *cdev;
 603        long state, max_state;
 604
 605        /*
 606         * Above Trip?
 607         * -----------
 608         * Calculate the thermal trend (using the passive cooling equation)
 609         * and modify the performance limit for all passive cooling devices
 610         * accordingly.  Note that we assume symmetry.
 611         */
 612        if (temp >= trip_temp) {
 613                tz->passive = true;
 614
 615                trend = (tz->tc1 * (temp - tz->last_temperature)) +
 616                        (tz->tc2 * (temp - trip_temp));
 617
 618                /* Heating up? */
 619                if (trend > 0) {
 620                        list_for_each_entry(instance, &tz->cooling_devices,
 621                                            node) {
 622                                if (instance->trip != trip)
 623                                        continue;
 624                                cdev = instance->cdev;
 625                                cdev->ops->get_cur_state(cdev, &state);
 626                                cdev->ops->get_max_state(cdev, &max_state);
 627                                if (state++ < max_state)
 628                                        cdev->ops->set_cur_state(cdev, state);
 629                        }
 630                } else if (trend < 0) { /* Cooling off? */
 631                        list_for_each_entry(instance, &tz->cooling_devices,
 632                                            node) {
 633                                if (instance->trip != trip)
 634                                        continue;
 635                                cdev = instance->cdev;
 636                                cdev->ops->get_cur_state(cdev, &state);
 637                                cdev->ops->get_max_state(cdev, &max_state);
 638                                if (state > 0)
 639                                        cdev->ops->set_cur_state(cdev, --state);
 640                        }
 641                }
 642                return;
 643        }
 644
 645        /*
 646         * Below Trip?
 647         * -----------
 648         * Implement passive cooling hysteresis to slowly increase performance
 649         * and avoid thrashing around the passive trip point.  Note that we
 650         * assume symmetry.
 651         */
 652        list_for_each_entry(instance, &tz->cooling_devices, node) {
 653                if (instance->trip != trip)
 654                        continue;
 655                cdev = instance->cdev;
 656                cdev->ops->get_cur_state(cdev, &state);
 657                cdev->ops->get_max_state(cdev, &max_state);
 658                if (state > 0)
 659                        cdev->ops->set_cur_state(cdev, --state);
 660                if (state == 0)
 661                        tz->passive = false;
 662        }
 663}
 664
 665static void thermal_zone_device_check(struct work_struct *work)
 666{
 667        struct thermal_zone_device *tz = container_of(work, struct
 668                                                      thermal_zone_device,
 669                                                      poll_queue.work);
 670        thermal_zone_device_update(tz);
 671}
 672
 673/**
 674 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
 675 * @tz:         thermal zone device
 676 * @trip:       indicates which trip point the cooling devices is
 677 *              associated with in this thermal zone.
 678 * @cdev:       thermal cooling device
 679 *
 680 * This function is usually called in the thermal zone device .bind callback.
 681 */
 682int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
 683                                     int trip,
 684                                     struct thermal_cooling_device *cdev)
 685{
 686        struct thermal_cooling_device_instance *dev;
 687        struct thermal_cooling_device_instance *pos;
 688        struct thermal_zone_device *pos1;
 689        struct thermal_cooling_device *pos2;
 690        int result;
 691
 692        if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
 693                return -EINVAL;
 694
 695        list_for_each_entry(pos1, &thermal_tz_list, node) {
 696                if (pos1 == tz)
 697                        break;
 698        }
 699        list_for_each_entry(pos2, &thermal_cdev_list, node) {
 700                if (pos2 == cdev)
 701                        break;
 702        }
 703
 704        if (tz != pos1 || cdev != pos2)
 705                return -EINVAL;
 706
 707        dev =
 708            kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
 709        if (!dev)
 710                return -ENOMEM;
 711        dev->tz = tz;
 712        dev->cdev = cdev;
 713        dev->trip = trip;
 714        result = get_idr(&tz->idr, &tz->lock, &dev->id);
 715        if (result)
 716                goto free_mem;
 717
 718        sprintf(dev->name, "cdev%d", dev->id);
 719        result =
 720            sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
 721        if (result)
 722                goto release_idr;
 723
 724        sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
 725        dev->attr.attr.name = dev->attr_name;
 726        dev->attr.attr.mode = 0444;
 727        dev->attr.show = thermal_cooling_device_trip_point_show;
 728        result = device_create_file(&tz->device, &dev->attr);
 729        if (result)
 730                goto remove_symbol_link;
 731
 732        mutex_lock(&tz->lock);
 733        list_for_each_entry(pos, &tz->cooling_devices, node)
 734            if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
 735                result = -EEXIST;
 736                break;
 737        }
 738        if (!result)
 739                list_add_tail(&dev->node, &tz->cooling_devices);
 740        mutex_unlock(&tz->lock);
 741
 742        if (!result)
 743                return 0;
 744
 745        device_remove_file(&tz->device, &dev->attr);
 746      remove_symbol_link:
 747        sysfs_remove_link(&tz->device.kobj, dev->name);
 748      release_idr:
 749        release_idr(&tz->idr, &tz->lock, dev->id);
 750      free_mem:
 751        kfree(dev);
 752        return result;
 753}
 754
 755EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
 756
 757/**
 758 * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
 759 * @tz:         thermal zone device
 760 * @trip:       indicates which trip point the cooling devices is
 761 *              associated with in this thermal zone.
 762 * @cdev:       thermal cooling device
 763 *
 764 * This function is usually called in the thermal zone device .unbind callback.
 765 */
 766int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
 767                                       int trip,
 768                                       struct thermal_cooling_device *cdev)
 769{
 770        struct thermal_cooling_device_instance *pos, *next;
 771
 772        mutex_lock(&tz->lock);
 773        list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
 774                if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
 775                        list_del(&pos->node);
 776                        mutex_unlock(&tz->lock);
 777                        goto unbind;
 778                }
 779        }
 780        mutex_unlock(&tz->lock);
 781
 782        return -ENODEV;
 783
 784      unbind:
 785        device_remove_file(&tz->device, &pos->attr);
 786        sysfs_remove_link(&tz->device.kobj, pos->name);
 787        release_idr(&tz->idr, &tz->lock, pos->id);
 788        kfree(pos);
 789        return 0;
 790}
 791
 792EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
 793
 794static void thermal_release(struct device *dev)
 795{
 796        struct thermal_zone_device *tz;
 797        struct thermal_cooling_device *cdev;
 798
 799        if (!strncmp(dev_name(dev), "thermal_zone", sizeof "thermal_zone" - 1)) {
 800                tz = to_thermal_zone(dev);
 801                kfree(tz);
 802        } else {
 803                cdev = to_cooling_device(dev);
 804                kfree(cdev);
 805        }
 806}
 807
 808static struct class thermal_class = {
 809        .name = "thermal",
 810        .dev_release = thermal_release,
 811};
 812
 813/**
 814 * thermal_cooling_device_register - register a new thermal cooling device
 815 * @type:       the thermal cooling device type.
 816 * @devdata:    device private data.
 817 * @ops:                standard thermal cooling devices callbacks.
 818 */
 819struct thermal_cooling_device *thermal_cooling_device_register(char *type,
 820                                                               void *devdata,
 821                                                               struct
 822                                                               thermal_cooling_device_ops
 823                                                               *ops)
 824{
 825        struct thermal_cooling_device *cdev;
 826        struct thermal_zone_device *pos;
 827        int result;
 828
 829        if (strlen(type) >= THERMAL_NAME_LENGTH)
 830                return ERR_PTR(-EINVAL);
 831
 832        if (!ops || !ops->get_max_state || !ops->get_cur_state ||
 833            !ops->set_cur_state)
 834                return ERR_PTR(-EINVAL);
 835
 836        cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
 837        if (!cdev)
 838                return ERR_PTR(-ENOMEM);
 839
 840        result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
 841        if (result) {
 842                kfree(cdev);
 843                return ERR_PTR(result);
 844        }
 845
 846        strcpy(cdev->type, type);
 847        cdev->ops = ops;
 848        cdev->device.class = &thermal_class;
 849        cdev->devdata = devdata;
 850        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
 851        result = device_register(&cdev->device);
 852        if (result) {
 853                release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
 854                kfree(cdev);
 855                return ERR_PTR(result);
 856        }
 857
 858        /* sys I/F */
 859        if (type) {
 860                result = device_create_file(&cdev->device, &dev_attr_cdev_type);
 861                if (result)
 862                        goto unregister;
 863        }
 864
 865        result = device_create_file(&cdev->device, &dev_attr_max_state);
 866        if (result)
 867                goto unregister;
 868
 869        result = device_create_file(&cdev->device, &dev_attr_cur_state);
 870        if (result)
 871                goto unregister;
 872
 873        mutex_lock(&thermal_list_lock);
 874        list_add(&cdev->node, &thermal_cdev_list);
 875        list_for_each_entry(pos, &thermal_tz_list, node) {
 876                if (!pos->ops->bind)
 877                        continue;
 878                result = pos->ops->bind(pos, cdev);
 879                if (result)
 880                        break;
 881
 882        }
 883        mutex_unlock(&thermal_list_lock);
 884
 885        if (!result)
 886                return cdev;
 887
 888      unregister:
 889        release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
 890        device_unregister(&cdev->device);
 891        return ERR_PTR(result);
 892}
 893
 894EXPORT_SYMBOL(thermal_cooling_device_register);
 895
 896/**
 897 * thermal_cooling_device_unregister - removes the registered thermal cooling device
 898 * @cdev:       the thermal cooling device to remove.
 899 *
 900 * thermal_cooling_device_unregister() must be called when the device is no
 901 * longer needed.
 902 */
 903void thermal_cooling_device_unregister(struct
 904                                       thermal_cooling_device
 905                                       *cdev)
 906{
 907        struct thermal_zone_device *tz;
 908        struct thermal_cooling_device *pos = NULL;
 909
 910        if (!cdev)
 911                return;
 912
 913        mutex_lock(&thermal_list_lock);
 914        list_for_each_entry(pos, &thermal_cdev_list, node)
 915            if (pos == cdev)
 916                break;
 917        if (pos != cdev) {
 918                /* thermal cooling device not found */
 919                mutex_unlock(&thermal_list_lock);
 920                return;
 921        }
 922        list_del(&cdev->node);
 923        list_for_each_entry(tz, &thermal_tz_list, node) {
 924                if (!tz->ops->unbind)
 925                        continue;
 926                tz->ops->unbind(tz, cdev);
 927        }
 928        mutex_unlock(&thermal_list_lock);
 929        if (cdev->type[0])
 930                device_remove_file(&cdev->device, &dev_attr_cdev_type);
 931        device_remove_file(&cdev->device, &dev_attr_max_state);
 932        device_remove_file(&cdev->device, &dev_attr_cur_state);
 933
 934        release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
 935        device_unregister(&cdev->device);
 936        return;
 937}
 938
 939EXPORT_SYMBOL(thermal_cooling_device_unregister);
 940
 941/**
 942 * thermal_zone_device_update - force an update of a thermal zone's state
 943 * @ttz:        the thermal zone to update
 944 */
 945
 946void thermal_zone_device_update(struct thermal_zone_device *tz)
 947{
 948        int count, ret = 0;
 949        long temp, trip_temp;
 950        enum thermal_trip_type trip_type;
 951        struct thermal_cooling_device_instance *instance;
 952        struct thermal_cooling_device *cdev;
 953
 954        mutex_lock(&tz->lock);
 955
 956        if (tz->ops->get_temp(tz, &temp)) {
 957                /* get_temp failed - retry it later */
 958                printk(KERN_WARNING PREFIX "failed to read out thermal zone "
 959                       "%d\n", tz->id);
 960                goto leave;
 961        }
 962
 963        for (count = 0; count < tz->trips; count++) {
 964                tz->ops->get_trip_type(tz, count, &trip_type);
 965                tz->ops->get_trip_temp(tz, count, &trip_temp);
 966
 967                switch (trip_type) {
 968                case THERMAL_TRIP_CRITICAL:
 969                        if (temp >= trip_temp) {
 970                                if (tz->ops->notify)
 971                                        ret = tz->ops->notify(tz, count,
 972                                                              trip_type);
 973                                if (!ret) {
 974                                        printk(KERN_EMERG
 975                                               "Critical temperature reached (%ld C), shutting down.\n",
 976                                               temp/1000);
 977                                        orderly_poweroff(true);
 978                                }
 979                        }
 980                        break;
 981                case THERMAL_TRIP_HOT:
 982                        if (temp >= trip_temp)
 983                                if (tz->ops->notify)
 984                                        tz->ops->notify(tz, count, trip_type);
 985                        break;
 986                case THERMAL_TRIP_ACTIVE:
 987                        list_for_each_entry(instance, &tz->cooling_devices,
 988                                            node) {
 989                                if (instance->trip != count)
 990                                        continue;
 991
 992                                cdev = instance->cdev;
 993
 994                                if (temp >= trip_temp)
 995                                        cdev->ops->set_cur_state(cdev, 1);
 996                                else
 997                                        cdev->ops->set_cur_state(cdev, 0);
 998                        }
 999                        break;
1000                case THERMAL_TRIP_PASSIVE:
1001                        if (temp >= trip_temp || tz->passive)
1002                                thermal_zone_device_passive(tz, temp,
1003                                                            trip_temp, count);
1004                        break;
1005                }
1006        }
1007
1008        if (tz->forced_passive)
1009                thermal_zone_device_passive(tz, temp, tz->forced_passive,
1010                                            THERMAL_TRIPS_NONE);
1011
1012        tz->last_temperature = temp;
1013
1014      leave:
1015        if (tz->passive)
1016                thermal_zone_device_set_polling(tz, tz->passive_delay);
1017        else if (tz->polling_delay)
1018                thermal_zone_device_set_polling(tz, tz->polling_delay);
1019        mutex_unlock(&tz->lock);
1020}
1021EXPORT_SYMBOL(thermal_zone_device_update);
1022
1023/**
1024 * thermal_zone_device_register - register a new thermal zone device
1025 * @type:       the thermal zone device type
1026 * @trips:      the number of trip points the thermal zone support
1027 * @devdata:    private device data
1028 * @ops:        standard thermal zone device callbacks
1029 * @tc1:        thermal coefficient 1 for passive calculations
1030 * @tc2:        thermal coefficient 2 for passive calculations
1031 * @passive_delay: number of milliseconds to wait between polls when
1032 *                 performing passive cooling
1033 * @polling_delay: number of milliseconds to wait between polls when checking
1034 *                 whether trip points have been crossed (0 for interrupt
1035 *                 driven systems)
1036 *
1037 * thermal_zone_device_unregister() must be called when the device is no
1038 * longer needed. The passive cooling formula uses tc1 and tc2 as described in
1039 * section 11.1.5.1 of the ACPI specification 3.0.
1040 */
1041struct thermal_zone_device *thermal_zone_device_register(char *type,
1042                                                         int trips,
1043                                                         void *devdata, struct
1044                                                         thermal_zone_device_ops
1045                                                         *ops, int tc1, int
1046                                                         tc2,
1047                                                         int passive_delay,
1048                                                         int polling_delay)
1049{
1050        struct thermal_zone_device *tz;
1051        struct thermal_cooling_device *pos;
1052        enum thermal_trip_type trip_type;
1053        int result;
1054        int count;
1055        int passive = 0;
1056
1057        if (strlen(type) >= THERMAL_NAME_LENGTH)
1058                return ERR_PTR(-EINVAL);
1059
1060        if (trips > THERMAL_MAX_TRIPS || trips < 0)
1061                return ERR_PTR(-EINVAL);
1062
1063        if (!ops || !ops->get_temp)
1064                return ERR_PTR(-EINVAL);
1065
1066        tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
1067        if (!tz)
1068                return ERR_PTR(-ENOMEM);
1069
1070        INIT_LIST_HEAD(&tz->cooling_devices);
1071        idr_init(&tz->idr);
1072        mutex_init(&tz->lock);
1073        result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
1074        if (result) {
1075                kfree(tz);
1076                return ERR_PTR(result);
1077        }
1078
1079        strcpy(tz->type, type);
1080        tz->ops = ops;
1081        tz->device.class = &thermal_class;
1082        tz->devdata = devdata;
1083        tz->trips = trips;
1084        tz->tc1 = tc1;
1085        tz->tc2 = tc2;
1086        tz->passive_delay = passive_delay;
1087        tz->polling_delay = polling_delay;
1088
1089        dev_set_name(&tz->device, "thermal_zone%d", tz->id);
1090        result = device_register(&tz->device);
1091        if (result) {
1092                release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
1093                kfree(tz);
1094                return ERR_PTR(result);
1095        }
1096
1097        /* sys I/F */
1098        if (type) {
1099                result = device_create_file(&tz->device, &dev_attr_type);
1100                if (result)
1101                        goto unregister;
1102        }
1103
1104        result = device_create_file(&tz->device, &dev_attr_temp);
1105        if (result)
1106                goto unregister;
1107
1108        if (ops->get_mode) {
1109                result = device_create_file(&tz->device, &dev_attr_mode);
1110                if (result)
1111                        goto unregister;
1112        }
1113
1114        for (count = 0; count < trips; count++) {
1115                TRIP_POINT_ATTR_ADD(&tz->device, count, result);
1116                if (result)
1117                        goto unregister;
1118                tz->ops->get_trip_type(tz, count, &trip_type);
1119                if (trip_type == THERMAL_TRIP_PASSIVE)
1120                        passive = 1;
1121        }
1122
1123        if (!passive)
1124                result = device_create_file(&tz->device,
1125                                            &dev_attr_passive);
1126
1127        if (result)
1128                goto unregister;
1129
1130        result = thermal_add_hwmon_sysfs(tz);
1131        if (result)
1132                goto unregister;
1133
1134        mutex_lock(&thermal_list_lock);
1135        list_add_tail(&tz->node, &thermal_tz_list);
1136        if (ops->bind)
1137                list_for_each_entry(pos, &thermal_cdev_list, node) {
1138                result = ops->bind(tz, pos);
1139                if (result)
1140                        break;
1141                }
1142        mutex_unlock(&thermal_list_lock);
1143
1144        INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1145
1146        thermal_zone_device_update(tz);
1147
1148        if (!result)
1149                return tz;
1150
1151      unregister:
1152        release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
1153        device_unregister(&tz->device);
1154        return ERR_PTR(result);
1155}
1156
1157EXPORT_SYMBOL(thermal_zone_device_register);
1158
1159/**
1160 * thermal_device_unregister - removes the registered thermal zone device
1161 * @tz: the thermal zone device to remove
1162 */
1163void thermal_zone_device_unregister(struct thermal_zone_device *tz)
1164{
1165        struct thermal_cooling_device *cdev;
1166        struct thermal_zone_device *pos = NULL;
1167        int count;
1168
1169        if (!tz)
1170                return;
1171
1172        mutex_lock(&thermal_list_lock);
1173        list_for_each_entry(pos, &thermal_tz_list, node)
1174            if (pos == tz)
1175                break;
1176        if (pos != tz) {
1177                /* thermal zone device not found */
1178                mutex_unlock(&thermal_list_lock);
1179                return;
1180        }
1181        list_del(&tz->node);
1182        if (tz->ops->unbind)
1183                list_for_each_entry(cdev, &thermal_cdev_list, node)
1184                    tz->ops->unbind(tz, cdev);
1185        mutex_unlock(&thermal_list_lock);
1186
1187        thermal_zone_device_set_polling(tz, 0);
1188
1189        if (tz->type[0])
1190                device_remove_file(&tz->device, &dev_attr_type);
1191        device_remove_file(&tz->device, &dev_attr_temp);
1192        if (tz->ops->get_mode)
1193                device_remove_file(&tz->device, &dev_attr_mode);
1194
1195        for (count = 0; count < tz->trips; count++)
1196                TRIP_POINT_ATTR_REMOVE(&tz->device, count);
1197
1198        thermal_remove_hwmon_sysfs(tz);
1199        release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
1200        idr_destroy(&tz->idr);
1201        mutex_destroy(&tz->lock);
1202        device_unregister(&tz->device);
1203        return;
1204}
1205
1206EXPORT_SYMBOL(thermal_zone_device_unregister);
1207
1208static int __init thermal_init(void)
1209{
1210        int result = 0;
1211
1212        result = class_register(&thermal_class);
1213        if (result) {
1214                idr_destroy(&thermal_tz_idr);
1215                idr_destroy(&thermal_cdev_idr);
1216                mutex_destroy(&thermal_idr_lock);
1217                mutex_destroy(&thermal_list_lock);
1218        }
1219        return result;
1220}
1221
1222static void __exit thermal_exit(void)
1223{
1224        class_unregister(&thermal_class);
1225        idr_destroy(&thermal_tz_idr);
1226        idr_destroy(&thermal_cdev_idr);
1227        mutex_destroy(&thermal_idr_lock);
1228        mutex_destroy(&thermal_list_lock);
1229}
1230
1231subsys_initcall(thermal_init);
1232module_exit(thermal_exit);
1233
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.