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