]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/cpufreq/cpufreq_stats.c
afs: Fix afs_find_server search loop
[mirror_ubuntu-bionic-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 }
f7bc9b20
GS
121
122 if (len >= PAGE_SIZE) {
123 pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n");
124 return -EFBIG;
125 }
1da177e4
LT
126 return len;
127}
df18e504 128cpufreq_freq_attr_ro(trans_table);
1da177e4 129
df18e504
VK
130cpufreq_freq_attr_ro(total_trans);
131cpufreq_freq_attr_ro(time_in_state);
ee7930ee 132cpufreq_freq_attr_wo(reset);
1da177e4
LT
133
134static struct attribute *default_attrs[] = {
df18e504
VK
135 &total_trans.attr,
136 &time_in_state.attr,
ee7930ee 137 &reset.attr,
df18e504 138 &trans_table.attr,
1da177e4
LT
139 NULL
140};
402202e8 141static const struct attribute_group stats_attr_group = {
1da177e4
LT
142 .attrs = default_attrs,
143 .name = "stats"
144};
145
50941607 146static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
1da177e4
LT
147{
148 int index;
50941607
VK
149 for (index = 0; index < stats->max_state; index++)
150 if (stats->freq_table[index] == freq)
1da177e4
LT
151 return index;
152 return -1;
153}
154
1aefc75b 155void cpufreq_stats_free_table(struct cpufreq_policy *policy)
1da177e4 156{
50941607 157 struct cpufreq_stats *stats = policy->stats;
b8eed8af 158
a9aaf291 159 /* Already freed */
50941607 160 if (!stats)
2d13594d
VK
161 return;
162
50941607 163 pr_debug("%s: Free stats table\n", __func__);
2d13594d
VK
164
165 sysfs_remove_group(&policy->kobj, &stats_attr_group);
50941607
VK
166 kfree(stats->time_in_state);
167 kfree(stats);
a9aaf291 168 policy->stats = NULL;
98586ed8 169}
170
1aefc75b 171void cpufreq_stats_create_table(struct cpufreq_policy *policy)
1da177e4 172{
a685c6d0 173 unsigned int i = 0, count = 0, ret = -ENOMEM;
50941607 174 struct cpufreq_stats *stats;
1da177e4 175 unsigned int alloc_size;
55d85293 176 struct cpufreq_frequency_table *pos;
ad4c2302 177
55d85293
VK
178 count = cpufreq_table_count_valid_entries(policy);
179 if (!count)
1aefc75b 180 return;
ad4c2302 181
b8c67448 182 /* stats already initialized */
a9aaf291 183 if (policy->stats)
1aefc75b 184 return;
b8c67448 185
50941607 186 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
a685c6d0 187 if (!stats)
1aefc75b 188 return;
1da177e4 189
1e7586a1 190 alloc_size = count * sizeof(int) + count * sizeof(u64);
1da177e4 191
1da177e4 192 alloc_size += count * count * sizeof(int);
a685c6d0
VK
193
194 /* Allocate memory for time_in_state/freq_table/trans_table in one go */
50941607 195 stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
a685c6d0
VK
196 if (!stats->time_in_state)
197 goto free_stat;
198
50941607 199 stats->freq_table = (unsigned int *)(stats->time_in_state + count);
1da177e4 200
50941607 201 stats->trans_table = stats->freq_table + count;
a685c6d0
VK
202
203 stats->max_state = count;
204
205 /* Find valid-unique entries */
55d85293 206 cpufreq_for_each_valid_entry(pos, policy->freq_table)
50941607
VK
207 if (freq_table_get_index(stats, pos->frequency) == -1)
208 stats->freq_table[i++] = pos->frequency;
a685c6d0 209
490285c6 210 stats->state_num = i;
50941607
VK
211 stats->last_time = get_jiffies_64();
212 stats->last_index = freq_table_get_index(stats, policy->cur);
a685c6d0
VK
213
214 policy->stats = stats;
215 ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
216 if (!ret)
1aefc75b 217 return;
a685c6d0
VK
218
219 /* We failed, release resources */
a9aaf291 220 policy->stats = NULL;
a685c6d0
VK
221 kfree(stats->time_in_state);
222free_stat:
223 kfree(stats);
b3f9ff88
VK
224}
225
1aefc75b
RW
226void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
227 unsigned int new_freq)
1da177e4 228{
1aefc75b 229 struct cpufreq_stats *stats = policy->stats;
1da177e4
LT
230 int old_index, new_index;
231
1aefc75b 232 if (!stats) {
a9aaf291 233 pr_debug("%s: No stats found\n", __func__);
1aefc75b 234 return;
a9aaf291
VK
235 }
236
50941607 237 old_index = stats->last_index;
1aefc75b 238 new_index = freq_table_get_index(stats, new_freq);
1da177e4 239
50941607 240 /* We can't do stats->time_in_state[-1]= .. */
1aefc75b
RW
241 if (old_index == -1 || new_index == -1 || old_index == new_index)
242 return;
8edc59d9 243
e7347694
VK
244 cpufreq_stats_update(stats);
245
50941607 246 stats->last_index = new_index;
50941607 247 stats->trans_table[old_index * stats->max_state + new_index]++;
50941607 248 stats->total_trans++;
1da177e4 249}