openwrt_deco_e4r/target/linux/xburst/patches-3.3/0010-cpufreq_stats-Support-runtime-changes-to-frequency-t.patch

302 lines
8.6 KiB
Diff

From ca40c7542f0cd0e0dfa074bd4ccefc04b8561427 Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Tue, 2 Aug 2011 10:26:09 +0200
Subject: [PATCH 10/21] cpufreq_stats: Support runtime changes to frequency
table.
---
drivers/cpufreq/cpufreq_stats.c | 161 ++++++++++++++++++++-------------------
1 files changed, 83 insertions(+), 78 deletions(-)
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -20,6 +20,7 @@
#include <linux/kobject.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
+#include <linux/string.h>
#include <asm/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -36,7 +37,7 @@ struct cpufreq_stats {
unsigned long long last_time;
unsigned int max_state;
unsigned int state_num;
- unsigned int last_index;
+ int last_index;
cputime64_t *time_in_state;
unsigned int *freq_table;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
@@ -59,7 +60,7 @@ static int cpufreq_stats_update(unsigned
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, cpu);
- if (stat->time_in_state)
+ if (stat->time_in_state && stat->last_index != -1)
stat->time_in_state[stat->last_index] +=
cur_time - stat->last_time;
stat->last_time = cur_time;
@@ -81,7 +82,7 @@ static ssize_t show_time_in_state(struct
ssize_t len = 0;
int i;
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
+ if (!stat || !stat->time_in_state)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
@@ -99,7 +100,7 @@ static ssize_t show_trans_table(struct c
int i, j;
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
+ if (!stat || !stat->trans_table)
return 0;
cpufreq_stats_update(stat->cpu);
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
@@ -158,63 +159,35 @@ static struct attribute_group stats_attr
static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
{
int index;
- for (index = 0; index < stat->max_state; index++)
- if (stat->freq_table[index] == freq)
- return index;
+ if (stat->freq_table)
+ for (index = 0; index < stat->max_state; index++)
+ if (stat->freq_table[index] == freq)
+ return index;
return -1;
}
-/* should be called late in the CPU removal sequence so that the stats
- * memory is still available in case someone tries to use it.
- */
static void cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (policy && policy->cpu == cpu)
+ sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
per_cpu(cpufreq_stats_table, cpu) = NULL;
-}
-
-/* must be called early in the CPU removal sequence (before
- * cpufreq_remove_dev) so that policy is still valid.
- */
-static void cpufreq_stats_free_sysfs(unsigned int cpu)
-{
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (policy && policy->cpu == cpu)
- sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (policy)
cpufreq_cpu_put(policy);
}
-static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
+static int cpufreq_stats_update_table(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
- unsigned int i, j, count = 0, ret = 0;
- struct cpufreq_stats *stat;
- struct cpufreq_policy *data;
+ unsigned int i, j, count = 0;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
- if (per_cpu(cpufreq_stats_table, cpu))
- return -EBUSY;
- stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
- if ((stat) == NULL)
- return -ENOMEM;
-
- data = cpufreq_cpu_get(cpu);
- if (data == NULL) {
- ret = -EINVAL;
- goto error_get_fail;
- }
-
- ret = sysfs_create_group(&data->kobj, &stats_attr_group);
- if (ret)
- goto error_out;
-
- stat->cpu = cpu;
- per_cpu(cpufreq_stats_table, cpu) = stat;
+ struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
@@ -223,40 +196,73 @@ static int cpufreq_stats_create_table(st
count++;
}
+ if (stat->max_state != count) {
+ stat->max_state = count;
+ kfree(stat->time_in_state);
+ stat->time_in_state = NULL;
+ }
alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
-
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int);
#endif
- stat->max_state = count;
- stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
- if (!stat->time_in_state) {
- ret = -ENOMEM;
- goto error_out;
- }
- stat->freq_table = (unsigned int *)(stat->time_in_state + count);
-
+ if (stat->time_in_state) {
+ memset(stat->time_in_state, 0, alloc_size);
+ } else {
+ stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
+ if (!stat->time_in_state)
+ return -ENOMEM;
+ stat->freq_table = (unsigned int *)(
+ stat->time_in_state + count);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table = stat->freq_table + count;
+ stat->trans_table = stat->freq_table + count;
#endif
+ }
+
j = 0;
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- if (freq_table_get_index(stat, freq) == -1)
- stat->freq_table[j++] = freq;
+ if (stat->freq_table) {
+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ unsigned int freq = table[i].frequency;
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ if (freq_table_get_index(stat, freq) == -1)
+ stat->freq_table[j++] = freq;
+ }
}
stat->state_num = j;
spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock);
+ return 0;
+}
+
+static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table)
+{
+ unsigned int ret = 0;
+ struct cpufreq_stats *stat;
+ struct cpufreq_policy *data;
+ unsigned int cpu = policy->cpu;
+
+ stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
+ if ((stat) == NULL)
+ return -ENOMEM;
+
+ data = cpufreq_cpu_get(cpu);
+ if (data == NULL) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+ ret = sysfs_create_group(&data->kobj, &stats_attr_group);
cpufreq_cpu_put(data);
+ if (ret)
+ goto error_out;
+
+ stat->cpu = cpu;
+ per_cpu(cpufreq_stats_table, cpu) = stat;
+
return 0;
error_out:
- cpufreq_cpu_put(data);
-error_get_fail:
kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL;
return ret;
@@ -274,10 +280,12 @@ static int cpufreq_stat_notifier_policy(
table = cpufreq_frequency_get_table(cpu);
if (!table)
return 0;
- ret = cpufreq_stats_create_table(policy, table);
- if (ret)
- return ret;
- return 0;
+ if (!per_cpu(cpufreq_stats_table, cpu)) {
+ ret = cpufreq_stats_create_table(policy, table);
+ if (ret)
+ return ret;
+ }
+ return cpufreq_stats_update_table(policy, table);
}
static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
@@ -297,21 +305,23 @@ static int cpufreq_stat_notifier_trans(s
old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
- /* We can't do stat->time_in_state[-1]= .. */
- if (old_index == -1 || new_index == -1)
- return 0;
-
cpufreq_stats_update(freq->cpu);
-
if (old_index == new_index)
return 0;
+ if (new_index == -1)
+ return 0;
+
spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
+ if (old_index != -1) {
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table[old_index * stat->max_state + new_index]++;
+ if (stat->trans_table)
+ stat->trans_table[old_index * stat->max_state +
+ new_index]++;
#endif
- stat->total_trans++;
+ stat->total_trans++;
+ }
spin_unlock(&cpufreq_stats_lock);
return 0;
}
@@ -327,9 +337,6 @@ static int __cpuinit cpufreq_stat_cpu_ca
case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
- case CPU_DOWN_PREPARE:
- cpufreq_stats_free_sysfs(cpu);
- break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
@@ -338,10 +345,9 @@ static int __cpuinit cpufreq_stat_cpu_ca
return NOTIFY_OK;
}
-/* priority=1 so this will get called before cpufreq_remove_dev */
-static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
+static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
+{
.notifier_call = cpufreq_stat_cpu_callback,
- .priority = 1,
};
static struct notifier_block notifier_policy_block = {
@@ -388,7 +394,6 @@ static void __exit cpufreq_stats_exit(vo
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
cpufreq_stats_free_table(cpu);
- cpufreq_stats_free_sysfs(cpu);
}
}