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