linux/drivers/thermal/thermal_sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  thermal.c - sysfs interface of thermal devices
   4 *
   5 *  Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com>
   6 *
   7 *  Highly based on original thermal_core.c
   8 *  Copyright (C) 2008 Intel Corp
   9 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
  10 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
  11 */
  12
  13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14
  15#include <linux/sysfs.h>
  16#include <linux/device.h>
  17#include <linux/err.h>
  18#include <linux/slab.h>
  19#include <linux/string.h>
  20#include <linux/jiffies.h>
  21
  22#include "thermal_core.h"
  23
  24/* sys I/F for thermal zone */
  25
  26static ssize_t
  27type_show(struct device *dev, struct device_attribute *attr, char *buf)
  28{
  29        struct thermal_zone_device *tz = to_thermal_zone(dev);
  30
  31        return sprintf(buf, "%s\n", tz->type);
  32}
  33
  34static ssize_t
  35temp_show(struct device *dev, struct device_attribute *attr, char *buf)
  36{
  37        struct thermal_zone_device *tz = to_thermal_zone(dev);
  38        int temperature, ret;
  39
  40        ret = thermal_zone_get_temp(tz, &temperature);
  41
  42        if (ret)
  43                return ret;
  44
  45        return sprintf(buf, "%d\n", temperature);
  46}
  47
  48static ssize_t
  49mode_show(struct device *dev, struct device_attribute *attr, char *buf)
  50{
  51        struct thermal_zone_device *tz = to_thermal_zone(dev);
  52        int enabled = thermal_zone_device_is_enabled(tz);
  53
  54        return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
  55}
  56
  57static ssize_t
  58mode_store(struct device *dev, struct device_attribute *attr,
  59           const char *buf, size_t count)
  60{
  61        struct thermal_zone_device *tz = to_thermal_zone(dev);
  62        int result;
  63
  64        if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
  65                result = thermal_zone_device_enable(tz);
  66        else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
  67                result = thermal_zone_device_disable(tz);
  68        else
  69                result = -EINVAL;
  70
  71        if (result)
  72                return result;
  73
  74        return count;
  75}
  76
  77static ssize_t
  78trip_point_type_show(struct device *dev, struct device_attribute *attr,
  79                     char *buf)
  80{
  81        struct thermal_zone_device *tz = to_thermal_zone(dev);
  82        enum thermal_trip_type type;
  83        int trip, result;
  84
  85        if (!tz->ops->get_trip_type)
  86                return -EPERM;
  87
  88        if (sscanf(attr->attr.name, "trip_point_%d_type", &trip) != 1)
  89                return -EINVAL;
  90
  91        result = tz->ops->get_trip_type(tz, trip, &type);
  92        if (result)
  93                return result;
  94
  95        switch (type) {
  96        case THERMAL_TRIP_CRITICAL:
  97                return sprintf(buf, "critical\n");
  98        case THERMAL_TRIP_HOT:
  99                return sprintf(buf, "hot\n");
 100        case THERMAL_TRIP_PASSIVE:
 101                return sprintf(buf, "passive\n");
 102        case THERMAL_TRIP_ACTIVE:
 103                return sprintf(buf, "active\n");
 104        default:
 105                return sprintf(buf, "unknown\n");
 106        }
 107}
 108
 109static ssize_t
 110trip_point_temp_store(struct device *dev, struct device_attribute *attr,
 111                      const char *buf, size_t count)
 112{
 113        struct thermal_zone_device *tz = to_thermal_zone(dev);
 114        int trip, ret;
 115        int temperature, hyst = 0;
 116        enum thermal_trip_type type;
 117
 118        if (!tz->ops->set_trip_temp)
 119                return -EPERM;
 120
 121        if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1)
 122                return -EINVAL;
 123
 124        if (kstrtoint(buf, 10, &temperature))
 125                return -EINVAL;
 126
 127        ret = tz->ops->set_trip_temp(tz, trip, temperature);
 128        if (ret)
 129                return ret;
 130
 131        if (tz->ops->get_trip_hyst) {
 132                ret = tz->ops->get_trip_hyst(tz, trip, &hyst);
 133                if (ret)
 134                        return ret;
 135        }
 136
 137        ret = tz->ops->get_trip_type(tz, trip, &type);
 138        if (ret)
 139                return ret;
 140
 141        thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst);
 142
 143        thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 144
 145        return count;
 146}
 147
 148static ssize_t
 149trip_point_temp_show(struct device *dev, struct device_attribute *attr,
 150                     char *buf)
 151{
 152        struct thermal_zone_device *tz = to_thermal_zone(dev);
 153        int trip, ret;
 154        int temperature;
 155
 156        if (!tz->ops->get_trip_temp)
 157                return -EPERM;
 158
 159        if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1)
 160                return -EINVAL;
 161
 162        ret = tz->ops->get_trip_temp(tz, trip, &temperature);
 163
 164        if (ret)
 165                return ret;
 166
 167        return sprintf(buf, "%d\n", temperature);
 168}
 169
 170static ssize_t
 171trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
 172                      const char *buf, size_t count)
 173{
 174        struct thermal_zone_device *tz = to_thermal_zone(dev);
 175        int trip, ret;
 176        int temperature;
 177
 178        if (!tz->ops->set_trip_hyst)
 179                return -EPERM;
 180
 181        if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1)
 182                return -EINVAL;
 183
 184        if (kstrtoint(buf, 10, &temperature))
 185                return -EINVAL;
 186
 187        /*
 188         * We are not doing any check on the 'temperature' value
 189         * here. The driver implementing 'set_trip_hyst' has to
 190         * take care of this.
 191         */
 192        ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 193
 194        if (!ret)
 195                thermal_zone_set_trips(tz);
 196
 197        return ret ? ret : count;
 198}
 199
 200static ssize_t
 201trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
 202                     char *buf)
 203{
 204        struct thermal_zone_device *tz = to_thermal_zone(dev);
 205        int trip, ret;
 206        int temperature;
 207
 208        if (!tz->ops->get_trip_hyst)
 209                return -EPERM;
 210
 211        if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1)
 212                return -EINVAL;
 213
 214        ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
 215
 216        return ret ? ret : sprintf(buf, "%d\n", temperature);
 217}
 218
 219static ssize_t
 220policy_store(struct device *dev, struct device_attribute *attr,
 221             const char *buf, size_t count)
 222{
 223        struct thermal_zone_device *tz = to_thermal_zone(dev);
 224        char name[THERMAL_NAME_LENGTH];
 225        int ret;
 226
 227        snprintf(name, sizeof(name), "%s", buf);
 228
 229        ret = thermal_zone_device_set_policy(tz, name);
 230        if (!ret)
 231                ret = count;
 232
 233        return ret;
 234}
 235
 236static ssize_t
 237policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
 238{
 239        struct thermal_zone_device *tz = to_thermal_zone(dev);
 240
 241        return sprintf(buf, "%s\n", tz->governor->name);
 242}
 243
 244static ssize_t
 245available_policies_show(struct device *dev, struct device_attribute *devattr,
 246                        char *buf)
 247{
 248        return thermal_build_list_of_policies(buf);
 249}
 250
 251#if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
 252static ssize_t
 253emul_temp_store(struct device *dev, struct device_attribute *attr,
 254                const char *buf, size_t count)
 255{
 256        struct thermal_zone_device *tz = to_thermal_zone(dev);
 257        int ret = 0;
 258        int temperature;
 259
 260        if (kstrtoint(buf, 10, &temperature))
 261                return -EINVAL;
 262
 263        if (!tz->ops->set_emul_temp) {
 264                mutex_lock(&tz->lock);
 265                tz->emul_temperature = temperature;
 266                mutex_unlock(&tz->lock);
 267        } else {
 268                ret = tz->ops->set_emul_temp(tz, temperature);
 269        }
 270
 271        if (!ret)
 272                thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 273
 274        return ret ? ret : count;
 275}
 276static DEVICE_ATTR_WO(emul_temp);
 277#endif
 278
 279static ssize_t
 280sustainable_power_show(struct device *dev, struct device_attribute *devattr,
 281                       char *buf)
 282{
 283        struct thermal_zone_device *tz = to_thermal_zone(dev);
 284
 285        if (tz->tzp)
 286                return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
 287        else
 288                return -EIO;
 289}
 290
 291static ssize_t
 292sustainable_power_store(struct device *dev, struct device_attribute *devattr,
 293                        const char *buf, size_t count)
 294{
 295        struct thermal_zone_device *tz = to_thermal_zone(dev);
 296        u32 sustainable_power;
 297
 298        if (!tz->tzp)
 299                return -EIO;
 300
 301        if (kstrtou32(buf, 10, &sustainable_power))
 302                return -EINVAL;
 303
 304        tz->tzp->sustainable_power = sustainable_power;
 305
 306        return count;
 307}
 308
 309#define create_s32_tzp_attr(name)                                       \
 310        static ssize_t                                                  \
 311        name##_show(struct device *dev, struct device_attribute *devattr, \
 312                char *buf)                                              \
 313        {                                                               \
 314        struct thermal_zone_device *tz = to_thermal_zone(dev);          \
 315                                                                        \
 316        if (tz->tzp)                                                    \
 317                return sprintf(buf, "%d\n", tz->tzp->name);             \
 318        else                                                            \
 319                return -EIO;                                            \
 320        }                                                               \
 321                                                                        \
 322        static ssize_t                                                  \
 323        name##_store(struct device *dev, struct device_attribute *devattr, \
 324                const char *buf, size_t count)                          \
 325        {                                                               \
 326                struct thermal_zone_device *tz = to_thermal_zone(dev);  \
 327                s32 value;                                              \
 328                                                                        \
 329                if (!tz->tzp)                                           \
 330                        return -EIO;                                    \
 331                                                                        \
 332                if (kstrtos32(buf, 10, &value))                         \
 333                        return -EINVAL;                                 \
 334                                                                        \
 335                tz->tzp->name = value;                                  \
 336                                                                        \
 337                return count;                                           \
 338        }                                                               \
 339        static DEVICE_ATTR_RW(name)
 340
 341create_s32_tzp_attr(k_po);
 342create_s32_tzp_attr(k_pu);
 343create_s32_tzp_attr(k_i);
 344create_s32_tzp_attr(k_d);
 345create_s32_tzp_attr(integral_cutoff);
 346create_s32_tzp_attr(slope);
 347create_s32_tzp_attr(offset);
 348#undef create_s32_tzp_attr
 349
 350/*
 351 * These are thermal zone device attributes that will always be present.
 352 * All the attributes created for tzp (create_s32_tzp_attr) also are always
 353 * present on the sysfs interface.
 354 */
 355static DEVICE_ATTR_RO(type);
 356static DEVICE_ATTR_RO(temp);
 357static DEVICE_ATTR_RW(policy);
 358static DEVICE_ATTR_RO(available_policies);
 359static DEVICE_ATTR_RW(sustainable_power);
 360
 361/* These thermal zone device attributes are created based on conditions */
 362static DEVICE_ATTR_RW(mode);
 363
 364/* These attributes are unconditionally added to a thermal zone */
 365static struct attribute *thermal_zone_dev_attrs[] = {
 366        &dev_attr_type.attr,
 367        &dev_attr_temp.attr,
 368#if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
 369        &dev_attr_emul_temp.attr,
 370#endif
 371        &dev_attr_policy.attr,
 372        &dev_attr_available_policies.attr,
 373        &dev_attr_sustainable_power.attr,
 374        &dev_attr_k_po.attr,
 375        &dev_attr_k_pu.attr,
 376        &dev_attr_k_i.attr,
 377        &dev_attr_k_d.attr,
 378        &dev_attr_integral_cutoff.attr,
 379        &dev_attr_slope.attr,
 380        &dev_attr_offset.attr,
 381        NULL,
 382};
 383
 384static const struct attribute_group thermal_zone_attribute_group = {
 385        .attrs = thermal_zone_dev_attrs,
 386};
 387
 388static struct attribute *thermal_zone_mode_attrs[] = {
 389        &dev_attr_mode.attr,
 390        NULL,
 391};
 392
 393static const struct attribute_group thermal_zone_mode_attribute_group = {
 394        .attrs = thermal_zone_mode_attrs,
 395};
 396
 397static const struct attribute_group *thermal_zone_attribute_groups[] = {
 398        &thermal_zone_attribute_group,
 399        &thermal_zone_mode_attribute_group,
 400        /* This is not NULL terminated as we create the group dynamically */
 401};
 402
 403/**
 404 * create_trip_attrs() - create attributes for trip points
 405 * @tz:         the thermal zone device
 406 * @mask:       Writeable trip point bitmap.
 407 *
 408 * helper function to instantiate sysfs entries for every trip
 409 * point and its properties of a struct thermal_zone_device.
 410 *
 411 * Return: 0 on success, the proper error value otherwise.
 412 */
 413static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
 414{
 415        struct attribute **attrs;
 416        int indx;
 417
 418        /* This function works only for zones with at least one trip */
 419        if (tz->trips <= 0)
 420                return -EINVAL;
 421
 422        tz->trip_type_attrs = kcalloc(tz->trips, sizeof(*tz->trip_type_attrs),
 423                                      GFP_KERNEL);
 424        if (!tz->trip_type_attrs)
 425                return -ENOMEM;
 426
 427        tz->trip_temp_attrs = kcalloc(tz->trips, sizeof(*tz->trip_temp_attrs),
 428                                      GFP_KERNEL);
 429        if (!tz->trip_temp_attrs) {
 430                kfree(tz->trip_type_attrs);
 431                return -ENOMEM;
 432        }
 433
 434        if (tz->ops->get_trip_hyst) {
 435                tz->trip_hyst_attrs = kcalloc(tz->trips,
 436                                              sizeof(*tz->trip_hyst_attrs),
 437                                              GFP_KERNEL);
 438                if (!tz->trip_hyst_attrs) {
 439                        kfree(tz->trip_type_attrs);
 440                        kfree(tz->trip_temp_attrs);
 441                        return -ENOMEM;
 442                }
 443        }
 444
 445        attrs = kcalloc(tz->trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
 446        if (!attrs) {
 447                kfree(tz->trip_type_attrs);
 448                kfree(tz->trip_temp_attrs);
 449                if (tz->ops->get_trip_hyst)
 450                        kfree(tz->trip_hyst_attrs);
 451                return -ENOMEM;
 452        }
 453
 454        for (indx = 0; indx < tz->trips; indx++) {
 455                /* create trip type attribute */
 456                snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
 457                         "trip_point_%d_type", indx);
 458
 459                sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
 460                tz->trip_type_attrs[indx].attr.attr.name =
 461                                                tz->trip_type_attrs[indx].name;
 462                tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
 463                tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
 464                attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
 465
 466                /* create trip temp attribute */
 467                snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
 468                         "trip_point_%d_temp", indx);
 469
 470                sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
 471                tz->trip_temp_attrs[indx].attr.attr.name =
 472                                                tz->trip_temp_attrs[indx].name;
 473                tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
 474                tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
 475                if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
 476                    mask & (1 << indx)) {
 477                        tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
 478                        tz->trip_temp_attrs[indx].attr.store =
 479                                                        trip_point_temp_store;
 480                }
 481                attrs[indx + tz->trips] = &tz->trip_temp_attrs[indx].attr.attr;
 482
 483                /* create Optional trip hyst attribute */
 484                if (!tz->ops->get_trip_hyst)
 485                        continue;
 486                snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
 487                         "trip_point_%d_hyst", indx);
 488
 489                sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
 490                tz->trip_hyst_attrs[indx].attr.attr.name =
 491                                        tz->trip_hyst_attrs[indx].name;
 492                tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
 493                tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
 494                if (tz->ops->set_trip_hyst) {
 495                        tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
 496                        tz->trip_hyst_attrs[indx].attr.store =
 497                                        trip_point_hyst_store;
 498                }
 499                attrs[indx + tz->trips * 2] =
 500                                        &tz->trip_hyst_attrs[indx].attr.attr;
 501        }
 502        attrs[tz->trips * 3] = NULL;
 503
 504        tz->trips_attribute_group.attrs = attrs;
 505
 506        return 0;
 507}
 508
 509/**
 510 * destroy_trip_attrs() - destroy attributes for trip points
 511 * @tz:         the thermal zone device
 512 *
 513 * helper function to free resources allocated by create_trip_attrs()
 514 */
 515static void destroy_trip_attrs(struct thermal_zone_device *tz)
 516{
 517        if (!tz)
 518                return;
 519
 520        kfree(tz->trip_type_attrs);
 521        kfree(tz->trip_temp_attrs);
 522        if (tz->ops->get_trip_hyst)
 523                kfree(tz->trip_hyst_attrs);
 524        kfree(tz->trips_attribute_group.attrs);
 525}
 526
 527int thermal_zone_create_device_groups(struct thermal_zone_device *tz,
 528                                      int mask)
 529{
 530        const struct attribute_group **groups;
 531        int i, size, result;
 532
 533        /* we need one extra for trips and the NULL to terminate the array */
 534        size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2;
 535        /* This also takes care of API requirement to be NULL terminated */
 536        groups = kcalloc(size, sizeof(*groups), GFP_KERNEL);
 537        if (!groups)
 538                return -ENOMEM;
 539
 540        for (i = 0; i < size - 2; i++)
 541                groups[i] = thermal_zone_attribute_groups[i];
 542
 543        if (tz->trips) {
 544                result = create_trip_attrs(tz, mask);
 545                if (result) {
 546                        kfree(groups);
 547
 548                        return result;
 549                }
 550
 551                groups[size - 2] = &tz->trips_attribute_group;
 552        }
 553
 554        tz->device.groups = groups;
 555
 556        return 0;
 557}
 558
 559void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz)
 560{
 561        if (!tz)
 562                return;
 563
 564        if (tz->trips)
 565                destroy_trip_attrs(tz);
 566
 567        kfree(tz->device.groups);
 568}
 569
 570/* sys I/F for cooling device */
 571static ssize_t
 572cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf)
 573{
 574        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 575
 576        return sprintf(buf, "%s\n", cdev->type);
 577}
 578
 579static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
 580                              char *buf)
 581{
 582        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 583        unsigned long state;
 584        int ret;
 585
 586        ret = cdev->ops->get_max_state(cdev, &state);
 587        if (ret)
 588                return ret;
 589        return sprintf(buf, "%ld\n", state);
 590}
 591
 592static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
 593                              char *buf)
 594{
 595        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 596        unsigned long state;
 597        int ret;
 598
 599        ret = cdev->ops->get_cur_state(cdev, &state);
 600        if (ret)
 601                return ret;
 602        return sprintf(buf, "%ld\n", state);
 603}
 604
 605static ssize_t
 606cur_state_store(struct device *dev, struct device_attribute *attr,
 607                const char *buf, size_t count)
 608{
 609        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 610        unsigned long state;
 611        int result;
 612
 613        if (sscanf(buf, "%ld\n", &state) != 1)
 614                return -EINVAL;
 615
 616        if ((long)state < 0)
 617                return -EINVAL;
 618
 619        mutex_lock(&cdev->lock);
 620
 621        result = cdev->ops->set_cur_state(cdev, state);
 622        if (!result)
 623                thermal_cooling_device_stats_update(cdev, state);
 624
 625        mutex_unlock(&cdev->lock);
 626        return result ? result : count;
 627}
 628
 629static struct device_attribute
 630dev_attr_cdev_type = __ATTR(type, 0444, cdev_type_show, NULL);
 631static DEVICE_ATTR_RO(max_state);
 632static DEVICE_ATTR_RW(cur_state);
 633
 634static struct attribute *cooling_device_attrs[] = {
 635        &dev_attr_cdev_type.attr,
 636        &dev_attr_max_state.attr,
 637        &dev_attr_cur_state.attr,
 638        NULL,
 639};
 640
 641static const struct attribute_group cooling_device_attr_group = {
 642        .attrs = cooling_device_attrs,
 643};
 644
 645static const struct attribute_group *cooling_device_attr_groups[] = {
 646        &cooling_device_attr_group,
 647        NULL, /* Space allocated for cooling_device_stats_attr_group */
 648        NULL,
 649};
 650
 651#ifdef CONFIG_THERMAL_STATISTICS
 652struct cooling_dev_stats {
 653        spinlock_t lock;
 654        unsigned int total_trans;
 655        unsigned long state;
 656        unsigned long max_states;
 657        ktime_t last_time;
 658        ktime_t *time_in_state;
 659        unsigned int *trans_table;
 660};
 661
 662static void update_time_in_state(struct cooling_dev_stats *stats)
 663{
 664        ktime_t now = ktime_get(), delta;
 665
 666        delta = ktime_sub(now, stats->last_time);
 667        stats->time_in_state[stats->state] =
 668                ktime_add(stats->time_in_state[stats->state], delta);
 669        stats->last_time = now;
 670}
 671
 672void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 673                                         unsigned long new_state)
 674{
 675        struct cooling_dev_stats *stats = cdev->stats;
 676
 677        if (!stats)
 678                return;
 679
 680        spin_lock(&stats->lock);
 681
 682        if (stats->state == new_state)
 683                goto unlock;
 684
 685        update_time_in_state(stats);
 686        stats->trans_table[stats->state * stats->max_states + new_state]++;
 687        stats->state = new_state;
 688        stats->total_trans++;
 689
 690unlock:
 691        spin_unlock(&stats->lock);
 692}
 693
 694static ssize_t total_trans_show(struct device *dev,
 695                                struct device_attribute *attr, char *buf)
 696{
 697        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 698        struct cooling_dev_stats *stats = cdev->stats;
 699        int ret;
 700
 701        spin_lock(&stats->lock);
 702        ret = sprintf(buf, "%u\n", stats->total_trans);
 703        spin_unlock(&stats->lock);
 704
 705        return ret;
 706}
 707
 708static ssize_t
 709time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
 710                      char *buf)
 711{
 712        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 713        struct cooling_dev_stats *stats = cdev->stats;
 714        ssize_t len = 0;
 715        int i;
 716
 717        spin_lock(&stats->lock);
 718        update_time_in_state(stats);
 719
 720        for (i = 0; i < stats->max_states; i++) {
 721                len += sprintf(buf + len, "state%u\t%llu\n", i,
 722                               ktime_to_ms(stats->time_in_state[i]));
 723        }
 724        spin_unlock(&stats->lock);
 725
 726        return len;
 727}
 728
 729static ssize_t
 730reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
 731            size_t count)
 732{
 733        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 734        struct cooling_dev_stats *stats = cdev->stats;
 735        int i, states = stats->max_states;
 736
 737        spin_lock(&stats->lock);
 738
 739        stats->total_trans = 0;
 740        stats->last_time = ktime_get();
 741        memset(stats->trans_table, 0,
 742               states * states * sizeof(*stats->trans_table));
 743
 744        for (i = 0; i < stats->max_states; i++)
 745                stats->time_in_state[i] = ktime_set(0, 0);
 746
 747        spin_unlock(&stats->lock);
 748
 749        return count;
 750}
 751
 752static ssize_t trans_table_show(struct device *dev,
 753                                struct device_attribute *attr, char *buf)
 754{
 755        struct thermal_cooling_device *cdev = to_cooling_device(dev);
 756        struct cooling_dev_stats *stats = cdev->stats;
 757        ssize_t len = 0;
 758        int i, j;
 759
 760        len += snprintf(buf + len, PAGE_SIZE - len, " From  :    To\n");
 761        len += snprintf(buf + len, PAGE_SIZE - len, "       : ");
 762        for (i = 0; i < stats->max_states; i++) {
 763                if (len >= PAGE_SIZE)
 764                        break;
 765                len += snprintf(buf + len, PAGE_SIZE - len, "state%2u  ", i);
 766        }
 767        if (len >= PAGE_SIZE)
 768                return PAGE_SIZE;
 769
 770        len += snprintf(buf + len, PAGE_SIZE - len, "\n");
 771
 772        for (i = 0; i < stats->max_states; i++) {
 773                if (len >= PAGE_SIZE)
 774                        break;
 775
 776                len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
 777
 778                for (j = 0; j < stats->max_states; j++) {
 779                        if (len >= PAGE_SIZE)
 780                                break;
 781                        len += snprintf(buf + len, PAGE_SIZE - len, "%8u ",
 782                                stats->trans_table[i * stats->max_states + j]);
 783                }
 784                if (len >= PAGE_SIZE)
 785                        break;
 786                len += snprintf(buf + len, PAGE_SIZE - len, "\n");
 787        }
 788
 789        if (len >= PAGE_SIZE) {
 790                pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
 791                return -EFBIG;
 792        }
 793        return len;
 794}
 795
 796static DEVICE_ATTR_RO(total_trans);
 797static DEVICE_ATTR_RO(time_in_state_ms);
 798static DEVICE_ATTR_WO(reset);
 799static DEVICE_ATTR_RO(trans_table);
 800
 801static struct attribute *cooling_device_stats_attrs[] = {
 802        &dev_attr_total_trans.attr,
 803        &dev_attr_time_in_state_ms.attr,
 804        &dev_attr_reset.attr,
 805        &dev_attr_trans_table.attr,
 806        NULL
 807};
 808
 809static const struct attribute_group cooling_device_stats_attr_group = {
 810        .attrs = cooling_device_stats_attrs,
 811        .name = "stats"
 812};
 813
 814static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 815{
 816        struct cooling_dev_stats *stats;
 817        unsigned long states;
 818        int var;
 819
 820        if (cdev->ops->get_max_state(cdev, &states))
 821                return;
 822
 823        states++; /* Total number of states is highest state + 1 */
 824
 825        var = sizeof(*stats);
 826        var += sizeof(*stats->time_in_state) * states;
 827        var += sizeof(*stats->trans_table) * states * states;
 828
 829        stats = kzalloc(var, GFP_KERNEL);
 830        if (!stats)
 831                return;
 832
 833        stats->time_in_state = (ktime_t *)(stats + 1);
 834        stats->trans_table = (unsigned int *)(stats->time_in_state + states);
 835        cdev->stats = stats;
 836        stats->last_time = ktime_get();
 837        stats->max_states = states;
 838
 839        spin_lock_init(&stats->lock);
 840
 841        /* Fill the empty slot left in cooling_device_attr_groups */
 842        var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
 843        cooling_device_attr_groups[var] = &cooling_device_stats_attr_group;
 844}
 845
 846static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
 847{
 848        kfree(cdev->stats);
 849        cdev->stats = NULL;
 850}
 851
 852#else
 853
 854static inline void
 855cooling_device_stats_setup(struct thermal_cooling_device *cdev) {}
 856static inline void
 857cooling_device_stats_destroy(struct thermal_cooling_device *cdev) {}
 858
 859#endif /* CONFIG_THERMAL_STATISTICS */
 860
 861void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *cdev)
 862{
 863        cooling_device_stats_setup(cdev);
 864        cdev->device.groups = cooling_device_attr_groups;
 865}
 866
 867void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
 868{
 869        cooling_device_stats_destroy(cdev);
 870}
 871
 872/* these helper will be used only at the time of bindig */
 873ssize_t
 874trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
 875{
 876        struct thermal_instance *instance;
 877
 878        instance =
 879            container_of(attr, struct thermal_instance, attr);
 880
 881        return sprintf(buf, "%d\n", instance->trip);
 882}
 883
 884ssize_t
 885weight_show(struct device *dev, struct device_attribute *attr, char *buf)
 886{
 887        struct thermal_instance *instance;
 888
 889        instance = container_of(attr, struct thermal_instance, weight_attr);
 890
 891        return sprintf(buf, "%d\n", instance->weight);
 892}
 893
 894ssize_t weight_store(struct device *dev, struct device_attribute *attr,
 895                     const char *buf, size_t count)
 896{
 897        struct thermal_instance *instance;
 898        int ret, weight;
 899
 900        ret = kstrtoint(buf, 0, &weight);
 901        if (ret)
 902                return ret;
 903
 904        instance = container_of(attr, struct thermal_instance, weight_attr);
 905        instance->weight = weight;
 906
 907        return count;
 908}
 909