]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/cpufreq/cpufreq_stats.c
cpufreq: intel_pstate: Register when ACPI PCCH is present
[people/arne_f/kernel.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
50941607 30static int 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
LT
37 spin_unlock(&cpufreq_stats_lock);
38 return 0;
39}
40
ee7930ee
MM
41static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
42{
43 unsigned int count = stats->max_state;
44
45 memset(stats->time_in_state, 0, count * sizeof(u64));
ee7930ee 46 memset(stats->trans_table, 0, count * count * sizeof(int));
ee7930ee
MM
47 stats->last_time = get_jiffies_64();
48 stats->total_trans = 0;
49}
50
0a829c5a 51static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
1da177e4 52{
a9aaf291 53 return sprintf(buf, "%d\n", policy->stats->total_trans);
1da177e4
LT
54}
55
0a829c5a 56static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
1da177e4 57{
50941607 58 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
59 ssize_t len = 0;
60 int i;
a9aaf291 61
1aefc75b
RW
62 if (policy->fast_switch_enabled)
63 return 0;
64
50941607
VK
65 cpufreq_stats_update(stats);
66 for (i = 0; i < stats->state_num; i++) {
67 len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
0a829c5a 68 (unsigned long long)
50941607 69 jiffies_64_to_clock_t(stats->time_in_state[i]));
1da177e4
LT
70 }
71 return len;
72}
73
ee7930ee
MM
74static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
75 size_t count)
76{
77 /* We don't care what is written to the attribute. */
78 cpufreq_stats_clear_table(policy->stats);
79 return count;
80}
81
0a829c5a 82static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
1da177e4 83{
50941607 84 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
85 ssize_t len = 0;
86 int i, j;
87
1aefc75b
RW
88 if (policy->fast_switch_enabled)
89 return 0;
90
58f1df25
VP
91 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
92 len += snprintf(buf + len, PAGE_SIZE - len, " : ");
50941607 93 for (i = 0; i < stats->state_num; i++) {
58f1df25
VP
94 if (len >= PAGE_SIZE)
95 break;
96 len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
50941607 97 stats->freq_table[i]);
58f1df25
VP
98 }
99 if (len >= PAGE_SIZE)
25aca347 100 return PAGE_SIZE;
58f1df25
VP
101
102 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
103
50941607 104 for (i = 0; i < stats->state_num; i++) {
1da177e4
LT
105 if (len >= PAGE_SIZE)
106 break;
58f1df25
VP
107
108 len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
50941607 109 stats->freq_table[i]);
1da177e4 110
50941607 111 for (j = 0; j < stats->state_num; j++) {
1da177e4
LT
112 if (len >= PAGE_SIZE)
113 break;
58f1df25 114 len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
50941607 115 stats->trans_table[i*stats->max_state+j]);
1da177e4 116 }
25aca347
CEB
117 if (len >= PAGE_SIZE)
118 break;
1da177e4
LT
119 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
120 }
25aca347
CEB
121 if (len >= PAGE_SIZE)
122 return PAGE_SIZE;
1da177e4
LT
123 return len;
124}
df18e504 125cpufreq_freq_attr_ro(trans_table);
1da177e4 126
df18e504
VK
127cpufreq_freq_attr_ro(total_trans);
128cpufreq_freq_attr_ro(time_in_state);
ee7930ee 129cpufreq_freq_attr_wo(reset);
1da177e4
LT
130
131static struct attribute *default_attrs[] = {
df18e504
VK
132 &total_trans.attr,
133 &time_in_state.attr,
ee7930ee 134 &reset.attr,
df18e504 135 &trans_table.attr,
1da177e4
LT
136 NULL
137};
402202e8 138static const struct attribute_group stats_attr_group = {
1da177e4
LT
139 .attrs = default_attrs,
140 .name = "stats"
141};
142
50941607 143static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
1da177e4
LT
144{
145 int index;
50941607
VK
146 for (index = 0; index < stats->max_state; index++)
147 if (stats->freq_table[index] == freq)
1da177e4
LT
148 return index;
149 return -1;
150}
151
1aefc75b 152void cpufreq_stats_free_table(struct cpufreq_policy *policy)
1da177e4 153{
50941607 154 struct cpufreq_stats *stats = policy->stats;
b8eed8af 155
a9aaf291 156 /* Already freed */
50941607 157 if (!stats)
2d13594d
VK
158 return;
159
50941607 160 pr_debug("%s: Free stats table\n", __func__);
2d13594d
VK
161
162 sysfs_remove_group(&policy->kobj, &stats_attr_group);
50941607
VK
163 kfree(stats->time_in_state);
164 kfree(stats);
a9aaf291 165 policy->stats = NULL;
98586ed8 166}
167
1aefc75b 168void cpufreq_stats_create_table(struct cpufreq_policy *policy)
1da177e4 169{
a685c6d0 170 unsigned int i = 0, count = 0, ret = -ENOMEM;
50941607 171 struct cpufreq_stats *stats;
1da177e4 172 unsigned int alloc_size;
55d85293 173 struct cpufreq_frequency_table *pos;
ad4c2302 174
55d85293
VK
175 count = cpufreq_table_count_valid_entries(policy);
176 if (!count)
1aefc75b 177 return;
ad4c2302 178
b8c67448 179 /* stats already initialized */
a9aaf291 180 if (policy->stats)
1aefc75b 181 return;
b8c67448 182
50941607 183 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
a685c6d0 184 if (!stats)
1aefc75b 185 return;
1da177e4 186
1e7586a1 187 alloc_size = count * sizeof(int) + count * sizeof(u64);
1da177e4 188
1da177e4 189 alloc_size += count * count * sizeof(int);
a685c6d0
VK
190
191 /* Allocate memory for time_in_state/freq_table/trans_table in one go */
50941607 192 stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
a685c6d0
VK
193 if (!stats->time_in_state)
194 goto free_stat;
195
50941607 196 stats->freq_table = (unsigned int *)(stats->time_in_state + count);
1da177e4 197
50941607 198 stats->trans_table = stats->freq_table + count;
a685c6d0
VK
199
200 stats->max_state = count;
201
202 /* Find valid-unique entries */
55d85293 203 cpufreq_for_each_valid_entry(pos, policy->freq_table)
50941607
VK
204 if (freq_table_get_index(stats, pos->frequency) == -1)
205 stats->freq_table[i++] = pos->frequency;
a685c6d0 206
490285c6 207 stats->state_num = i;
50941607
VK
208 stats->last_time = get_jiffies_64();
209 stats->last_index = freq_table_get_index(stats, policy->cur);
a685c6d0
VK
210
211 policy->stats = stats;
212 ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
213 if (!ret)
1aefc75b 214 return;
a685c6d0
VK
215
216 /* We failed, release resources */
a9aaf291 217 policy->stats = NULL;
a685c6d0
VK
218 kfree(stats->time_in_state);
219free_stat:
220 kfree(stats);
b3f9ff88
VK
221}
222
1aefc75b
RW
223void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
224 unsigned int new_freq)
1da177e4 225{
1aefc75b 226 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
227 int old_index, new_index;
228
1aefc75b 229 if (!stats) {
a9aaf291 230 pr_debug("%s: No stats found\n", __func__);
1aefc75b 231 return;
a9aaf291
VK
232 }
233
50941607 234 old_index = stats->last_index;
1aefc75b 235 new_index = freq_table_get_index(stats, new_freq);
1da177e4 236
50941607 237 /* We can't do stats->time_in_state[-1]= .. */
1aefc75b
RW
238 if (old_index == -1 || new_index == -1 || old_index == new_index)
239 return;
8edc59d9 240
e7347694
VK
241 cpufreq_stats_update(stats);
242
50941607 243 stats->last_index = new_index;
50941607 244 stats->trans_table[old_index * stats->max_state + new_index]++;
50941607 245 stats->total_trans++;
1da177e4 246}