brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · 1838aa7 Raw
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