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> 131da177e4SLinus Torvalds #include <linux/sysdev.h> 141da177e4SLinus Torvalds #include <linux/cpu.h> 151da177e4SLinus Torvalds #include <linux/sysfs.h> 161da177e4SLinus Torvalds #include <linux/cpufreq.h> 171da177e4SLinus Torvalds #include <linux/jiffies.h> 181da177e4SLinus Torvalds #include <linux/percpu.h> 191da177e4SLinus Torvalds #include <linux/kobject.h> 201da177e4SLinus Torvalds #include <linux/spinlock.h> 21c32b6b8eSAshok Raj #include <linux/notifier.h> 2258f1df25SVenkatesh Pallipadi #include <asm/cputime.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static spinlock_t cpufreq_stats_lock; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \ 271da177e4SLinus Torvalds static struct freq_attr _attr_##_name = {\ 287b595756STejun Heo .attr = {.name = __stringify(_name), .mode = _mode, }, \ 291da177e4SLinus Torvalds .show = _show,\ 301da177e4SLinus Torvalds }; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds struct cpufreq_stats { 331da177e4SLinus Torvalds unsigned int cpu; 341da177e4SLinus Torvalds unsigned int total_trans; 351da177e4SLinus Torvalds unsigned long long last_time; 361da177e4SLinus Torvalds unsigned int max_state; 371da177e4SLinus Torvalds unsigned int state_num; 381da177e4SLinus Torvalds unsigned int last_index; 3958f1df25SVenkatesh Pallipadi cputime64_t *time_in_state; 401da177e4SLinus Torvalds unsigned int *freq_table; 411da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 421da177e4SLinus Torvalds unsigned int *trans_table; 431da177e4SLinus Torvalds #endif 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 467a6aedfaSMike Travis static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds struct cpufreq_stats_attribute { 491da177e4SLinus Torvalds struct attribute attr; 501da177e4SLinus Torvalds ssize_t(*show) (struct cpufreq_stats *, char *); 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds static int 541da177e4SLinus Torvalds 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) 6358f1df25SVenkatesh Pallipadi stat->time_in_state[stat->last_index] = 6458f1df25SVenkatesh Pallipadi cputime64_add(stat->time_in_state[stat->last_index], 6558f1df25SVenkatesh Pallipadi cputime_sub(cur_time, stat->last_time)); 6658f1df25SVenkatesh Pallipadi stat->last_time = cur_time; 671da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 681da177e4SLinus Torvalds return 0; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds static ssize_t 721da177e4SLinus Torvalds show_total_trans(struct cpufreq_policy *policy, char *buf) 731da177e4SLinus Torvalds { 747a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 751da177e4SLinus Torvalds if (!stat) 761da177e4SLinus Torvalds return 0; 771da177e4SLinus Torvalds return sprintf(buf, "%d\n", 787a6aedfaSMike Travis per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static ssize_t 821da177e4SLinus Torvalds show_time_in_state(struct cpufreq_policy *policy, char *buf) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds ssize_t len = 0; 851da177e4SLinus Torvalds int i; 867a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 871da177e4SLinus Torvalds if (!stat) 881da177e4SLinus Torvalds return 0; 891da177e4SLinus Torvalds cpufreq_stats_update(stat->cpu); 901da177e4SLinus Torvalds for (i = 0; i < stat->state_num; i++) { 9158f1df25SVenkatesh Pallipadi len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], 9258f1df25SVenkatesh Pallipadi (unsigned long long)cputime64_to_clock_t(stat->time_in_state[i])); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds return len; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 981da177e4SLinus Torvalds static ssize_t 991da177e4SLinus Torvalds show_trans_table(struct cpufreq_policy *policy, char *buf) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds ssize_t len = 0; 1021da177e4SLinus Torvalds int i, j; 1031da177e4SLinus Torvalds 1047a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); 1051da177e4SLinus Torvalds if (!stat) 1061da177e4SLinus Torvalds return 0; 1071da177e4SLinus Torvalds cpufreq_stats_update(stat->cpu); 10858f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); 10958f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, " : "); 1101da177e4SLinus Torvalds for (i = 0; i < stat->state_num; i++) { 1111da177e4SLinus Torvalds if (len >= PAGE_SIZE) 1121da177e4SLinus Torvalds break; 11358f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", 11458f1df25SVenkatesh Pallipadi stat->freq_table[i]); 11558f1df25SVenkatesh Pallipadi } 11658f1df25SVenkatesh Pallipadi if (len >= PAGE_SIZE) 11725aca347SCesar Eduardo Barros return PAGE_SIZE; 11858f1df25SVenkatesh Pallipadi 11958f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 12058f1df25SVenkatesh Pallipadi 12158f1df25SVenkatesh Pallipadi for (i = 0; i < stat->state_num; i++) { 12258f1df25SVenkatesh Pallipadi if (len >= PAGE_SIZE) 12358f1df25SVenkatesh Pallipadi break; 12458f1df25SVenkatesh Pallipadi 12558f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", 1261da177e4SLinus Torvalds stat->freq_table[i]); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds for (j = 0; j < stat->state_num; j++) { 1291da177e4SLinus Torvalds if (len >= PAGE_SIZE) 1301da177e4SLinus Torvalds break; 13158f1df25SVenkatesh Pallipadi len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", 1321da177e4SLinus Torvalds stat->trans_table[i*stat->max_state+j]); 1331da177e4SLinus Torvalds } 13425aca347SCesar Eduardo Barros if (len >= PAGE_SIZE) 13525aca347SCesar Eduardo Barros break; 1361da177e4SLinus Torvalds len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 1371da177e4SLinus Torvalds } 13825aca347SCesar Eduardo Barros if (len >= PAGE_SIZE) 13925aca347SCesar Eduardo Barros return PAGE_SIZE; 1401da177e4SLinus Torvalds return len; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table); 1431da177e4SLinus Torvalds #endif 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans); 1461da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 1491da177e4SLinus Torvalds &_attr_total_trans.attr, 1501da177e4SLinus Torvalds &_attr_time_in_state.attr, 1511da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 1521da177e4SLinus Torvalds &_attr_trans_table.attr, 1531da177e4SLinus Torvalds #endif 1541da177e4SLinus Torvalds NULL 1551da177e4SLinus Torvalds }; 1561da177e4SLinus Torvalds static struct attribute_group stats_attr_group = { 1571da177e4SLinus Torvalds .attrs = default_attrs, 1581da177e4SLinus Torvalds .name = "stats" 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds static int 1621da177e4SLinus Torvalds freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds int index; 1651da177e4SLinus Torvalds for (index = 0; index < stat->max_state; index++) 1661da177e4SLinus Torvalds if (stat->freq_table[index] == freq) 1671da177e4SLinus Torvalds return index; 1681da177e4SLinus Torvalds return -1; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 171a3323473SAdrian Bunk static void cpufreq_stats_free_table(unsigned int cpu) 1721da177e4SLinus Torvalds { 1737a6aedfaSMike Travis struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); 1741da177e4SLinus Torvalds struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 1751da177e4SLinus Torvalds if (policy && policy->cpu == cpu) 1761da177e4SLinus Torvalds sysfs_remove_group(&policy->kobj, &stats_attr_group); 1771da177e4SLinus Torvalds if (stat) { 1781da177e4SLinus Torvalds kfree(stat->time_in_state); 1791da177e4SLinus Torvalds kfree(stat); 1801da177e4SLinus Torvalds } 1817a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = NULL; 1821da177e4SLinus Torvalds if (policy) 1831da177e4SLinus Torvalds cpufreq_cpu_put(policy); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds static int 1871da177e4SLinus Torvalds cpufreq_stats_create_table (struct cpufreq_policy *policy, 1881da177e4SLinus Torvalds struct cpufreq_frequency_table *table) 1891da177e4SLinus Torvalds { 1901da177e4SLinus Torvalds unsigned int i, j, count = 0, ret = 0; 1911da177e4SLinus Torvalds struct cpufreq_stats *stat; 1921da177e4SLinus Torvalds struct cpufreq_policy *data; 1931da177e4SLinus Torvalds unsigned int alloc_size; 1941da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 1957a6aedfaSMike Travis if (per_cpu(cpufreq_stats_table, cpu)) 1961da177e4SLinus Torvalds return -EBUSY; 197e98df50cSDave Jones if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL) 1981da177e4SLinus Torvalds return -ENOMEM; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds data = cpufreq_cpu_get(cpu); 201bc7b26fdSDave Jones if (data == NULL) { 202bc7b26fdSDave Jones ret = -EINVAL; 203bc7b26fdSDave Jones goto error_get_fail; 204bc7b26fdSDave Jones } 205bc7b26fdSDave Jones 2061da177e4SLinus Torvalds if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group))) 2071da177e4SLinus Torvalds goto error_out; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds stat->cpu = cpu; 2107a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = stat; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 2131da177e4SLinus Torvalds unsigned int freq = table[i].frequency; 2141da177e4SLinus Torvalds if (freq == CPUFREQ_ENTRY_INVALID) 2151da177e4SLinus Torvalds continue; 2161da177e4SLinus Torvalds count++; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 21958f1df25SVenkatesh Pallipadi alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 2221da177e4SLinus Torvalds alloc_size += count * count * sizeof(int); 2231da177e4SLinus Torvalds #endif 2241da177e4SLinus Torvalds stat->max_state = count; 225e98df50cSDave Jones stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); 2261da177e4SLinus Torvalds if (!stat->time_in_state) { 2271da177e4SLinus Torvalds ret = -ENOMEM; 2281da177e4SLinus Torvalds goto error_out; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds stat->freq_table = (unsigned int *)(stat->time_in_state + count); 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 2331da177e4SLinus Torvalds stat->trans_table = stat->freq_table + count; 2341da177e4SLinus Torvalds #endif 2351da177e4SLinus Torvalds j = 0; 2361da177e4SLinus Torvalds for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 2371da177e4SLinus Torvalds unsigned int freq = table[i].frequency; 2381da177e4SLinus Torvalds if (freq == CPUFREQ_ENTRY_INVALID) 2391da177e4SLinus Torvalds continue; 2401da177e4SLinus Torvalds if (freq_table_get_index(stat, freq) == -1) 2411da177e4SLinus Torvalds stat->freq_table[j++] = freq; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds stat->state_num = j; 2441da177e4SLinus Torvalds spin_lock(&cpufreq_stats_lock); 24558f1df25SVenkatesh Pallipadi stat->last_time = get_jiffies_64(); 2461da177e4SLinus Torvalds stat->last_index = freq_table_get_index(stat, policy->cur); 2471da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 2481da177e4SLinus Torvalds cpufreq_cpu_put(data); 2491da177e4SLinus Torvalds return 0; 2501da177e4SLinus Torvalds error_out: 2511da177e4SLinus Torvalds cpufreq_cpu_put(data); 252b7fb358cSDave Jones error_get_fail: 2531da177e4SLinus Torvalds kfree(stat); 2547a6aedfaSMike Travis per_cpu(cpufreq_stats_table, cpu) = NULL; 2551da177e4SLinus Torvalds return ret; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds static int 2591da177e4SLinus Torvalds cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val, 2601da177e4SLinus Torvalds void *data) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds int ret; 2631da177e4SLinus Torvalds struct cpufreq_policy *policy = data; 2641da177e4SLinus Torvalds struct cpufreq_frequency_table *table; 2651da177e4SLinus Torvalds unsigned int cpu = policy->cpu; 2661da177e4SLinus Torvalds if (val != CPUFREQ_NOTIFY) 2671da177e4SLinus Torvalds return 0; 2681da177e4SLinus Torvalds table = cpufreq_frequency_get_table(cpu); 2691da177e4SLinus Torvalds if (!table) 2701da177e4SLinus Torvalds return 0; 2711da177e4SLinus Torvalds if ((ret = cpufreq_stats_create_table(policy, table))) 2721da177e4SLinus Torvalds return ret; 2731da177e4SLinus Torvalds return 0; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static int 2771da177e4SLinus Torvalds cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, 2781da177e4SLinus Torvalds void *data) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds struct cpufreq_freqs *freq = data; 2811da177e4SLinus Torvalds struct cpufreq_stats *stat; 2821da177e4SLinus Torvalds int old_index, new_index; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds if (val != CPUFREQ_POSTCHANGE) 2851da177e4SLinus Torvalds return 0; 2861da177e4SLinus Torvalds 2877a6aedfaSMike Travis stat = per_cpu(cpufreq_stats_table, freq->cpu); 2881da177e4SLinus Torvalds if (!stat) 2891da177e4SLinus Torvalds return 0; 2908edc59d9SVenkatesh Pallipadi 2916501faf8SShaohua Li old_index = stat->last_index; 2921da177e4SLinus Torvalds new_index = freq_table_get_index(stat, freq->new); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds cpufreq_stats_update(freq->cpu); 2951da177e4SLinus Torvalds if (old_index == new_index) 2961da177e4SLinus Torvalds return 0; 2971da177e4SLinus Torvalds 2988edc59d9SVenkatesh Pallipadi if (old_index == -1 || new_index == -1) 2998edc59d9SVenkatesh Pallipadi return 0; 3008edc59d9SVenkatesh Pallipadi 3011da177e4SLinus Torvalds spin_lock(&cpufreq_stats_lock); 3021da177e4SLinus Torvalds stat->last_index = new_index; 3031da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS 3041da177e4SLinus Torvalds stat->trans_table[old_index * stat->max_state + new_index]++; 3051da177e4SLinus Torvalds #endif 3061da177e4SLinus Torvalds stat->total_trans++; 3071da177e4SLinus Torvalds spin_unlock(&cpufreq_stats_lock); 3081da177e4SLinus Torvalds return 0; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 31155395ae7SSatyam Sharma static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, 31255395ae7SSatyam Sharma unsigned long action, 31355395ae7SSatyam Sharma void *hcpu) 314c32b6b8eSAshok Raj { 315c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 316c32b6b8eSAshok Raj 317c32b6b8eSAshok Raj switch (action) { 318c32b6b8eSAshok Raj case CPU_ONLINE: 3198bb78442SRafael J. Wysocki case CPU_ONLINE_FROZEN: 320c32b6b8eSAshok Raj cpufreq_update_policy(cpu); 321c32b6b8eSAshok Raj break; 322c32b6b8eSAshok Raj case CPU_DEAD: 3238bb78442SRafael J. Wysocki case CPU_DEAD_FROZEN: 324c32b6b8eSAshok Raj cpufreq_stats_free_table(cpu); 325c32b6b8eSAshok Raj break; 326c32b6b8eSAshok Raj } 327c32b6b8eSAshok Raj return NOTIFY_OK; 328c32b6b8eSAshok Raj } 329c32b6b8eSAshok Raj 330f6ebef30SSam Ravnborg static struct notifier_block cpufreq_stat_cpu_notifier __refdata = 331c32b6b8eSAshok Raj { 332c32b6b8eSAshok Raj .notifier_call = cpufreq_stat_cpu_callback, 333c32b6b8eSAshok Raj }; 334c32b6b8eSAshok Raj 3351da177e4SLinus Torvalds static struct notifier_block notifier_policy_block = { 3361da177e4SLinus Torvalds .notifier_call = cpufreq_stat_notifier_policy 3371da177e4SLinus Torvalds }; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds static struct notifier_block notifier_trans_block = { 3401da177e4SLinus Torvalds .notifier_call = cpufreq_stat_notifier_trans 3411da177e4SLinus Torvalds }; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds static int 3441da177e4SLinus Torvalds __init cpufreq_stats_init(void) 3451da177e4SLinus Torvalds { 3461da177e4SLinus Torvalds int ret; 3471da177e4SLinus Torvalds unsigned int cpu; 348c32b6b8eSAshok Raj 3491da177e4SLinus Torvalds spin_lock_init(&cpufreq_stats_lock); 3501da177e4SLinus Torvalds if ((ret = cpufreq_register_notifier(¬ifier_policy_block, 3511da177e4SLinus Torvalds CPUFREQ_POLICY_NOTIFIER))) 3521da177e4SLinus Torvalds return ret; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds if ((ret = cpufreq_register_notifier(¬ifier_trans_block, 3551da177e4SLinus Torvalds CPUFREQ_TRANSITION_NOTIFIER))) { 3561da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_policy_block, 3571da177e4SLinus Torvalds CPUFREQ_POLICY_NOTIFIER); 3581da177e4SLinus Torvalds return ret; 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds 36165edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); 362c32b6b8eSAshok Raj for_each_online_cpu(cpu) { 36355395ae7SSatyam Sharma cpufreq_update_policy(cpu); 364c32b6b8eSAshok Raj } 3651da177e4SLinus Torvalds return 0; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds static void 3681da177e4SLinus Torvalds __exit cpufreq_stats_exit(void) 3691da177e4SLinus Torvalds { 3701da177e4SLinus Torvalds unsigned int cpu; 371c32b6b8eSAshok Raj 3721da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_policy_block, 3731da177e4SLinus Torvalds CPUFREQ_POLICY_NOTIFIER); 3741da177e4SLinus Torvalds cpufreq_unregister_notifier(¬ifier_trans_block, 3751da177e4SLinus Torvalds CPUFREQ_TRANSITION_NOTIFIER); 37665edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); 377c32b6b8eSAshok Raj for_each_online_cpu(cpu) { 37855395ae7SSatyam Sharma cpufreq_stats_free_table(cpu); 379c32b6b8eSAshok Raj } 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); 383e08f5f5bSGautham R Shenoy MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " 384e08f5f5bSGautham R Shenoy "through sysfs filesystem"); 3851da177e4SLinus Torvalds MODULE_LICENSE ("GPL"); 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds module_init(cpufreq_stats_init); 3881da177e4SLinus Torvalds module_exit(cpufreq_stats_exit); 389