Merge branch 'linux-linaro-lsk-v3.10' into linux-linaro-lsk-v3.10-android
[firefly-linux-kernel-4.4.55.git] / drivers / cpufreq / cpufreq_stats.c
1 /*
2  *  drivers/cpufreq/cpufreq_stats.c
3  *
4  *  Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
5  *  (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
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
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/cpu.h>
15 #include <linux/sysfs.h>
16 #include <linux/cpufreq.h>
17 #include <linux/module.h>
18 #include <linux/jiffies.h>
19 #include <linux/percpu.h>
20 #include <linux/kobject.h>
21 #include <linux/spinlock.h>
22 #include <linux/notifier.h>
23 #include <linux/sort.h>
24 #include <linux/err.h>
25 #include <linux/of.h>
26 #include <linux/sched.h>
27 #include <asm/cputime.h>
28 #ifdef CONFIG_BL_SWITCHER
29 #include <asm/bL_switcher.h>
30 #endif
31
32 static spinlock_t cpufreq_stats_lock;
33
34 struct cpufreq_stats {
35         unsigned int cpu;
36         unsigned int total_trans;
37         unsigned long long  last_time;
38         unsigned int max_state;
39         unsigned int state_num;
40         unsigned int last_index;
41         u64 *time_in_state;
42         unsigned int *freq_table;
43 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
44         unsigned int *trans_table;
45 #endif
46 };
47
48 struct all_cpufreq_stats {
49         unsigned int state_num;
50         cputime64_t *time_in_state;
51         unsigned int *freq_table;
52 };
53
54 struct cpufreq_power_stats {
55         unsigned int state_num;
56         unsigned int *curr;
57         unsigned int *freq_table;
58 };
59
60 struct all_freq_table {
61         unsigned int *freq_table;
62         unsigned int table_size;
63 };
64
65 static struct all_freq_table *all_freq_table;
66
67 static DEFINE_PER_CPU(struct all_cpufreq_stats *, all_cpufreq_stats);
68 static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
69 static DEFINE_PER_CPU(struct cpufreq_power_stats *, cpufreq_power_stats);
70
71 struct cpufreq_stats_attribute {
72         struct attribute attr;
73         ssize_t(*show) (struct cpufreq_stats *, char *);
74 };
75
76 static int cpufreq_stats_update(unsigned int cpu)
77 {
78         struct cpufreq_stats *stat;
79         struct all_cpufreq_stats *all_stat;
80         unsigned long long cur_time;
81
82         cur_time = get_jiffies_64();
83         spin_lock(&cpufreq_stats_lock);
84         stat = per_cpu(cpufreq_stats_table, cpu);
85         all_stat = per_cpu(all_cpufreq_stats, cpu);
86         if (!stat) {
87                 spin_unlock(&cpufreq_stats_lock);
88                 return 0;
89         }
90         if (stat->time_in_state) {
91                 stat->time_in_state[stat->last_index] +=
92                         cur_time - stat->last_time;
93                 if (all_stat)
94                         all_stat->time_in_state[stat->last_index] +=
95                                         cur_time - stat->last_time;
96         }
97         stat->last_time = cur_time;
98         spin_unlock(&cpufreq_stats_lock);
99         return 0;
100 }
101
102 static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
103 {
104         struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
105         if (!stat)
106                 return 0;
107         return sprintf(buf, "%d\n",
108                         per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
109 }
110
111 static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
112 {
113         ssize_t len = 0;
114         int i;
115         struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
116         if (!stat)
117                 return 0;
118         cpufreq_stats_update(stat->cpu);
119         for (i = 0; i < stat->state_num; i++) {
120                 len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
121                         (unsigned long long)
122                         jiffies_64_to_clock_t(stat->time_in_state[i]));
123         }
124         return len;
125 }
126
127 static int get_index_all_cpufreq_stat(struct all_cpufreq_stats *all_stat,
128                 unsigned int freq)
129 {
130         int i;
131         if (!all_stat)
132                 return -1;
133         for (i = 0; i < all_stat->state_num; i++) {
134                 if (all_stat->freq_table[i] == freq)
135                         return i;
136         }
137         return -1;
138 }
139
140 void acct_update_power(struct task_struct *task, cputime_t cputime) {
141         struct cpufreq_power_stats *powerstats;
142         struct cpufreq_stats *stats;
143         unsigned int cpu_num, curr;
144
145         if (!task)
146                 return;
147         cpu_num = task_cpu(task);
148         powerstats = per_cpu(cpufreq_power_stats, cpu_num);
149         stats = per_cpu(cpufreq_stats_table, cpu_num);
150         if (!powerstats || !stats)
151                 return;
152
153         curr = powerstats->curr[stats->last_index];
154         task->cpu_power += curr * cputime_to_usecs(cputime);
155 }
156 EXPORT_SYMBOL_GPL(acct_update_power);
157
158 static ssize_t show_current_in_state(struct kobject *kobj,
159                 struct kobj_attribute *attr, char *buf)
160 {
161         ssize_t len = 0;
162         unsigned int i, cpu;
163         struct cpufreq_power_stats *powerstats;
164
165         spin_lock(&cpufreq_stats_lock);
166         for_each_possible_cpu(cpu) {
167                 powerstats = per_cpu(cpufreq_power_stats, cpu);
168                 if (!powerstats)
169                         continue;
170                 len += scnprintf(buf + len, PAGE_SIZE - len, "CPU%d:", cpu);
171                 for (i = 0; i < powerstats->state_num; i++)
172                         len += scnprintf(buf + len, PAGE_SIZE - len,
173                                         "%d=%d ", powerstats->freq_table[i],
174                                         powerstats->curr[i]);
175                 len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
176         }
177         spin_unlock(&cpufreq_stats_lock);
178         return len;
179 }
180
181 static ssize_t show_all_time_in_state(struct kobject *kobj,
182                 struct kobj_attribute *attr, char *buf)
183 {
184         ssize_t len = 0;
185         unsigned int i, cpu, freq, index;
186         struct all_cpufreq_stats *all_stat;
187         struct cpufreq_policy *policy;
188
189         len += scnprintf(buf + len, PAGE_SIZE - len, "freq\t\t");
190         for_each_possible_cpu(cpu) {
191                 len += scnprintf(buf + len, PAGE_SIZE - len, "cpu%d\t\t", cpu);
192                 if (cpu_online(cpu))
193                         cpufreq_stats_update(cpu);
194         }
195
196         if (!all_freq_table)
197                 goto out;
198         for (i = 0; i < all_freq_table->table_size; i++) {
199                 freq = all_freq_table->freq_table[i];
200                 len += scnprintf(buf + len, PAGE_SIZE - len, "\n%u\t\t", freq);
201                 for_each_possible_cpu(cpu) {
202                         policy = cpufreq_cpu_get(cpu);
203                         if (policy == NULL)
204                                 continue;
205                         all_stat = per_cpu(all_cpufreq_stats, policy->cpu);
206                         index = get_index_all_cpufreq_stat(all_stat, freq);
207                         if (index != -1) {
208                                 len += scnprintf(buf + len, PAGE_SIZE - len,
209                                         "%llu\t\t", (unsigned long long)
210                                         cputime64_to_clock_t(all_stat->time_in_state[index]));
211                         } else {
212                                 len += scnprintf(buf + len, PAGE_SIZE - len,
213                                                 "N/A\t\t");
214                         }
215                         cpufreq_cpu_put(policy);
216                 }
217         }
218
219 out:
220         len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
221         return len;
222 }
223
224 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
225 static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
226 {
227         ssize_t len = 0;
228         int i, j;
229
230         struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
231         if (!stat)
232                 return 0;
233         cpufreq_stats_update(stat->cpu);
234         len += snprintf(buf + len, PAGE_SIZE - len, "   From  :    To\n");
235         len += snprintf(buf + len, PAGE_SIZE - len, "         : ");
236         for (i = 0; i < stat->state_num; i++) {
237                 if (len >= PAGE_SIZE)
238                         break;
239                 len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
240                                 stat->freq_table[i]);
241         }
242         if (len >= PAGE_SIZE)
243                 return PAGE_SIZE;
244
245         len += snprintf(buf + len, PAGE_SIZE - len, "\n");
246
247         for (i = 0; i < stat->state_num; i++) {
248                 if (len >= PAGE_SIZE)
249                         break;
250
251                 len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
252                                 stat->freq_table[i]);
253
254                 for (j = 0; j < stat->state_num; j++)   {
255                         if (len >= PAGE_SIZE)
256                                 break;
257                         len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
258                                         stat->trans_table[i*stat->max_state+j]);
259                 }
260                 if (len >= PAGE_SIZE)
261                         break;
262                 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
263         }
264         if (len >= PAGE_SIZE)
265                 return PAGE_SIZE;
266         return len;
267 }
268 cpufreq_freq_attr_ro(trans_table);
269 #endif
270
271 cpufreq_freq_attr_ro(total_trans);
272 cpufreq_freq_attr_ro(time_in_state);
273
274 static struct attribute *default_attrs[] = {
275         &total_trans.attr,
276         &time_in_state.attr,
277 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
278         &trans_table.attr,
279 #endif
280         NULL
281 };
282 static struct attribute_group stats_attr_group = {
283         .attrs = default_attrs,
284         .name = "stats"
285 };
286
287 static struct kobj_attribute _attr_all_time_in_state = __ATTR(all_time_in_state,
288                 0444, show_all_time_in_state, NULL);
289
290 static struct kobj_attribute _attr_current_in_state = __ATTR(current_in_state,
291                 0444, show_current_in_state, NULL);
292
293 static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
294 {
295         int index;
296         for (index = 0; index < stat->max_state; index++)
297                 if (stat->freq_table[index] == freq)
298                         return index;
299         return -1;
300 }
301
302 /* should be called late in the CPU removal sequence so that the stats
303  * memory is still available in case someone tries to use it.
304  */
305 static void cpufreq_stats_free_table(unsigned int cpu)
306 {
307         struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
308
309         if (stat) {
310                 pr_debug("%s: Free stat table\n", __func__);
311                 kfree(stat->time_in_state);
312                 kfree(stat);
313                 per_cpu(cpufreq_stats_table, cpu) = NULL;
314         }
315 }
316
317 /* must be called early in the CPU removal sequence (before
318  * cpufreq_remove_dev) so that policy is still valid.
319  */
320 static void cpufreq_stats_free_sysfs(unsigned int cpu)
321 {
322         struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
323
324         if (!policy)
325                 return;
326
327         if (!cpufreq_frequency_get_table(cpu))
328                 goto put_ref;
329
330         if (!policy_is_shared(policy)) {
331                 pr_debug("%s: Free sysfs stat\n", __func__);
332                 sysfs_remove_group(&policy->kobj, &stats_attr_group);
333         }
334
335 put_ref:
336         cpufreq_cpu_put(policy);
337 }
338
339 static void cpufreq_allstats_free(void)
340 {
341         int cpu;
342         struct all_cpufreq_stats *all_stat;
343
344         sysfs_remove_file(cpufreq_global_kobject,
345                                                 &_attr_all_time_in_state.attr);
346
347         for_each_possible_cpu(cpu) {
348                 all_stat = per_cpu(all_cpufreq_stats, cpu);
349                 if (!all_stat)
350                         continue;
351                 kfree(all_stat->time_in_state);
352                 kfree(all_stat);
353                 per_cpu(all_cpufreq_stats, cpu) = NULL;
354         }
355         if (all_freq_table) {
356                 kfree(all_freq_table->freq_table);
357                 kfree(all_freq_table);
358                 all_freq_table = NULL;
359         }
360 }
361
362 static void cpufreq_powerstats_free(void)
363 {
364         int cpu;
365         struct cpufreq_power_stats *powerstats;
366
367         sysfs_remove_file(cpufreq_global_kobject, &_attr_current_in_state.attr);
368
369         for_each_possible_cpu(cpu) {
370                 powerstats = per_cpu(cpufreq_power_stats, cpu);
371                 if (!powerstats)
372                         continue;
373                 kfree(powerstats->curr);
374                 kfree(powerstats);
375                 per_cpu(cpufreq_power_stats, cpu) = NULL;
376         }
377 }
378
379 static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
380                 struct cpufreq_frequency_table *table, int count)
381 {
382         unsigned int i, j, ret = 0;
383         struct cpufreq_stats *stat;
384         struct cpufreq_policy *data;
385         unsigned int alloc_size;
386         unsigned int cpu = policy->cpu;
387         if (per_cpu(cpufreq_stats_table, cpu))
388                 return -EBUSY;
389         stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
390         if ((stat) == NULL)
391                 return -ENOMEM;
392
393         data = cpufreq_cpu_get(cpu);
394         if (data == NULL) {
395                 ret = -EINVAL;
396                 goto error_get_fail;
397         }
398
399         ret = sysfs_create_group(&data->kobj, &stats_attr_group);
400         if (ret)
401                 goto error_out;
402
403         stat->cpu = cpu;
404         per_cpu(cpufreq_stats_table, cpu) = stat;
405
406
407         alloc_size = count * sizeof(int) + count * sizeof(u64);
408
409 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
410         alloc_size += count * count * sizeof(int);
411 #endif
412         stat->max_state = count;
413         stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
414         if (!stat->time_in_state) {
415                 ret = -ENOMEM;
416                 goto error_out;
417         }
418         stat->freq_table = (unsigned int *)(stat->time_in_state + count);
419
420 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
421         stat->trans_table = stat->freq_table + count;
422 #endif
423         j = 0;
424         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
425                 unsigned int freq = table[i].frequency;
426                 if (freq == CPUFREQ_ENTRY_INVALID)
427                         continue;
428                 if (freq_table_get_index(stat, freq) == -1)
429                         stat->freq_table[j++] = freq;
430         }
431         stat->state_num = j;
432         spin_lock(&cpufreq_stats_lock);
433         stat->last_time = get_jiffies_64();
434         stat->last_index = freq_table_get_index(stat, policy->cur);
435         spin_unlock(&cpufreq_stats_lock);
436         cpufreq_cpu_put(data);
437         return 0;
438 error_out:
439         cpufreq_cpu_put(data);
440 error_get_fail:
441         kfree(stat);
442         per_cpu(cpufreq_stats_table, cpu) = NULL;
443         return ret;
444 }
445
446 static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
447 {
448         struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
449                         policy->last_cpu);
450
451         pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
452                         policy->cpu, policy->last_cpu);
453         per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
454                         policy->last_cpu);
455         per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
456         stat->cpu = policy->cpu;
457 }
458
459 static void cpufreq_powerstats_create(unsigned int cpu,
460                 struct cpufreq_frequency_table *table, int count) {
461         unsigned int alloc_size, i = 0, j = 0, ret = 0;
462         struct cpufreq_power_stats *powerstats;
463         struct device_node *cpu_node;
464         char device_path[16];
465
466         powerstats = kzalloc(sizeof(struct cpufreq_power_stats),
467                         GFP_KERNEL);
468         if (!powerstats)
469                 return;
470
471         /* Allocate memory for freq table per cpu as well as clockticks per
472          * freq*/
473         alloc_size = count * sizeof(unsigned int) +
474                 count * sizeof(unsigned int);
475         powerstats->curr = kzalloc(alloc_size, GFP_KERNEL);
476         if (!powerstats->curr) {
477                 kfree(powerstats);
478                 return;
479         }
480         powerstats->freq_table = powerstats->curr + count;
481
482         spin_lock(&cpufreq_stats_lock);
483         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END && j < count; i++) {
484                 unsigned int freq = table[i].frequency;
485
486                 if (freq == CPUFREQ_ENTRY_INVALID)
487                         continue;
488                 powerstats->freq_table[j++] = freq;
489         }
490         powerstats->state_num = j;
491
492         snprintf(device_path, sizeof(device_path), "/cpus/cpu@%d", cpu);
493         cpu_node = of_find_node_by_path(device_path);
494         if (cpu_node) {
495                 ret = of_property_read_u32_array(cpu_node, "current",
496                                 powerstats->curr, count);
497                 if (ret) {
498                         kfree(powerstats->curr);
499                         kfree(powerstats);
500                         powerstats = NULL;
501                 }
502         }
503         per_cpu(cpufreq_power_stats, cpu) = powerstats;
504         spin_unlock(&cpufreq_stats_lock);
505 }
506
507 static int compare_for_sort(const void *lhs_ptr, const void *rhs_ptr)
508 {
509         unsigned int lhs = *(const unsigned int *)(lhs_ptr);
510         unsigned int rhs = *(const unsigned int *)(rhs_ptr);
511         if (lhs < rhs)
512                 return -1;
513         if (lhs > rhs)
514                 return 1;
515         return 0;
516 }
517
518 static bool check_all_freq_table(unsigned int freq)
519 {
520         int i;
521         for (i = 0; i < all_freq_table->table_size; i++) {
522                 if (freq == all_freq_table->freq_table[i])
523                         return true;
524         }
525         return false;
526 }
527
528 static void create_all_freq_table(void)
529 {
530         all_freq_table = kzalloc(sizeof(struct all_freq_table),
531                         GFP_KERNEL);
532         if (!all_freq_table)
533                 pr_warn("could not allocate memory for all_freq_table\n");
534         return;
535 }
536
537 static void add_all_freq_table(unsigned int freq)
538 {
539         unsigned int size;
540         size = sizeof(unsigned int) * (all_freq_table->table_size + 1);
541         all_freq_table->freq_table = krealloc(all_freq_table->freq_table,
542                         size, GFP_ATOMIC);
543         if (IS_ERR(all_freq_table->freq_table)) {
544                 pr_warn("Could not reallocate memory for freq_table\n");
545                 all_freq_table->freq_table = NULL;
546                 return;
547         }
548         all_freq_table->freq_table[all_freq_table->table_size++] = freq;
549 }
550
551 static void cpufreq_allstats_create(unsigned int cpu,
552                 struct cpufreq_frequency_table *table, int count)
553 {
554         int i , j = 0;
555         unsigned int alloc_size;
556         struct all_cpufreq_stats *all_stat;
557         bool sort_needed = false;
558
559         all_stat = kzalloc(sizeof(struct all_cpufreq_stats),
560                         GFP_KERNEL);
561         if (!all_stat) {
562                 pr_warn("Cannot allocate memory for cpufreq stats\n");
563                 return;
564         }
565
566         /*Allocate memory for freq table per cpu as well as clockticks per freq*/
567         alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
568         all_stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
569         if (!all_stat->time_in_state) {
570                 pr_warn("Cannot allocate memory for cpufreq time_in_state\n");
571                 kfree(all_stat);
572                 all_stat = NULL;
573                 return;
574         }
575         all_stat->freq_table = (unsigned int *)
576                 (all_stat->time_in_state + count);
577
578         spin_lock(&cpufreq_stats_lock);
579         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
580                 unsigned int freq = table[i].frequency;
581                 if (freq == CPUFREQ_ENTRY_INVALID)
582                         continue;
583                 all_stat->freq_table[j++] = freq;
584                 if (all_freq_table && !check_all_freq_table(freq)) {
585                         add_all_freq_table(freq);
586                         sort_needed = true;
587                 }
588         }
589         if (sort_needed)
590                 sort(all_freq_table->freq_table, all_freq_table->table_size,
591                                 sizeof(unsigned int), &compare_for_sort, NULL);
592         all_stat->state_num = j;
593         per_cpu(all_cpufreq_stats, cpu) = all_stat;
594         spin_unlock(&cpufreq_stats_lock);
595 }
596
597 static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
598                 unsigned long val, void *data)
599 {
600         int ret, count = 0, i;
601         struct cpufreq_policy *policy = data;
602         struct cpufreq_frequency_table *table;
603         unsigned int cpu = policy->cpu;
604
605         if (val == CPUFREQ_UPDATE_POLICY_CPU) {
606                 cpufreq_stats_update_policy_cpu(policy);
607                 return 0;
608         }
609
610         if (val != CPUFREQ_NOTIFY)
611                 return 0;
612         table = cpufreq_frequency_get_table(cpu);
613         if (!table)
614                 return 0;
615
616         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
617                 unsigned int freq = table[i].frequency;
618
619                 if (freq == CPUFREQ_ENTRY_INVALID)
620                         continue;
621                 count++;
622         }
623
624         if (!per_cpu(all_cpufreq_stats, cpu))
625                 cpufreq_allstats_create(cpu, table, count);
626
627         if (!per_cpu(cpufreq_power_stats, cpu))
628                 cpufreq_powerstats_create(cpu, table, count);
629
630         ret = cpufreq_stats_create_table(policy, table, count);
631         if (ret)
632                 return ret;
633         return 0;
634 }
635
636 static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
637                 unsigned long val, void *data)
638 {
639         struct cpufreq_freqs *freq = data;
640         struct cpufreq_stats *stat;
641         int old_index, new_index;
642
643         if (val != CPUFREQ_POSTCHANGE)
644                 return 0;
645
646         stat = per_cpu(cpufreq_stats_table, freq->cpu);
647         if (!stat)
648                 return 0;
649
650         old_index = stat->last_index;
651         new_index = freq_table_get_index(stat, freq->new);
652
653         /* We can't do stat->time_in_state[-1]= .. */
654         if (old_index == -1 || new_index == -1)
655                 return 0;
656
657         cpufreq_stats_update(freq->cpu);
658
659         if (old_index == new_index)
660                 return 0;
661
662         spin_lock(&cpufreq_stats_lock);
663         stat->last_index = new_index;
664 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
665         stat->trans_table[old_index * stat->max_state + new_index]++;
666 #endif
667         stat->total_trans++;
668         spin_unlock(&cpufreq_stats_lock);
669         return 0;
670 }
671
672 static int cpufreq_stats_create_table_cpu(unsigned int cpu)
673 {
674         struct cpufreq_policy *policy;
675         struct cpufreq_frequency_table *table;
676         int ret = -ENODEV, i, count = 0;
677
678         policy = cpufreq_cpu_get(cpu);
679         if (!policy)
680                 return -ENODEV;
681
682         table = cpufreq_frequency_get_table(cpu);
683         if (!table)
684                 goto out;
685
686         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
687                 unsigned int freq = table[i].frequency;
688
689                 if (freq == CPUFREQ_ENTRY_INVALID)
690                         continue;
691                 count++;
692         }
693
694         if (!per_cpu(all_cpufreq_stats, cpu))
695                 cpufreq_allstats_create(cpu, table, count);
696
697         if (!per_cpu(cpufreq_power_stats, cpu))
698                 cpufreq_powerstats_create(cpu, table, count);
699
700         ret = cpufreq_stats_create_table(policy, table, count);
701
702 out:
703         cpufreq_cpu_put(policy);
704         return ret;
705 }
706
707 static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
708                                                unsigned long action,
709                                                void *hcpu)
710 {
711         unsigned int cpu = (unsigned long)hcpu;
712
713         switch (action) {
714         case CPU_ONLINE:
715         case CPU_ONLINE_FROZEN:
716                 cpufreq_update_policy(cpu);
717                 break;
718         case CPU_DOWN_PREPARE:
719         case CPU_DOWN_PREPARE_FROZEN:
720                 cpufreq_stats_free_sysfs(cpu);
721                 break;
722         case CPU_DEAD:
723         case CPU_DEAD_FROZEN:
724                 cpufreq_stats_free_table(cpu);
725                 break;
726         case CPU_DOWN_FAILED:
727         case CPU_DOWN_FAILED_FROZEN:
728                 cpufreq_stats_create_table_cpu(cpu);
729                 break;
730         }
731         return NOTIFY_OK;
732 }
733
734 /* priority=1 so this will get called before cpufreq_remove_dev */
735 static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
736         .notifier_call = cpufreq_stat_cpu_callback,
737         .priority = 1,
738 };
739
740 static struct notifier_block notifier_policy_block = {
741         .notifier_call = cpufreq_stat_notifier_policy
742 };
743
744 static struct notifier_block notifier_trans_block = {
745         .notifier_call = cpufreq_stat_notifier_trans
746 };
747
748 static int cpufreq_stats_setup(void)
749 {
750         int ret;
751         unsigned int cpu;
752
753         spin_lock_init(&cpufreq_stats_lock);
754         ret = cpufreq_register_notifier(&notifier_policy_block,
755                                 CPUFREQ_POLICY_NOTIFIER);
756         if (ret)
757                 return ret;
758
759         register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
760         for_each_online_cpu(cpu)
761                 cpufreq_update_policy(cpu);
762
763         ret = cpufreq_register_notifier(&notifier_trans_block,
764                                 CPUFREQ_TRANSITION_NOTIFIER);
765         if (ret) {
766                 cpufreq_unregister_notifier(&notifier_policy_block,
767                                 CPUFREQ_POLICY_NOTIFIER);
768                 unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
769                 for_each_online_cpu(cpu)
770                         cpufreq_stats_free_table(cpu);
771                 return ret;
772         }
773
774         create_all_freq_table();
775         ret = sysfs_create_file(cpufreq_global_kobject,
776                         &_attr_all_time_in_state.attr);
777         if (ret)
778                 pr_warn("Cannot create sysfs file for cpufreq stats\n");
779
780         ret = sysfs_create_file(cpufreq_global_kobject,
781                         &_attr_current_in_state.attr);
782         if (ret)
783                 pr_warn("Cannot create sysfs file for cpufreq current stats\n");
784
785         return 0;
786 }
787
788 static void cpufreq_stats_cleanup(void)
789 {
790         unsigned int cpu;
791
792         cpufreq_unregister_notifier(&notifier_policy_block,
793                         CPUFREQ_POLICY_NOTIFIER);
794         cpufreq_unregister_notifier(&notifier_trans_block,
795                         CPUFREQ_TRANSITION_NOTIFIER);
796         unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
797         for_each_online_cpu(cpu) {
798                 cpufreq_stats_free_table(cpu);
799                 cpufreq_stats_free_sysfs(cpu);
800         }
801         cpufreq_allstats_free();
802         cpufreq_powerstats_free();
803 }
804
805 #ifdef CONFIG_BL_SWITCHER
806 static int cpufreq_stats_switcher_notifier(struct notifier_block *nfb,
807                                         unsigned long action, void *_arg)
808 {
809         switch (action) {
810         case BL_NOTIFY_PRE_ENABLE:
811         case BL_NOTIFY_PRE_DISABLE:
812                 cpufreq_stats_cleanup();
813                 break;
814
815         case BL_NOTIFY_POST_ENABLE:
816         case BL_NOTIFY_POST_DISABLE:
817                 cpufreq_stats_setup();
818                 break;
819
820         default:
821                 return NOTIFY_DONE;
822         }
823
824         return NOTIFY_OK;
825 }
826
827 static struct notifier_block switcher_notifier = {
828         .notifier_call = cpufreq_stats_switcher_notifier,
829 };
830 #endif
831
832 static int __init cpufreq_stats_init(void)
833 {
834         int ret;
835         spin_lock_init(&cpufreq_stats_lock);
836
837         ret = cpufreq_stats_setup();
838 #ifdef CONFIG_BL_SWITCHER
839         if (!ret)
840                 bL_switcher_register_notifier(&switcher_notifier);
841 #endif
842         return ret;
843 }
844
845 static void __exit cpufreq_stats_exit(void)
846 {
847 #ifdef CONFIG_BL_SWITCHER
848         bL_switcher_unregister_notifier(&switcher_notifier);
849 #endif
850         cpufreq_stats_cleanup();
851 }
852
853 MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
854 MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
855                                 "through sysfs filesystem");
856 MODULE_LICENSE("GPL");
857
858 module_init(cpufreq_stats_init);
859 module_exit(cpufreq_stats_exit);