@@ -745,6 +745,10 @@ static const struct attribute_group *cooling_device_attr_groups[] = {
};
#ifdef CONFIG_THERMAL_STATISTICS
+static int cooling_device_stats_resize(struct thermal_cooling_device *cdev,
+ unsigned long cur_state,
+ unsigned long max_state);
+
struct cooling_dev_stats {
spinlock_t lock;
unsigned int total_trans;
@@ -787,6 +791,23 @@ void thermal_cdev_stats_update_cur(struct thermal_cooling_device *cdev,
spin_unlock(&stats->lock);
}
+void thermal_cdev_stats_update_max(struct thermal_cooling_device *cdev)
+{
+ struct cooling_dev_stats *stats = cdev->stats;
+ unsigned long cur_state, max_state;
+
+ if (!stats)
+ return;
+
+ if (cdev->ops->get_max_state(cdev, &max_state))
+ return;
+
+ if (cdev->ops->get_cur_state(cdev, &cur_state))
+ return;
+
+ cooling_device_stats_resize(cdev, cur_state, max_state);
+}
+
static ssize_t total_trans_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -907,36 +928,44 @@ static const struct attribute_group cooling_device_stats_attr_group = {
.name = "stats"
};
-static int cooling_device_stats_resize(struct thermal_cooling_device *cdev)
+static int cooling_device_stats_resize(struct thermal_cooling_device *cdev,
+ unsigned long cur_state,
+ unsigned long max_state)
{
struct cooling_dev_stats *stats = cdev->stats;
- unsigned long states;
- int ret;
-
- ret = cdev->ops->get_max_state(cdev, &states);
- if (ret)
- return ret;
+ unsigned long states = max_state + 1;
+ void *time_in_state, *trans_table;
- states++; /* Total number of states is highest state + 1 */
+ if (stats->max_states == states)
+ return 0;
- stats->time_in_state = kcalloc(states, sizeof(*stats->time_in_state), GFP_KERNEL);
- if (!stats->time_in_state)
+ time_in_state = kcalloc(states, sizeof(*stats->time_in_state), GFP_KERNEL);
+ if (!time_in_state)
return -ENOMEM;
- stats->trans_table = kcalloc(states, sizeof(*stats->trans_table) * states, GFP_KERNEL);
- if (!stats->trans_table) {
- kfree(stats->time_in_state);
+ trans_table = kcalloc(states, sizeof(*stats->trans_table) * states, GFP_KERNEL);
+ if (!trans_table) {
+ kfree(time_in_state);
return -ENOMEM;
}
+ spin_lock(&stats->lock);
+ kfree(stats->time_in_state);
+ kfree(stats->trans_table);
+ stats->time_in_state = time_in_state;
+ stats->trans_table = trans_table;
stats->last_time = ktime_get();
stats->max_states = states;
+ stats->state = cur_state;
+ stats->total_trans = 0;
+ spin_unlock(&stats->lock);
return 0;
}
static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
{
struct cooling_dev_stats *stats;
+ unsigned long max_state;
int var, ret;
stats = kzalloc(sizeof(*stats), GFP_KERNEL);
@@ -946,7 +975,15 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
cdev->stats = stats;
spin_lock_init(&stats->lock);
- ret = cooling_device_stats_resize(cdev);
+ ret = cdev->ops->get_max_state(cdev, &max_state);
+ if (ret)
+ return;
+
+ /**
+ * cooling device current state will be updated soon
+ * during registration
+ **/
+ ret = cooling_device_stats_resize(cdev, 0, max_state);
if (ret) {
kfree(cdev->stats);
cdev->stats = NULL;
@@ -533,4 +533,11 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
{ }
#endif /* CONFIG_THERMAL */
+#ifdef CONFIG_THERMAL_STATISTICS
+void thermal_cdev_stats_update_max(struct thermal_cooling_device *cdev);
+#else
+static inline void
+thermal_cdev_stats_update_max(struct thermal_cooling_device *cdev) {}
+#endif /* CONFIG_THERMAL_STATISTICS */
+
#endif /* __THERMAL_H__ */
Introduce thermal_cdev_stats_update_max() which can be used to update the cooling device statistics table when maximum cooling state of a cooling device is changed. Signed-off-by: Zhang Rui <rui.zhang@intel.com> --- drivers/thermal/thermal_sysfs.c | 65 ++++++++++++++++++++++++++------- include/linux/thermal.h | 7 ++++ 2 files changed, 58 insertions(+), 14 deletions(-)