Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  thermal.c - sysfs interface of thermal devices
0004  *
0005  *  Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com>
0006  *
0007  *  Highly based on original thermal_core.c
0008  *  Copyright (C) 2008 Intel Corp
0009  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
0010  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
0011  */
0012 
0013 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0014 
0015 #include <linux/sysfs.h>
0016 #include <linux/device.h>
0017 #include <linux/err.h>
0018 #include <linux/slab.h>
0019 #include <linux/string.h>
0020 #include <linux/jiffies.h>
0021 
0022 #include "thermal_core.h"
0023 
0024 /* sys I/F for thermal zone */
0025 
0026 static ssize_t
0027 type_show(struct device *dev, struct device_attribute *attr, char *buf)
0028 {
0029     struct thermal_zone_device *tz = to_thermal_zone(dev);
0030 
0031     return sprintf(buf, "%s\n", tz->type);
0032 }
0033 
0034 static ssize_t
0035 temp_show(struct device *dev, struct device_attribute *attr, char *buf)
0036 {
0037     struct thermal_zone_device *tz = to_thermal_zone(dev);
0038     int temperature, ret;
0039 
0040     ret = thermal_zone_get_temp(tz, &temperature);
0041 
0042     if (ret)
0043         return ret;
0044 
0045     return sprintf(buf, "%d\n", temperature);
0046 }
0047 
0048 static ssize_t
0049 mode_show(struct device *dev, struct device_attribute *attr, char *buf)
0050 {
0051     struct thermal_zone_device *tz = to_thermal_zone(dev);
0052     int enabled = thermal_zone_device_is_enabled(tz);
0053 
0054     return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
0055 }
0056 
0057 static ssize_t
0058 mode_store(struct device *dev, struct device_attribute *attr,
0059        const char *buf, size_t count)
0060 {
0061     struct thermal_zone_device *tz = to_thermal_zone(dev);
0062     int result;
0063 
0064     if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
0065         result = thermal_zone_device_enable(tz);
0066     else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
0067         result = thermal_zone_device_disable(tz);
0068     else
0069         result = -EINVAL;
0070 
0071     if (result)
0072         return result;
0073 
0074     return count;
0075 }
0076 
0077 static ssize_t
0078 trip_point_type_show(struct device *dev, struct device_attribute *attr,
0079              char *buf)
0080 {
0081     struct thermal_zone_device *tz = to_thermal_zone(dev);
0082     enum thermal_trip_type type;
0083     int trip, result;
0084 
0085     if (!tz->ops->get_trip_type)
0086         return -EPERM;
0087 
0088     if (sscanf(attr->attr.name, "trip_point_%d_type", &trip) != 1)
0089         return -EINVAL;
0090 
0091     result = tz->ops->get_trip_type(tz, trip, &type);
0092     if (result)
0093         return result;
0094 
0095     switch (type) {
0096     case THERMAL_TRIP_CRITICAL:
0097         return sprintf(buf, "critical\n");
0098     case THERMAL_TRIP_HOT:
0099         return sprintf(buf, "hot\n");
0100     case THERMAL_TRIP_PASSIVE:
0101         return sprintf(buf, "passive\n");
0102     case THERMAL_TRIP_ACTIVE:
0103         return sprintf(buf, "active\n");
0104     default:
0105         return sprintf(buf, "unknown\n");
0106     }
0107 }
0108 
0109 static ssize_t
0110 trip_point_temp_store(struct device *dev, struct device_attribute *attr,
0111               const char *buf, size_t count)
0112 {
0113     struct thermal_zone_device *tz = to_thermal_zone(dev);
0114     int trip, ret;
0115     int temperature, hyst = 0;
0116     enum thermal_trip_type type;
0117 
0118     if (!tz->ops->set_trip_temp)
0119         return -EPERM;
0120 
0121     if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1)
0122         return -EINVAL;
0123 
0124     if (kstrtoint(buf, 10, &temperature))
0125         return -EINVAL;
0126 
0127     ret = tz->ops->set_trip_temp(tz, trip, temperature);
0128     if (ret)
0129         return ret;
0130 
0131     if (tz->ops->get_trip_hyst) {
0132         ret = tz->ops->get_trip_hyst(tz, trip, &hyst);
0133         if (ret)
0134             return ret;
0135     }
0136 
0137     ret = tz->ops->get_trip_type(tz, trip, &type);
0138     if (ret)
0139         return ret;
0140 
0141     thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst);
0142 
0143     thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
0144 
0145     return count;
0146 }
0147 
0148 static ssize_t
0149 trip_point_temp_show(struct device *dev, struct device_attribute *attr,
0150              char *buf)
0151 {
0152     struct thermal_zone_device *tz = to_thermal_zone(dev);
0153     int trip, ret;
0154     int temperature;
0155 
0156     if (!tz->ops->get_trip_temp)
0157         return -EPERM;
0158 
0159     if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1)
0160         return -EINVAL;
0161 
0162     ret = tz->ops->get_trip_temp(tz, trip, &temperature);
0163 
0164     if (ret)
0165         return ret;
0166 
0167     return sprintf(buf, "%d\n", temperature);
0168 }
0169 
0170 static ssize_t
0171 trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
0172               const char *buf, size_t count)
0173 {
0174     struct thermal_zone_device *tz = to_thermal_zone(dev);
0175     int trip, ret;
0176     int temperature;
0177 
0178     if (!tz->ops->set_trip_hyst)
0179         return -EPERM;
0180 
0181     if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1)
0182         return -EINVAL;
0183 
0184     if (kstrtoint(buf, 10, &temperature))
0185         return -EINVAL;
0186 
0187     /*
0188      * We are not doing any check on the 'temperature' value
0189      * here. The driver implementing 'set_trip_hyst' has to
0190      * take care of this.
0191      */
0192     ret = tz->ops->set_trip_hyst(tz, trip, temperature);
0193 
0194     if (!ret)
0195         thermal_zone_set_trips(tz);
0196 
0197     return ret ? ret : count;
0198 }
0199 
0200 static ssize_t
0201 trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
0202              char *buf)
0203 {
0204     struct thermal_zone_device *tz = to_thermal_zone(dev);
0205     int trip, ret;
0206     int temperature;
0207 
0208     if (!tz->ops->get_trip_hyst)
0209         return -EPERM;
0210 
0211     if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1)
0212         return -EINVAL;
0213 
0214     ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
0215 
0216     return ret ? ret : sprintf(buf, "%d\n", temperature);
0217 }
0218 
0219 static ssize_t
0220 policy_store(struct device *dev, struct device_attribute *attr,
0221          const char *buf, size_t count)
0222 {
0223     struct thermal_zone_device *tz = to_thermal_zone(dev);
0224     char name[THERMAL_NAME_LENGTH];
0225     int ret;
0226 
0227     snprintf(name, sizeof(name), "%s", buf);
0228 
0229     ret = thermal_zone_device_set_policy(tz, name);
0230     if (!ret)
0231         ret = count;
0232 
0233     return ret;
0234 }
0235 
0236 static ssize_t
0237 policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
0238 {
0239     struct thermal_zone_device *tz = to_thermal_zone(dev);
0240 
0241     return sprintf(buf, "%s\n", tz->governor->name);
0242 }
0243 
0244 static ssize_t
0245 available_policies_show(struct device *dev, struct device_attribute *devattr,
0246             char *buf)
0247 {
0248     return thermal_build_list_of_policies(buf);
0249 }
0250 
0251 #if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
0252 static ssize_t
0253 emul_temp_store(struct device *dev, struct device_attribute *attr,
0254         const char *buf, size_t count)
0255 {
0256     struct thermal_zone_device *tz = to_thermal_zone(dev);
0257     int ret = 0;
0258     int temperature;
0259 
0260     if (kstrtoint(buf, 10, &temperature))
0261         return -EINVAL;
0262 
0263     if (!tz->ops->set_emul_temp) {
0264         mutex_lock(&tz->lock);
0265         tz->emul_temperature = temperature;
0266         mutex_unlock(&tz->lock);
0267     } else {
0268         ret = tz->ops->set_emul_temp(tz, temperature);
0269     }
0270 
0271     if (!ret)
0272         thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
0273 
0274     return ret ? ret : count;
0275 }
0276 static DEVICE_ATTR_WO(emul_temp);
0277 #endif
0278 
0279 static ssize_t
0280 sustainable_power_show(struct device *dev, struct device_attribute *devattr,
0281                char *buf)
0282 {
0283     struct thermal_zone_device *tz = to_thermal_zone(dev);
0284 
0285     if (tz->tzp)
0286         return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
0287     else
0288         return -EIO;
0289 }
0290 
0291 static ssize_t
0292 sustainable_power_store(struct device *dev, struct device_attribute *devattr,
0293             const char *buf, size_t count)
0294 {
0295     struct thermal_zone_device *tz = to_thermal_zone(dev);
0296     u32 sustainable_power;
0297 
0298     if (!tz->tzp)
0299         return -EIO;
0300 
0301     if (kstrtou32(buf, 10, &sustainable_power))
0302         return -EINVAL;
0303 
0304     tz->tzp->sustainable_power = sustainable_power;
0305 
0306     return count;
0307 }
0308 
0309 #define create_s32_tzp_attr(name)                   \
0310     static ssize_t                          \
0311     name##_show(struct device *dev, struct device_attribute *devattr, \
0312         char *buf)                      \
0313     {                               \
0314     struct thermal_zone_device *tz = to_thermal_zone(dev);      \
0315                                     \
0316     if (tz->tzp)                            \
0317         return sprintf(buf, "%d\n", tz->tzp->name);     \
0318     else                                \
0319         return -EIO;                        \
0320     }                               \
0321                                     \
0322     static ssize_t                          \
0323     name##_store(struct device *dev, struct device_attribute *devattr, \
0324         const char *buf, size_t count)              \
0325     {                               \
0326         struct thermal_zone_device *tz = to_thermal_zone(dev);  \
0327         s32 value;                      \
0328                                     \
0329         if (!tz->tzp)                       \
0330             return -EIO;                    \
0331                                     \
0332         if (kstrtos32(buf, 10, &value))             \
0333             return -EINVAL;                 \
0334                                     \
0335         tz->tzp->name = value;                  \
0336                                     \
0337         return count;                       \
0338     }                               \
0339     static DEVICE_ATTR_RW(name)
0340 
0341 create_s32_tzp_attr(k_po);
0342 create_s32_tzp_attr(k_pu);
0343 create_s32_tzp_attr(k_i);
0344 create_s32_tzp_attr(k_d);
0345 create_s32_tzp_attr(integral_cutoff);
0346 create_s32_tzp_attr(slope);
0347 create_s32_tzp_attr(offset);
0348 #undef create_s32_tzp_attr
0349 
0350 /*
0351  * These are thermal zone device attributes that will always be present.
0352  * All the attributes created for tzp (create_s32_tzp_attr) also are always
0353  * present on the sysfs interface.
0354  */
0355 static DEVICE_ATTR_RO(type);
0356 static DEVICE_ATTR_RO(temp);
0357 static DEVICE_ATTR_RW(policy);
0358 static DEVICE_ATTR_RO(available_policies);
0359 static DEVICE_ATTR_RW(sustainable_power);
0360 
0361 /* These thermal zone device attributes are created based on conditions */
0362 static DEVICE_ATTR_RW(mode);
0363 
0364 /* These attributes are unconditionally added to a thermal zone */
0365 static struct attribute *thermal_zone_dev_attrs[] = {
0366     &dev_attr_type.attr,
0367     &dev_attr_temp.attr,
0368 #if (IS_ENABLED(CONFIG_THERMAL_EMULATION))
0369     &dev_attr_emul_temp.attr,
0370 #endif
0371     &dev_attr_policy.attr,
0372     &dev_attr_available_policies.attr,
0373     &dev_attr_sustainable_power.attr,
0374     &dev_attr_k_po.attr,
0375     &dev_attr_k_pu.attr,
0376     &dev_attr_k_i.attr,
0377     &dev_attr_k_d.attr,
0378     &dev_attr_integral_cutoff.attr,
0379     &dev_attr_slope.attr,
0380     &dev_attr_offset.attr,
0381     NULL,
0382 };
0383 
0384 static const struct attribute_group thermal_zone_attribute_group = {
0385     .attrs = thermal_zone_dev_attrs,
0386 };
0387 
0388 static struct attribute *thermal_zone_mode_attrs[] = {
0389     &dev_attr_mode.attr,
0390     NULL,
0391 };
0392 
0393 static const struct attribute_group thermal_zone_mode_attribute_group = {
0394     .attrs = thermal_zone_mode_attrs,
0395 };
0396 
0397 static const struct attribute_group *thermal_zone_attribute_groups[] = {
0398     &thermal_zone_attribute_group,
0399     &thermal_zone_mode_attribute_group,
0400     /* This is not NULL terminated as we create the group dynamically */
0401 };
0402 
0403 /**
0404  * create_trip_attrs() - create attributes for trip points
0405  * @tz:     the thermal zone device
0406  * @mask:   Writeable trip point bitmap.
0407  *
0408  * helper function to instantiate sysfs entries for every trip
0409  * point and its properties of a struct thermal_zone_device.
0410  *
0411  * Return: 0 on success, the proper error value otherwise.
0412  */
0413 static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
0414 {
0415     struct attribute **attrs;
0416     int indx;
0417 
0418     /* This function works only for zones with at least one trip */
0419     if (tz->num_trips <= 0)
0420         return -EINVAL;
0421 
0422     tz->trip_type_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_type_attrs),
0423                       GFP_KERNEL);
0424     if (!tz->trip_type_attrs)
0425         return -ENOMEM;
0426 
0427     tz->trip_temp_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_temp_attrs),
0428                       GFP_KERNEL);
0429     if (!tz->trip_temp_attrs) {
0430         kfree(tz->trip_type_attrs);
0431         return -ENOMEM;
0432     }
0433 
0434     if (tz->ops->get_trip_hyst) {
0435         tz->trip_hyst_attrs = kcalloc(tz->num_trips,
0436                           sizeof(*tz->trip_hyst_attrs),
0437                           GFP_KERNEL);
0438         if (!tz->trip_hyst_attrs) {
0439             kfree(tz->trip_type_attrs);
0440             kfree(tz->trip_temp_attrs);
0441             return -ENOMEM;
0442         }
0443     }
0444 
0445     attrs = kcalloc(tz->num_trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
0446     if (!attrs) {
0447         kfree(tz->trip_type_attrs);
0448         kfree(tz->trip_temp_attrs);
0449         if (tz->ops->get_trip_hyst)
0450             kfree(tz->trip_hyst_attrs);
0451         return -ENOMEM;
0452     }
0453 
0454     for (indx = 0; indx < tz->num_trips; indx++) {
0455         /* create trip type attribute */
0456         snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
0457              "trip_point_%d_type", indx);
0458 
0459         sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
0460         tz->trip_type_attrs[indx].attr.attr.name =
0461                         tz->trip_type_attrs[indx].name;
0462         tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
0463         tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
0464         attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
0465 
0466         /* create trip temp attribute */
0467         snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
0468              "trip_point_%d_temp", indx);
0469 
0470         sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
0471         tz->trip_temp_attrs[indx].attr.attr.name =
0472                         tz->trip_temp_attrs[indx].name;
0473         tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
0474         tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
0475         if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
0476             mask & (1 << indx)) {
0477             tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
0478             tz->trip_temp_attrs[indx].attr.store =
0479                             trip_point_temp_store;
0480         }
0481         attrs[indx + tz->num_trips] = &tz->trip_temp_attrs[indx].attr.attr;
0482 
0483         /* create Optional trip hyst attribute */
0484         if (!tz->ops->get_trip_hyst)
0485             continue;
0486         snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
0487              "trip_point_%d_hyst", indx);
0488 
0489         sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
0490         tz->trip_hyst_attrs[indx].attr.attr.name =
0491                     tz->trip_hyst_attrs[indx].name;
0492         tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
0493         tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
0494         if (tz->ops->set_trip_hyst) {
0495             tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
0496             tz->trip_hyst_attrs[indx].attr.store =
0497                     trip_point_hyst_store;
0498         }
0499         attrs[indx + tz->num_trips * 2] =
0500                     &tz->trip_hyst_attrs[indx].attr.attr;
0501     }
0502     attrs[tz->num_trips * 3] = NULL;
0503 
0504     tz->trips_attribute_group.attrs = attrs;
0505 
0506     return 0;
0507 }
0508 
0509 /**
0510  * destroy_trip_attrs() - destroy attributes for trip points
0511  * @tz:     the thermal zone device
0512  *
0513  * helper function to free resources allocated by create_trip_attrs()
0514  */
0515 static void destroy_trip_attrs(struct thermal_zone_device *tz)
0516 {
0517     if (!tz)
0518         return;
0519 
0520     kfree(tz->trip_type_attrs);
0521     kfree(tz->trip_temp_attrs);
0522     if (tz->ops->get_trip_hyst)
0523         kfree(tz->trip_hyst_attrs);
0524     kfree(tz->trips_attribute_group.attrs);
0525 }
0526 
0527 int thermal_zone_create_device_groups(struct thermal_zone_device *tz,
0528                       int mask)
0529 {
0530     const struct attribute_group **groups;
0531     int i, size, result;
0532 
0533     /* we need one extra for trips and the NULL to terminate the array */
0534     size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2;
0535     /* This also takes care of API requirement to be NULL terminated */
0536     groups = kcalloc(size, sizeof(*groups), GFP_KERNEL);
0537     if (!groups)
0538         return -ENOMEM;
0539 
0540     for (i = 0; i < size - 2; i++)
0541         groups[i] = thermal_zone_attribute_groups[i];
0542 
0543     if (tz->num_trips) {
0544         result = create_trip_attrs(tz, mask);
0545         if (result) {
0546             kfree(groups);
0547 
0548             return result;
0549         }
0550 
0551         groups[size - 2] = &tz->trips_attribute_group;
0552     }
0553 
0554     tz->device.groups = groups;
0555 
0556     return 0;
0557 }
0558 
0559 void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz)
0560 {
0561     if (!tz)
0562         return;
0563 
0564     if (tz->num_trips)
0565         destroy_trip_attrs(tz);
0566 
0567     kfree(tz->device.groups);
0568 }
0569 
0570 /* sys I/F for cooling device */
0571 static ssize_t
0572 cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf)
0573 {
0574     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0575 
0576     return sprintf(buf, "%s\n", cdev->type);
0577 }
0578 
0579 static ssize_t max_state_show(struct device *dev, struct device_attribute *attr,
0580                   char *buf)
0581 {
0582     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0583     unsigned long state;
0584     int ret;
0585 
0586     ret = cdev->ops->get_max_state(cdev, &state);
0587     if (ret)
0588         return ret;
0589     return sprintf(buf, "%ld\n", state);
0590 }
0591 
0592 static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr,
0593                   char *buf)
0594 {
0595     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0596     unsigned long state;
0597     int ret;
0598 
0599     ret = cdev->ops->get_cur_state(cdev, &state);
0600     if (ret)
0601         return ret;
0602     return sprintf(buf, "%ld\n", state);
0603 }
0604 
0605 static ssize_t
0606 cur_state_store(struct device *dev, struct device_attribute *attr,
0607         const char *buf, size_t count)
0608 {
0609     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0610     unsigned long state;
0611     int result;
0612 
0613     if (sscanf(buf, "%ld\n", &state) != 1)
0614         return -EINVAL;
0615 
0616     if ((long)state < 0)
0617         return -EINVAL;
0618 
0619     mutex_lock(&cdev->lock);
0620 
0621     result = cdev->ops->set_cur_state(cdev, state);
0622     if (!result)
0623         thermal_cooling_device_stats_update(cdev, state);
0624 
0625     mutex_unlock(&cdev->lock);
0626     return result ? result : count;
0627 }
0628 
0629 static struct device_attribute
0630 dev_attr_cdev_type = __ATTR(type, 0444, cdev_type_show, NULL);
0631 static DEVICE_ATTR_RO(max_state);
0632 static DEVICE_ATTR_RW(cur_state);
0633 
0634 static struct attribute *cooling_device_attrs[] = {
0635     &dev_attr_cdev_type.attr,
0636     &dev_attr_max_state.attr,
0637     &dev_attr_cur_state.attr,
0638     NULL,
0639 };
0640 
0641 static const struct attribute_group cooling_device_attr_group = {
0642     .attrs = cooling_device_attrs,
0643 };
0644 
0645 static const struct attribute_group *cooling_device_attr_groups[] = {
0646     &cooling_device_attr_group,
0647     NULL, /* Space allocated for cooling_device_stats_attr_group */
0648     NULL,
0649 };
0650 
0651 #ifdef CONFIG_THERMAL_STATISTICS
0652 struct cooling_dev_stats {
0653     spinlock_t lock;
0654     unsigned int total_trans;
0655     unsigned long state;
0656     unsigned long max_states;
0657     ktime_t last_time;
0658     ktime_t *time_in_state;
0659     unsigned int *trans_table;
0660 };
0661 
0662 static void update_time_in_state(struct cooling_dev_stats *stats)
0663 {
0664     ktime_t now = ktime_get(), delta;
0665 
0666     delta = ktime_sub(now, stats->last_time);
0667     stats->time_in_state[stats->state] =
0668         ktime_add(stats->time_in_state[stats->state], delta);
0669     stats->last_time = now;
0670 }
0671 
0672 void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
0673                      unsigned long new_state)
0674 {
0675     struct cooling_dev_stats *stats = cdev->stats;
0676 
0677     if (!stats)
0678         return;
0679 
0680     spin_lock(&stats->lock);
0681 
0682     if (stats->state == new_state)
0683         goto unlock;
0684 
0685     update_time_in_state(stats);
0686     stats->trans_table[stats->state * stats->max_states + new_state]++;
0687     stats->state = new_state;
0688     stats->total_trans++;
0689 
0690 unlock:
0691     spin_unlock(&stats->lock);
0692 }
0693 
0694 static ssize_t total_trans_show(struct device *dev,
0695                 struct device_attribute *attr, char *buf)
0696 {
0697     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0698     struct cooling_dev_stats *stats = cdev->stats;
0699     int ret;
0700 
0701     spin_lock(&stats->lock);
0702     ret = sprintf(buf, "%u\n", stats->total_trans);
0703     spin_unlock(&stats->lock);
0704 
0705     return ret;
0706 }
0707 
0708 static ssize_t
0709 time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
0710               char *buf)
0711 {
0712     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0713     struct cooling_dev_stats *stats = cdev->stats;
0714     ssize_t len = 0;
0715     int i;
0716 
0717     spin_lock(&stats->lock);
0718     update_time_in_state(stats);
0719 
0720     for (i = 0; i < stats->max_states; i++) {
0721         len += sprintf(buf + len, "state%u\t%llu\n", i,
0722                    ktime_to_ms(stats->time_in_state[i]));
0723     }
0724     spin_unlock(&stats->lock);
0725 
0726     return len;
0727 }
0728 
0729 static ssize_t
0730 reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
0731         size_t count)
0732 {
0733     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0734     struct cooling_dev_stats *stats = cdev->stats;
0735     int i, states = stats->max_states;
0736 
0737     spin_lock(&stats->lock);
0738 
0739     stats->total_trans = 0;
0740     stats->last_time = ktime_get();
0741     memset(stats->trans_table, 0,
0742            states * states * sizeof(*stats->trans_table));
0743 
0744     for (i = 0; i < stats->max_states; i++)
0745         stats->time_in_state[i] = ktime_set(0, 0);
0746 
0747     spin_unlock(&stats->lock);
0748 
0749     return count;
0750 }
0751 
0752 static ssize_t trans_table_show(struct device *dev,
0753                 struct device_attribute *attr, char *buf)
0754 {
0755     struct thermal_cooling_device *cdev = to_cooling_device(dev);
0756     struct cooling_dev_stats *stats = cdev->stats;
0757     ssize_t len = 0;
0758     int i, j;
0759 
0760     len += snprintf(buf + len, PAGE_SIZE - len, " From  :    To\n");
0761     len += snprintf(buf + len, PAGE_SIZE - len, "       : ");
0762     for (i = 0; i < stats->max_states; i++) {
0763         if (len >= PAGE_SIZE)
0764             break;
0765         len += snprintf(buf + len, PAGE_SIZE - len, "state%2u  ", i);
0766     }
0767     if (len >= PAGE_SIZE)
0768         return PAGE_SIZE;
0769 
0770     len += snprintf(buf + len, PAGE_SIZE - len, "\n");
0771 
0772     for (i = 0; i < stats->max_states; i++) {
0773         if (len >= PAGE_SIZE)
0774             break;
0775 
0776         len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
0777 
0778         for (j = 0; j < stats->max_states; j++) {
0779             if (len >= PAGE_SIZE)
0780                 break;
0781             len += snprintf(buf + len, PAGE_SIZE - len, "%8u ",
0782                 stats->trans_table[i * stats->max_states + j]);
0783         }
0784         if (len >= PAGE_SIZE)
0785             break;
0786         len += snprintf(buf + len, PAGE_SIZE - len, "\n");
0787     }
0788 
0789     if (len >= PAGE_SIZE) {
0790         pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
0791         return -EFBIG;
0792     }
0793     return len;
0794 }
0795 
0796 static DEVICE_ATTR_RO(total_trans);
0797 static DEVICE_ATTR_RO(time_in_state_ms);
0798 static DEVICE_ATTR_WO(reset);
0799 static DEVICE_ATTR_RO(trans_table);
0800 
0801 static struct attribute *cooling_device_stats_attrs[] = {
0802     &dev_attr_total_trans.attr,
0803     &dev_attr_time_in_state_ms.attr,
0804     &dev_attr_reset.attr,
0805     &dev_attr_trans_table.attr,
0806     NULL
0807 };
0808 
0809 static const struct attribute_group cooling_device_stats_attr_group = {
0810     .attrs = cooling_device_stats_attrs,
0811     .name = "stats"
0812 };
0813 
0814 static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
0815 {
0816     const struct attribute_group *stats_attr_group = NULL;
0817     struct cooling_dev_stats *stats;
0818     unsigned long states;
0819     int var;
0820 
0821     if (cdev->ops->get_max_state(cdev, &states))
0822         goto out;
0823 
0824     states++; /* Total number of states is highest state + 1 */
0825 
0826     var = sizeof(*stats);
0827     var += sizeof(*stats->time_in_state) * states;
0828     var += sizeof(*stats->trans_table) * states * states;
0829 
0830     stats = kzalloc(var, GFP_KERNEL);
0831     if (!stats)
0832         goto out;
0833 
0834     stats->time_in_state = (ktime_t *)(stats + 1);
0835     stats->trans_table = (unsigned int *)(stats->time_in_state + states);
0836     cdev->stats = stats;
0837     stats->last_time = ktime_get();
0838     stats->max_states = states;
0839 
0840     spin_lock_init(&stats->lock);
0841 
0842     stats_attr_group = &cooling_device_stats_attr_group;
0843 
0844 out:
0845     /* Fill the empty slot left in cooling_device_attr_groups */
0846     var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
0847     cooling_device_attr_groups[var] = stats_attr_group;
0848 }
0849 
0850 static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
0851 {
0852     kfree(cdev->stats);
0853     cdev->stats = NULL;
0854 }
0855 
0856 #else
0857 
0858 static inline void
0859 cooling_device_stats_setup(struct thermal_cooling_device *cdev) {}
0860 static inline void
0861 cooling_device_stats_destroy(struct thermal_cooling_device *cdev) {}
0862 
0863 #endif /* CONFIG_THERMAL_STATISTICS */
0864 
0865 void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *cdev)
0866 {
0867     cooling_device_stats_setup(cdev);
0868     cdev->device.groups = cooling_device_attr_groups;
0869 }
0870 
0871 void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev)
0872 {
0873     cooling_device_stats_destroy(cdev);
0874 }
0875 
0876 /* these helper will be used only at the time of bindig */
0877 ssize_t
0878 trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
0879 {
0880     struct thermal_instance *instance;
0881 
0882     instance =
0883         container_of(attr, struct thermal_instance, attr);
0884 
0885     return sprintf(buf, "%d\n", instance->trip);
0886 }
0887 
0888 ssize_t
0889 weight_show(struct device *dev, struct device_attribute *attr, char *buf)
0890 {
0891     struct thermal_instance *instance;
0892 
0893     instance = container_of(attr, struct thermal_instance, weight_attr);
0894 
0895     return sprintf(buf, "%d\n", instance->weight);
0896 }
0897 
0898 ssize_t weight_store(struct device *dev, struct device_attribute *attr,
0899              const char *buf, size_t count)
0900 {
0901     struct thermal_instance *instance;
0902     int ret, weight;
0903 
0904     ret = kstrtoint(buf, 0, &weight);
0905     if (ret)
0906         return ret;
0907 
0908     instance = container_of(attr, struct thermal_instance, weight_attr);
0909     instance->weight = weight;
0910 
0911     return count;
0912 }