diff mbox series

[RFC,2/5] thermal: create statistics table in two steps

Message ID 20200408041917.2329-2-rui.zhang@intel.com
State New
Headers show
Series None | expand

Commit Message

Zhang Rui April 8, 2020, 4:19 a.m. UTC
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(-)
diff mbox series

Patch

diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index 00caa7787b71..45cfc2746874 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -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;
 }