@@ -770,6 +770,9 @@ void thermal_cdev_stats_update_cur(struct thermal_cooling_device *cdev,
{
struct cooling_dev_stats *stats = cdev->stats;
+ if (!stats)
+ return;
+
spin_lock(&stats->lock);
if (stats->state == new_state)
@@ -904,33 +907,52 @@ static const struct attribute_group cooling_device_stats_attr_group = {
.name = "stats"
};
-static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
+static int cooling_device_stats_resize(struct thermal_cooling_device *cdev)
{
- struct cooling_dev_stats *stats;
+ struct cooling_dev_stats *stats = cdev->stats;
unsigned long states;
- int var;
+ int ret;
- if (cdev->ops->get_max_state(cdev, &states))
- return;
+ ret = cdev->ops->get_max_state(cdev, &states);
+ if (ret)
+ return ret;
states++; /* Total number of states is highest state + 1 */
- var = sizeof(*stats);
- var += sizeof(*stats->time_in_state) * states;
- var += sizeof(*stats->trans_table) * states * states;
+ stats->time_in_state = kcalloc(states, sizeof(*stats->time_in_state), GFP_KERNEL);
+ if (!stats->time_in_state)
+ return -ENOMEM;
- stats = kzalloc(var, GFP_KERNEL);
- if (!stats)
- return;
+ stats->trans_table = kcalloc(states, sizeof(*stats->trans_table) * states, GFP_KERNEL);
+ if (!stats->trans_table) {
+ kfree(stats->time_in_state);
+ return -ENOMEM;
+ }
- stats->time_in_state = (ktime_t *)(stats + 1);
- stats->trans_table = (unsigned int *)(stats->time_in_state + states);
- cdev->stats = stats;
stats->last_time = ktime_get();
stats->max_states = states;
+ return 0;
+}
+static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
+{
+ struct cooling_dev_stats *stats;
+ int var, ret;
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return;
+
+ cdev->stats = stats;
spin_lock_init(&stats->lock);
+ ret = cooling_device_stats_resize(cdev);
+ if (ret) {
+ kfree(cdev->stats);
+ cdev->stats = NULL;
+ return;
+ }
+
/* Fill the empty slot left in cooling_device_attr_groups */
var = ARRAY_SIZE(cooling_device_attr_groups) - 2;
cooling_device_attr_groups[var] = &cooling_device_stats_attr_group;
@@ -938,6 +960,12 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
{
+ struct cooling_dev_stats *stats = cdev->stats;
+
+ if (!stats)
+ return;
+ kfree(stats->time_in_state);
+ kfree(stats->trans_table);
kfree(cdev->stats);
cdev->stats = NULL;
}
Part of cooling device stats table is created based on the number of cooling states supported, and this may be changed at runtime. Introduce cooling_device_stats_resize() to handle this piece of the statistics table. Plus, check the existence of the statistics table before access because the table may fail to be created during cooling device registration. Signed-off-by: Zhang Rui <rui.zhang@intel.com> --- drivers/thermal/thermal_sysfs.c | 56 ++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-)