11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * drivers/cpufreq/cpufreq_stats.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. 51da177e4SLinus Torvalds * (C) 2004 Zou Nan hai <nanhai.zou@intel.com>. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 91da177e4SLinus Torvalds * published by the Free Software Foundation. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/kernel.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/cpu.h> 151da177e4SLinus Torvalds #include <linux/sysfs.h> 161da177e4SLinus Torvalds #include <linux/cpufreq.h> 175c720d37SPaul Gortmaker #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/jiffies.h> 191da177e4SLinus Torvalds #include <linux/percpu.h> 201da177e4SLinus Torvalds #include <linux/kobject.h> 211da177e4SLinus Torvalds #include <linux/spinlock.h> 22c32b6b8eSAshok Raj #include <linux/notifier.h> 2358f1df25SVenkatesh Pallipadi #include <asm/cputime.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds static spinlock_t cpufreq_stats_lock; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #define CPUFREQ_STATDEVICE_ATTR(_name, _mode, _show) \ 281da177e4SLinus Torvalds static struct freq_attr _attr_##_name = {\ 297b595756STejun Heo .attr = {.name = __stringify(_name), .mode = _mode, }, \ 301da177e4SLinus Torvalds .show = _show,\ 311da177e4SLinus Torvalds }; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds struct cpufreq_stats { 341da177e4SLinus Torvalds unsigned int cpu; 351da177e4SLinus Torvalds unsigned int total_trans; 361da177e4SLinus Torvalds unsigned long long last_time; 371da177e4SLinus Torvalds unsigned int max_state; 381da177e4SLinus Torvalds unsigned int state_num; 391da177e4SLinus Torvalds unsigned int last_index; 401e7586a1SViresh Kumar u64 *time_in_state; 411da177e4SLinus Torvalds unsigned int *freq_table; 421da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 431da177e4SLinus Torvalds unsigned int *trans_table; 441da177e4SLinus Torvalds #endif 451da177e4SLinus Torvalds }; 461da177e4SLinus Torvalds 477a6aedfaSMike Travis static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds struct cpufreq_stats_attribute { 501da177e4SLinus Torvalds struct attribute attr; 511da177e4SLinus Torvalds ssize_t(*show) (struct cpufreq_stats *, char *); 521da177e4SLinus Torvalds }; 531da177e4SLinus Torvalds 540a829c5aSDave Jones static int cpufreq_stats_update(unsigned int cpu) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds struct cpufreq_stats *stat; 5758f1df25SVenkatesh Pallipadi unsigned long long cur_time; 5858f1df25SVenkatesh Pallipadi 5958f1df25SVenkatesh Pallipadi cur_time = get_jiffies_64(); 601da177e4SLinus Torvalds spin_lock(&cpufreq_stats_lock); 617a6aedfaSMike Travis stat = per_cpu(cpufreq_stats_table, cpu); 621da177e4SLinus Torvalds if (stat->time_in_state) 6364861634SMartin Schwidefsky stat->time_in_state[stat->last_index] += 6464861634SMartin Schwidefsky cur_time - stat->last_time; 6558f1df25SVenkatesh Pallipadi stat->last_time = cur_time; 661da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 671da177e4SLinus Torvalds return 0; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 700a829c5aSDave Jones static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) 711da177e4SLinus Torvalds { 727a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 731da177e4SLinus Torvalds if (!stat) 741da177e4SLinus Torvalds return 0; 751da177e4SLinus Torvalds return sprintf(buf, "%d\n", 767a6aedfaSMike Travis per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 790a829c5aSDave Jones static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds ssize_t len = 0; 821da177e4SLinus Torvalds int i; 837a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 841da177e4SLinus Torvalds if (!stat) 851da177e4SLinus Torvalds return 0; 861da177e4SLinus Torvalds cpufreq_stats_update(stat->cpu); 871da177e4SLinus Torvalds for (i = 0; i < stat->state_num; i++) { 8858f1df25SVenkatesh Pallipadi len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], 890a829c5aSDave Jones (unsigned long long) 900a829c5aSDave Jones cputime64_to_clock_t(stat->time_in_state[i])); 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds return len; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 960a829c5aSDave Jones static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds ssize_t len = 0; 991da177e4SLinus Torvalds int i, j; 1001da177e4SLinus Torvalds 1017a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 1021da177e4SLinus Torvalds if (!stat) 1031da177e4SLinus Torvalds return 0; 1041da177e4SLinus Torvalds cpufreq_stats_update(stat->cpu); 10558f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); 10658f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, " : "); 1071da177e4SLinus Torvalds for (i = 0; i < stat->state_num; i++) { 1081da177e4SLinus Torvalds if (len >= PAGE_SIZE) 1091da177e4SLinus Torvalds break; 11058f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", 11158f1df25SVenkatesh Pallipadi stat->freq_table[i]); 11258f1df25SVenkatesh Pallipadi } 11358f1df25SVenkatesh Pallipadi if (len >= PAGE_SIZE) 11425aca347SCesar Eduardo Barros return PAGE_SIZE; 11558f1df25SVenkatesh Pallipadi 11658f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 11758f1df25SVenkatesh Pallipadi 11858f1df25SVenkatesh Pallipadi for (i = 0; i < stat->state_num; i++) { 11958f1df25SVenkatesh Pallipadi if (len >= PAGE_SIZE) 12058f1df25SVenkatesh Pallipadi break; 12158f1df25SVenkatesh Pallipadi 12258f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", 1231da177e4SLinus Torvalds stat->freq_table[i]); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds for (j = 0; j < stat->state_num; j++) { 1261da177e4SLinus Torvalds if (len >= PAGE_SIZE) 1271da177e4SLinus Torvalds break; 12858f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", 1291da177e4SLinus Torvalds stat->trans_table[i*stat->max_state+j]); 1301da177e4SLinus Torvalds } 13125aca347SCesar Eduardo Barros if (len >= PAGE_SIZE) 13225aca347SCesar Eduardo Barros break; 1331da177e4SLinus Torvalds len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 1341da177e4SLinus Torvalds } 13525aca347SCesar Eduardo Barros if (len >= PAGE_SIZE) 13625aca347SCesar Eduardo Barros return PAGE_SIZE; 1371da177e4SLinus Torvalds return len; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table); 1401da177e4SLinus Torvalds #endif 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans); 1431da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 1461da177e4SLinus Torvalds &_attr_total_trans.attr, 1471da177e4SLinus Torvalds &_attr_time_in_state.attr, 1481da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 1491da177e4SLinus Torvalds &_attr_trans_table.attr, 1501da177e4SLinus Torvalds #endif 1511da177e4SLinus Torvalds NULL 1521da177e4SLinus Torvalds }; 1531da177e4SLinus Torvalds static struct attribute_group stats_attr_group = { 1541da177e4SLinus Torvalds .attrs = default_attrs, 1551da177e4SLinus Torvalds .name = "stats" 1561da177e4SLinus Torvalds }; 1571da177e4SLinus Torvalds 1580a829c5aSDave Jones static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds int index; 1611da177e4SLinus Torvalds for (index = 0; index < stat->max_state; index++) 1621da177e4SLinus Torvalds if (stat->freq_table[index] == freq) 1631da177e4SLinus Torvalds return index; 1641da177e4SLinus Torvalds return -1; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 16798586ed8Ssteven finney /* should be called late in the CPU removal sequence so that the stats 16898586ed8Ssteven finney * memory is still available in case someone tries to use it. 16998586ed8Ssteven finney */ 170a3323473SAdrian Bunk static void cpufreq_stats_free_table(unsigned int cpu) 1711da177e4SLinus Torvalds { 1727a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); 173b8eed8afSViresh Kumar 1741da177e4SLinus Torvalds if (stat) { 175b8eed8afSViresh Kumar pr_debug("%s: Free stat table\n", __func__); 1761da177e4SLinus Torvalds kfree(stat->time_in_state); 1771da177e4SLinus Torvalds kfree(stat); 1787a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = NULL; 17998586ed8Ssteven finney } 180b8eed8afSViresh Kumar } 18198586ed8Ssteven finney 18298586ed8Ssteven finney /* must be called early in the CPU removal sequence (before 18398586ed8Ssteven finney * cpufreq_remove_dev) so that policy is still valid. 18498586ed8Ssteven finney */ 18598586ed8Ssteven finney static void cpufreq_stats_free_sysfs(unsigned int cpu) 18698586ed8Ssteven finney { 18798586ed8Ssteven finney struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 188b8eed8afSViresh Kumar if (policy && (cpumask_weight(policy->cpus) == 1)) { 189b8eed8afSViresh Kumar pr_debug("%s: Free sysfs stat\n", __func__); 19098586ed8Ssteven finney sysfs_remove_group(&policy->kobj, &stats_attr_group); 191b8eed8afSViresh Kumar } 1921da177e4SLinus Torvalds if (policy) 1931da177e4SLinus Torvalds cpufreq_cpu_put(policy); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1960a829c5aSDave Jones static int cpufreq_stats_create_table(struct cpufreq_policy *policy, 1971da177e4SLinus Torvalds struct cpufreq_frequency_table *table) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds unsigned int i, j, count = 0, ret = 0; 2001da177e4SLinus Torvalds struct cpufreq_stats *stat; 2011da177e4SLinus Torvalds struct cpufreq_policy *data; 2021da177e4SLinus Torvalds unsigned int alloc_size; 2031da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 2047a6aedfaSMike Travis if (per_cpu(cpufreq_stats_table, cpu)) 2051da177e4SLinus Torvalds return -EBUSY; 2060a829c5aSDave Jones stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); 2070a829c5aSDave Jones if ((stat) == NULL) 2081da177e4SLinus Torvalds return -ENOMEM; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds data = cpufreq_cpu_get(cpu); 211bc7b26fdSDave Jones if (data == NULL) { 212bc7b26fdSDave Jones ret = -EINVAL; 213bc7b26fdSDave Jones goto error_get_fail; 214bc7b26fdSDave Jones } 215bc7b26fdSDave Jones 2160a829c5aSDave Jones ret = sysfs_create_group(&data->kobj, &stats_attr_group); 2170a829c5aSDave Jones if (ret) 2181da177e4SLinus Torvalds goto error_out; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds stat->cpu = cpu; 2217a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = stat; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 2241da177e4SLinus Torvalds unsigned int freq = table[i].frequency; 2251da177e4SLinus Torvalds if (freq == CPUFREQ_ENTRY_INVALID) 2261da177e4SLinus Torvalds continue; 2271da177e4SLinus Torvalds count++; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301e7586a1SViresh Kumar alloc_size = count * sizeof(int) + count * sizeof(u64); 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 2331da177e4SLinus Torvalds alloc_size += count * count * sizeof(int); 2341da177e4SLinus Torvalds #endif 2351da177e4SLinus Torvalds stat->max_state = count; 236e98df50cSDave Jones stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); 2371da177e4SLinus Torvalds if (!stat->time_in_state) { 2381da177e4SLinus Torvalds ret = -ENOMEM; 2391da177e4SLinus Torvalds goto error_out; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds stat->freq_table = (unsigned int *)(stat->time_in_state + count); 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 2441da177e4SLinus Torvalds stat->trans_table = stat->freq_table + count; 2451da177e4SLinus Torvalds #endif 2461da177e4SLinus Torvalds j = 0; 2471da177e4SLinus Torvalds for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 2481da177e4SLinus Torvalds unsigned int freq = table[i].frequency; 2491da177e4SLinus Torvalds if (freq == CPUFREQ_ENTRY_INVALID) 2501da177e4SLinus Torvalds continue; 2511da177e4SLinus Torvalds if (freq_table_get_index(stat, freq) == -1) 2521da177e4SLinus Torvalds stat->freq_table[j++] = freq; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds stat->state_num = j; 2551da177e4SLinus Torvalds spin_lock(&cpufreq_stats_lock); 25658f1df25SVenkatesh Pallipadi stat->last_time = get_jiffies_64(); 2571da177e4SLinus Torvalds stat->last_index = freq_table_get_index(stat, policy->cur); 2581da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 2591da177e4SLinus Torvalds cpufreq_cpu_put(data); 2601da177e4SLinus Torvalds return 0; 2611da177e4SLinus Torvalds error_out: 2621da177e4SLinus Torvalds cpufreq_cpu_put(data); 263b7fb358cSDave Jones error_get_fail: 2641da177e4SLinus Torvalds kfree(stat); 2657a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = NULL; 2661da177e4SLinus Torvalds return ret; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 269b8eed8afSViresh Kumar static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) 270b8eed8afSViresh Kumar { 271b8eed8afSViresh Kumar struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, 272b8eed8afSViresh Kumar policy->last_cpu); 273b8eed8afSViresh Kumar 274b8eed8afSViresh Kumar pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n", 275b8eed8afSViresh Kumar policy->cpu, policy->last_cpu); 276b8eed8afSViresh Kumar per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table, 277b8eed8afSViresh Kumar policy->last_cpu); 278b8eed8afSViresh Kumar per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL; 279b8eed8afSViresh Kumar stat->cpu = policy->cpu; 280b8eed8afSViresh Kumar } 281b8eed8afSViresh Kumar 2820a829c5aSDave Jones static int cpufreq_stat_notifier_policy(struct notifier_block *nb, 2830a829c5aSDave Jones unsigned long val, void *data) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds int ret; 2861da177e4SLinus Torvalds struct cpufreq_policy *policy = data; 2871da177e4SLinus Torvalds struct cpufreq_frequency_table *table; 2881da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 289b8eed8afSViresh Kumar 290b8eed8afSViresh Kumar if (val == CPUFREQ_UPDATE_POLICY_CPU) { 291b8eed8afSViresh Kumar cpufreq_stats_update_policy_cpu(policy); 292b8eed8afSViresh Kumar return 0; 293b8eed8afSViresh Kumar } 294b8eed8afSViresh Kumar 2951da177e4SLinus Torvalds if (val != CPUFREQ_NOTIFY) 2961da177e4SLinus Torvalds return 0; 2971da177e4SLinus Torvalds table = cpufreq_frequency_get_table(cpu); 2981da177e4SLinus Torvalds if (!table) 2991da177e4SLinus Torvalds return 0; 3000a829c5aSDave Jones ret = cpufreq_stats_create_table(policy, table); 3010a829c5aSDave Jones if (ret) 3021da177e4SLinus Torvalds return ret; 3031da177e4SLinus Torvalds return 0; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3060a829c5aSDave Jones static int cpufreq_stat_notifier_trans(struct notifier_block *nb, 3070a829c5aSDave Jones unsigned long val, void *data) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds struct cpufreq_freqs *freq = data; 3101da177e4SLinus Torvalds struct cpufreq_stats *stat; 3111da177e4SLinus Torvalds int old_index, new_index; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if (val != CPUFREQ_POSTCHANGE) 3141da177e4SLinus Torvalds return 0; 3151da177e4SLinus Torvalds 3167a6aedfaSMike Travis stat = per_cpu(cpufreq_stats_table, freq->cpu); 3171da177e4SLinus Torvalds if (!stat) 3181da177e4SLinus Torvalds return 0; 3198edc59d9SVenkatesh Pallipadi 3206501faf8SShaohua Li old_index = stat->last_index; 3211da177e4SLinus Torvalds new_index = freq_table_get_index(stat, freq->new); 3221da177e4SLinus Torvalds 32346a310b8SKonrad Rzeszutek Wilk /* We can't do stat->time_in_state[-1]= .. */ 32446a310b8SKonrad Rzeszutek Wilk if (old_index == -1 || new_index == -1) 3251da177e4SLinus Torvalds return 0; 3261da177e4SLinus Torvalds 32746a310b8SKonrad Rzeszutek Wilk cpufreq_stats_update(freq->cpu); 32846a310b8SKonrad Rzeszutek Wilk 32946a310b8SKonrad Rzeszutek Wilk if (old_index == new_index) 3308edc59d9SVenkatesh Pallipadi return 0; 3318edc59d9SVenkatesh Pallipadi 3321da177e4SLinus Torvalds spin_lock(&cpufreq_stats_lock); 3331da177e4SLinus Torvalds stat->last_index = new_index; 3341da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 3351da177e4SLinus Torvalds stat->trans_table[old_index * stat->max_state + new_index]++; 3361da177e4SLinus Torvalds #endif 3371da177e4SLinus Torvalds stat->total_trans++; 3381da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 3391da177e4SLinus Torvalds return 0; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 34255395ae7SSatyam Sharma static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, 34355395ae7SSatyam Sharma unsigned long action, 34455395ae7SSatyam Sharma void *hcpu) 345c32b6b8eSAshok Raj { 346c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 347c32b6b8eSAshok Raj 348c32b6b8eSAshok Raj switch (action) { 349c32b6b8eSAshok Raj case CPU_ONLINE: 3508bb78442SRafael J. Wysocki case CPU_ONLINE_FROZEN: 351c32b6b8eSAshok Raj cpufreq_update_policy(cpu); 352c32b6b8eSAshok Raj break; 35398586ed8Ssteven finney case CPU_DOWN_PREPARE: 354e3773677STu, Xiaobing case CPU_DOWN_PREPARE_FROZEN: 35598586ed8Ssteven finney cpufreq_stats_free_sysfs(cpu); 35698586ed8Ssteven finney break; 357c32b6b8eSAshok Raj case CPU_DEAD: 3588bb78442SRafael J. Wysocki case CPU_DEAD_FROZEN: 359c32b6b8eSAshok Raj cpufreq_stats_free_table(cpu); 360c32b6b8eSAshok Raj break; 361c32b6b8eSAshok Raj } 362c32b6b8eSAshok Raj return NOTIFY_OK; 363c32b6b8eSAshok Raj } 364c32b6b8eSAshok Raj 36598586ed8Ssteven finney /* priority=1 so this will get called before cpufreq_remove_dev */ 366469057d5SKarthigan Srinivasan static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { 367c32b6b8eSAshok Raj .notifier_call = cpufreq_stat_cpu_callback, 36898586ed8Ssteven finney .priority = 1, 369c32b6b8eSAshok Raj }; 370c32b6b8eSAshok Raj 3711da177e4SLinus Torvalds static struct notifier_block notifier_policy_block = { 3721da177e4SLinus Torvalds .notifier_call = cpufreq_stat_notifier_policy 3731da177e4SLinus Torvalds }; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds static struct notifier_block notifier_trans_block = { 3761da177e4SLinus Torvalds .notifier_call = cpufreq_stat_notifier_trans 3771da177e4SLinus Torvalds }; 3781da177e4SLinus Torvalds 3790a829c5aSDave Jones static int __init cpufreq_stats_init(void) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds int ret; 3821da177e4SLinus Torvalds unsigned int cpu; 383c32b6b8eSAshok Raj 3841da177e4SLinus Torvalds spin_lock_init(&cpufreq_stats_lock); 3850a829c5aSDave Jones ret = cpufreq_register_notifier(¬ifier_policy_block, 3860a829c5aSDave Jones CPUFREQ_POLICY_NOTIFIER); 3870a829c5aSDave Jones if (ret) 3881da177e4SLinus Torvalds return ret; 3891da177e4SLinus Torvalds 39056836fb4SKonstantin Khlebnikov register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); 39156836fb4SKonstantin Khlebnikov for_each_online_cpu(cpu) 39256836fb4SKonstantin Khlebnikov cpufreq_update_policy(cpu); 39356836fb4SKonstantin Khlebnikov 3940a829c5aSDave Jones ret = cpufreq_register_notifier(¬ifier_trans_block, 3950a829c5aSDave Jones CPUFREQ_TRANSITION_NOTIFIER); 3960a829c5aSDave Jones if (ret) { 3971da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_policy_block, 3981da177e4SLinus Torvalds CPUFREQ_POLICY_NOTIFIER); 39956836fb4SKonstantin Khlebnikov unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); 40056836fb4SKonstantin Khlebnikov for_each_online_cpu(cpu) 40156836fb4SKonstantin Khlebnikov cpufreq_stats_free_table(cpu); 4021da177e4SLinus Torvalds return ret; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds return 0; 4061da177e4SLinus Torvalds } 4070a829c5aSDave Jones static void __exit cpufreq_stats_exit(void) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds unsigned int cpu; 410c32b6b8eSAshok Raj 4111da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_policy_block, 4121da177e4SLinus Torvalds CPUFREQ_POLICY_NOTIFIER); 4131da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_trans_block, 4141da177e4SLinus Torvalds CPUFREQ_TRANSITION_NOTIFIER); 41565edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); 416c32b6b8eSAshok Raj for_each_online_cpu(cpu) { 41755395ae7SSatyam Sharma cpufreq_stats_free_table(cpu); 41813f06753SDave Jones cpufreq_stats_free_sysfs(cpu); 419c32b6b8eSAshok Raj } 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>"); 423e08f5f5bSGautham R Shenoy MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats " 424e08f5f5bSGautham R Shenoy "through sysfs filesystem"); 4251da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds module_init(cpufreq_stats_init); 4281da177e4SLinus Torvalds module_exit(cpufreq_stats_exit); 429