net/mlx4_core: drop useless LIST_HEAD
[linux-2.6-block.git] / drivers / cpufreq / cpufreq_stats.c
CommitLineData
1da177e4
LT
1/*
2 * drivers/cpufreq/cpufreq_stats.c
3 *
4 * Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
0a829c5a 5 * (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
1da177e4
LT
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
1da177e4 12#include <linux/cpu.h>
1da177e4 13#include <linux/cpufreq.h>
5c720d37 14#include <linux/module.h>
5ff0a268 15#include <linux/slab.h>
1da177e4 16
1aefc75b 17static DEFINE_SPINLOCK(cpufreq_stats_lock);
1da177e4 18
1da177e4 19struct cpufreq_stats {
1da177e4 20 unsigned int total_trans;
bb176f7d 21 unsigned long long last_time;
1da177e4
LT
22 unsigned int max_state;
23 unsigned int state_num;
24 unsigned int last_index;
1e7586a1 25 u64 *time_in_state;
1da177e4 26 unsigned int *freq_table;
1da177e4 27 unsigned int *trans_table;
1da177e4
LT
28};
29
d476ec4f 30static void cpufreq_stats_update(struct cpufreq_stats *stats)
1da177e4 31{
9531347c 32 unsigned long long cur_time = get_jiffies_64();
58f1df25 33
1da177e4 34 spin_lock(&cpufreq_stats_lock);
c960f9b2 35 stats->time_in_state[stats->last_index] += cur_time - stats->last_time;
50941607 36 stats->last_time = cur_time;
1da177e4 37 spin_unlock(&cpufreq_stats_lock);
1da177e4
LT
38}
39
ee7930ee
MM
40static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
41{
42 unsigned int count = stats->max_state;
43
44 memset(stats->time_in_state, 0, count * sizeof(u64));
ee7930ee 45 memset(stats->trans_table, 0, count * count * sizeof(int));
ee7930ee
MM
46 stats->last_time = get_jiffies_64();
47 stats->total_trans = 0;
48}
49
0a829c5a 50static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
1da177e4 51{
a9aaf291 52 return sprintf(buf, "%d\n", policy->stats->total_trans);
1da177e4
LT
53}
54
0a829c5a 55static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
1da177e4 56{
50941607 57 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
58 ssize_t len = 0;
59 int i;
a9aaf291 60
1aefc75b
RW
61 if (policy->fast_switch_enabled)
62 return 0;
63
50941607
VK
64 cpufreq_stats_update(stats);
65 for (i = 0; i < stats->state_num; i++) {
66 len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
0a829c5a 67 (unsigned long long)
50941607 68 jiffies_64_to_clock_t(stats->time_in_state[i]));
1da177e4
LT
69 }
70 return len;
71}
72
ee7930ee
MM
73static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
74 size_t count)
75{
76 /* We don't care what is written to the attribute. */
77 cpufreq_stats_clear_table(policy->stats);
78 return count;
79}
80
0a829c5a 81static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
1da177e4 82{
50941607 83 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
84 ssize_t len = 0;
85 int i, j;
86
1aefc75b
RW
87 if (policy->fast_switch_enabled)
88 return 0;
89
58f1df25
VP
90 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
91 len += snprintf(buf + len, PAGE_SIZE - len, " : ");
50941607 92 for (i = 0; i < stats->state_num; i++) {
58f1df25
VP
93 if (len >= PAGE_SIZE)
94 break;
95 len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
50941607 96 stats->freq_table[i]);
58f1df25
VP
97 }
98 if (len >= PAGE_SIZE)
25aca347 99 return PAGE_SIZE;
58f1df25
VP
100
101 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
102
50941607 103 for (i = 0; i < stats->state_num; i++) {
1da177e4
LT
104 if (len >= PAGE_SIZE)
105 break;
58f1df25
VP
106
107 len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
50941607 108 stats->freq_table[i]);
1da177e4 109
50941607 110 for (j = 0; j < stats->state_num; j++) {
1da177e4
LT
111 if (len >= PAGE_SIZE)
112 break;
58f1df25 113 len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
50941607 114 stats->trans_table[i*stats->max_state+j]);
1da177e4 115 }
25aca347
CEB
116 if (len >= PAGE_SIZE)
117 break;
1da177e4
LT
118 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
119 }
f7bc9b20
GS
120
121 if (len >= PAGE_SIZE) {
122 pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n");
123 return -EFBIG;
124 }
1da177e4
LT
125 return len;
126}
df18e504 127cpufreq_freq_attr_ro(trans_table);
1da177e4 128
df18e504
VK
129cpufreq_freq_attr_ro(total_trans);
130cpufreq_freq_attr_ro(time_in_state);
ee7930ee 131cpufreq_freq_attr_wo(reset);
1da177e4
LT
132
133static struct attribute *default_attrs[] = {
df18e504
VK
134 &total_trans.attr,
135 &time_in_state.attr,
ee7930ee 136 &reset.attr,
df18e504 137 &trans_table.attr,
1da177e4
LT
138 NULL
139};
402202e8 140static const struct attribute_group stats_attr_group = {
1da177e4
LT
141 .attrs = default_attrs,
142 .name = "stats"
143};
144
50941607 145static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
1da177e4
LT
146{
147 int index;
50941607
VK
148 for (index = 0; index < stats->max_state; index++)
149 if (stats->freq_table[index] == freq)
1da177e4
LT
150 return index;
151 return -1;
152}
153
1aefc75b 154void cpufreq_stats_free_table(struct cpufreq_policy *policy)
1da177e4 155{
50941607 156 struct cpufreq_stats *stats = policy->stats;
b8eed8af 157
a9aaf291 158 /* Already freed */
50941607 159 if (!stats)
2d13594d
VK
160 return;
161
50941607 162 pr_debug("%s: Free stats table\n", __func__);
2d13594d
VK
163
164 sysfs_remove_group(&policy->kobj, &stats_attr_group);
50941607
VK
165 kfree(stats->time_in_state);
166 kfree(stats);
a9aaf291 167 policy->stats = NULL;
98586ed8 168}
169
1aefc75b 170void cpufreq_stats_create_table(struct cpufreq_policy *policy)
1da177e4 171{
a685c6d0 172 unsigned int i = 0, count = 0, ret = -ENOMEM;
50941607 173 struct cpufreq_stats *stats;
1da177e4 174 unsigned int alloc_size;
55d85293 175 struct cpufreq_frequency_table *pos;
ad4c2302 176
55d85293
VK
177 count = cpufreq_table_count_valid_entries(policy);
178 if (!count)
1aefc75b 179 return;
ad4c2302 180
b8c67448 181 /* stats already initialized */
a9aaf291 182 if (policy->stats)
1aefc75b 183 return;
b8c67448 184
50941607 185 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
a685c6d0 186 if (!stats)
1aefc75b 187 return;
1da177e4 188
1e7586a1 189 alloc_size = count * sizeof(int) + count * sizeof(u64);
1da177e4 190
1da177e4 191 alloc_size += count * count * sizeof(int);
a685c6d0
VK
192
193 /* Allocate memory for time_in_state/freq_table/trans_table in one go */
50941607 194 stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
a685c6d0
VK
195 if (!stats->time_in_state)
196 goto free_stat;
197
50941607 198 stats->freq_table = (unsigned int *)(stats->time_in_state + count);
1da177e4 199
50941607 200 stats->trans_table = stats->freq_table + count;
a685c6d0
VK
201
202 stats->max_state = count;
203
204 /* Find valid-unique entries */
55d85293 205 cpufreq_for_each_valid_entry(pos, policy->freq_table)
50941607
VK
206 if (freq_table_get_index(stats, pos->frequency) == -1)
207 stats->freq_table[i++] = pos->frequency;
a685c6d0 208
490285c6 209 stats->state_num = i;
50941607
VK
210 stats->last_time = get_jiffies_64();
211 stats->last_index = freq_table_get_index(stats, policy->cur);
a685c6d0
VK
212
213 policy->stats = stats;
214 ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
215 if (!ret)
1aefc75b 216 return;
a685c6d0
VK
217
218 /* We failed, release resources */
a9aaf291 219 policy->stats = NULL;
a685c6d0
VK
220 kfree(stats->time_in_state);
221free_stat:
222 kfree(stats);
b3f9ff88
VK
223}
224
1aefc75b
RW
225void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
226 unsigned int new_freq)
1da177e4 227{
1aefc75b 228 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
229 int old_index, new_index;
230
1aefc75b 231 if (!stats) {
a9aaf291 232 pr_debug("%s: No stats found\n", __func__);
1aefc75b 233 return;
a9aaf291
VK
234 }
235
50941607 236 old_index = stats->last_index;
1aefc75b 237 new_index = freq_table_get_index(stats, new_freq);
1da177e4 238
50941607 239 /* We can't do stats->time_in_state[-1]= .. */
1aefc75b
RW
240 if (old_index == -1 || new_index == -1 || old_index == new_index)
241 return;
8edc59d9 242
e7347694
VK
243 cpufreq_stats_update(stats);
244
50941607 245 stats->last_index = new_index;
50941607 246 stats->trans_table[old_index * stats->max_state + new_index]++;
50941607 247 stats->total_trans++;
1da177e4 248}