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/config.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/sysdev.h>
151da177e4SLinus Torvalds #include <linux/cpu.h>
161da177e4SLinus Torvalds #include <linux/sysfs.h>
171da177e4SLinus Torvalds #include <linux/cpufreq.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 = {\
291da177e4SLinus Torvalds 	.attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
301da177e4SLinus Torvalds 		.mode = _mode, }, \
311da177e4SLinus Torvalds 	.show = _show,\
321da177e4SLinus Torvalds };
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds struct cpufreq_stats {
351da177e4SLinus Torvalds 	unsigned int cpu;
361da177e4SLinus Torvalds 	unsigned int total_trans;
371da177e4SLinus Torvalds 	unsigned long long  last_time;
381da177e4SLinus Torvalds 	unsigned int max_state;
391da177e4SLinus Torvalds 	unsigned int state_num;
401da177e4SLinus Torvalds 	unsigned int last_index;
4158f1df25SVenkatesh Pallipadi 	cputime64_t *time_in_state;
421da177e4SLinus Torvalds 	unsigned int *freq_table;
431da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
441da177e4SLinus Torvalds 	unsigned int *trans_table;
451da177e4SLinus Torvalds #endif
461da177e4SLinus Torvalds };
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds static struct cpufreq_stats *cpufreq_stats_table[NR_CPUS];
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds struct cpufreq_stats_attribute {
511da177e4SLinus Torvalds 	struct attribute attr;
521da177e4SLinus Torvalds 	ssize_t(*show) (struct cpufreq_stats *, char *);
531da177e4SLinus Torvalds };
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds static int
561da177e4SLinus Torvalds cpufreq_stats_update (unsigned int cpu)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	struct cpufreq_stats *stat;
5958f1df25SVenkatesh Pallipadi 	unsigned long long cur_time;
6058f1df25SVenkatesh Pallipadi 
6158f1df25SVenkatesh Pallipadi 	cur_time = get_jiffies_64();
621da177e4SLinus Torvalds 	spin_lock(&cpufreq_stats_lock);
631da177e4SLinus Torvalds 	stat = cpufreq_stats_table[cpu];
641da177e4SLinus Torvalds 	if (stat->time_in_state)
6558f1df25SVenkatesh Pallipadi 		stat->time_in_state[stat->last_index] =
6658f1df25SVenkatesh Pallipadi 			cputime64_add(stat->time_in_state[stat->last_index],
6758f1df25SVenkatesh Pallipadi 				      cputime_sub(cur_time, stat->last_time));
6858f1df25SVenkatesh Pallipadi 	stat->last_time = cur_time;
691da177e4SLinus Torvalds 	spin_unlock(&cpufreq_stats_lock);
701da177e4SLinus Torvalds 	return 0;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds static ssize_t
741da177e4SLinus Torvalds show_total_trans(struct cpufreq_policy *policy, char *buf)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds 	struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
771da177e4SLinus Torvalds 	if (!stat)
781da177e4SLinus Torvalds 		return 0;
791da177e4SLinus Torvalds 	return sprintf(buf, "%d\n",
801da177e4SLinus Torvalds 			cpufreq_stats_table[stat->cpu]->total_trans);
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static ssize_t
841da177e4SLinus Torvalds show_time_in_state(struct cpufreq_policy *policy, char *buf)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	ssize_t len = 0;
871da177e4SLinus Torvalds 	int i;
881da177e4SLinus Torvalds 	struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
891da177e4SLinus Torvalds 	if (!stat)
901da177e4SLinus Torvalds 		return 0;
911da177e4SLinus Torvalds 	cpufreq_stats_update(stat->cpu);
921da177e4SLinus Torvalds 	for (i = 0; i < stat->state_num; i++) {
9358f1df25SVenkatesh Pallipadi 		len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
9458f1df25SVenkatesh Pallipadi 			(unsigned long long)cputime64_to_clock_t(stat->time_in_state[i]));
951da177e4SLinus Torvalds 	}
961da177e4SLinus Torvalds 	return len;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
1001da177e4SLinus Torvalds static ssize_t
1011da177e4SLinus Torvalds show_trans_table(struct cpufreq_policy *policy, char *buf)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds 	ssize_t len = 0;
1041da177e4SLinus Torvalds 	int i, j;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
1071da177e4SLinus Torvalds 	if (!stat)
1081da177e4SLinus Torvalds 		return 0;
1091da177e4SLinus Torvalds 	cpufreq_stats_update(stat->cpu);
11058f1df25SVenkatesh Pallipadi 	len += snprintf(buf + len, PAGE_SIZE - len, "   From  :    To\n");
11158f1df25SVenkatesh Pallipadi 	len += snprintf(buf + len, PAGE_SIZE - len, "         : ");
1121da177e4SLinus Torvalds 	for (i = 0; i < stat->state_num; i++) {
1131da177e4SLinus Torvalds 		if (len >= PAGE_SIZE)
1141da177e4SLinus Torvalds 			break;
11558f1df25SVenkatesh Pallipadi 		len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
11658f1df25SVenkatesh Pallipadi 				stat->freq_table[i]);
11758f1df25SVenkatesh Pallipadi 	}
11858f1df25SVenkatesh Pallipadi 	if (len >= PAGE_SIZE)
11958f1df25SVenkatesh Pallipadi 		return len;
12058f1df25SVenkatesh Pallipadi 
12158f1df25SVenkatesh Pallipadi 	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
12258f1df25SVenkatesh Pallipadi 
12358f1df25SVenkatesh Pallipadi 	for (i = 0; i < stat->state_num; i++) {
12458f1df25SVenkatesh Pallipadi 		if (len >= PAGE_SIZE)
12558f1df25SVenkatesh Pallipadi 			break;
12658f1df25SVenkatesh Pallipadi 
12758f1df25SVenkatesh Pallipadi 		len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
1281da177e4SLinus Torvalds 				stat->freq_table[i]);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 		for (j = 0; j < stat->state_num; j++)   {
1311da177e4SLinus Torvalds 			if (len >= PAGE_SIZE)
1321da177e4SLinus Torvalds 				break;
13358f1df25SVenkatesh Pallipadi 			len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
1341da177e4SLinus Torvalds 					stat->trans_table[i*stat->max_state+j]);
1351da177e4SLinus Torvalds 		}
1361da177e4SLinus Torvalds 		len += snprintf(buf + len, PAGE_SIZE - len, "\n");
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 	return len;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
1411da177e4SLinus Torvalds #endif
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
1441da177e4SLinus Torvalds CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds static struct attribute *default_attrs[] = {
1471da177e4SLinus Torvalds 	&_attr_total_trans.attr,
1481da177e4SLinus Torvalds 	&_attr_time_in_state.attr,
1491da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
1501da177e4SLinus Torvalds 	&_attr_trans_table.attr,
1511da177e4SLinus Torvalds #endif
1521da177e4SLinus Torvalds 	NULL
1531da177e4SLinus Torvalds };
1541da177e4SLinus Torvalds static struct attribute_group stats_attr_group = {
1551da177e4SLinus Torvalds 	.attrs = default_attrs,
1561da177e4SLinus Torvalds 	.name = "stats"
1571da177e4SLinus Torvalds };
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds static int
1601da177e4SLinus Torvalds freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	int index;
1631da177e4SLinus Torvalds 	for (index = 0; index < stat->max_state; index++)
1641da177e4SLinus Torvalds 		if (stat->freq_table[index] == freq)
1651da177e4SLinus Torvalds 			return index;
1661da177e4SLinus Torvalds 	return -1;
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds static void
1701da177e4SLinus Torvalds cpufreq_stats_free_table (unsigned int cpu)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
1731da177e4SLinus Torvalds 	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
1741da177e4SLinus Torvalds 	if (policy && policy->cpu == cpu)
1751da177e4SLinus Torvalds 		sysfs_remove_group(&policy->kobj, &stats_attr_group);
1761da177e4SLinus Torvalds 	if (stat) {
1771da177e4SLinus Torvalds 		kfree(stat->time_in_state);
1781da177e4SLinus Torvalds 		kfree(stat);
1791da177e4SLinus Torvalds 	}
1801da177e4SLinus Torvalds 	cpufreq_stats_table[cpu] = NULL;
1811da177e4SLinus Torvalds 	if (policy)
1821da177e4SLinus Torvalds 		cpufreq_cpu_put(policy);
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds static int
1861da177e4SLinus Torvalds cpufreq_stats_create_table (struct cpufreq_policy *policy,
1871da177e4SLinus Torvalds 		struct cpufreq_frequency_table *table)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds 	unsigned int i, j, count = 0, ret = 0;
1901da177e4SLinus Torvalds 	struct cpufreq_stats *stat;
1911da177e4SLinus Torvalds 	struct cpufreq_policy *data;
1921da177e4SLinus Torvalds 	unsigned int alloc_size;
1931da177e4SLinus Torvalds 	unsigned int cpu = policy->cpu;
1941da177e4SLinus Torvalds 	if (cpufreq_stats_table[cpu])
1951da177e4SLinus Torvalds 		return -EBUSY;
196e98df50cSDave Jones 	if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL)
1971da177e4SLinus Torvalds 		return -ENOMEM;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	data = cpufreq_cpu_get(cpu);
200bc7b26fdSDave Jones 	if (data == NULL) {
201bc7b26fdSDave Jones 		ret = -EINVAL;
202bc7b26fdSDave Jones 		goto error_get_fail;
203bc7b26fdSDave Jones 	}
204bc7b26fdSDave Jones 
2051da177e4SLinus Torvalds 	if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group)))
2061da177e4SLinus Torvalds 		goto error_out;
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	stat->cpu = cpu;
2091da177e4SLinus Torvalds 	cpufreq_stats_table[cpu] = stat;
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
2121da177e4SLinus Torvalds 		unsigned int freq = table[i].frequency;
2131da177e4SLinus Torvalds 		if (freq == CPUFREQ_ENTRY_INVALID)
2141da177e4SLinus Torvalds 			continue;
2151da177e4SLinus Torvalds 		count++;
2161da177e4SLinus Torvalds 	}
2171da177e4SLinus Torvalds 
21858f1df25SVenkatesh Pallipadi 	alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
2211da177e4SLinus Torvalds 	alloc_size += count * count * sizeof(int);
2221da177e4SLinus Torvalds #endif
2231da177e4SLinus Torvalds 	stat->max_state = count;
224e98df50cSDave Jones 	stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
2251da177e4SLinus Torvalds 	if (!stat->time_in_state) {
2261da177e4SLinus Torvalds 		ret = -ENOMEM;
2271da177e4SLinus Torvalds 		goto error_out;
2281da177e4SLinus Torvalds 	}
2291da177e4SLinus Torvalds 	stat->freq_table = (unsigned int *)(stat->time_in_state + count);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
2321da177e4SLinus Torvalds 	stat->trans_table = stat->freq_table + count;
2331da177e4SLinus Torvalds #endif
2341da177e4SLinus Torvalds 	j = 0;
2351da177e4SLinus Torvalds 	for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
2361da177e4SLinus Torvalds 		unsigned int freq = table[i].frequency;
2371da177e4SLinus Torvalds 		if (freq == CPUFREQ_ENTRY_INVALID)
2381da177e4SLinus Torvalds 			continue;
2391da177e4SLinus Torvalds 		if (freq_table_get_index(stat, freq) == -1)
2401da177e4SLinus Torvalds 			stat->freq_table[j++] = freq;
2411da177e4SLinus Torvalds 	}
2421da177e4SLinus Torvalds 	stat->state_num = j;
2431da177e4SLinus Torvalds 	spin_lock(&cpufreq_stats_lock);
24458f1df25SVenkatesh Pallipadi 	stat->last_time = get_jiffies_64();
2451da177e4SLinus Torvalds 	stat->last_index = freq_table_get_index(stat, policy->cur);
2461da177e4SLinus Torvalds 	spin_unlock(&cpufreq_stats_lock);
2471da177e4SLinus Torvalds 	cpufreq_cpu_put(data);
2481da177e4SLinus Torvalds 	return 0;
2491da177e4SLinus Torvalds error_out:
2501da177e4SLinus Torvalds 	cpufreq_cpu_put(data);
251b7fb358cSDave Jones error_get_fail:
2521da177e4SLinus Torvalds 	kfree(stat);
2531da177e4SLinus Torvalds 	cpufreq_stats_table[cpu] = NULL;
2541da177e4SLinus Torvalds 	return ret;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds static int
2581da177e4SLinus Torvalds cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
2591da177e4SLinus Torvalds 		void *data)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds 	int ret;
2621da177e4SLinus Torvalds 	struct cpufreq_policy *policy = data;
2631da177e4SLinus Torvalds 	struct cpufreq_frequency_table *table;
2641da177e4SLinus Torvalds 	unsigned int cpu = policy->cpu;
2651da177e4SLinus Torvalds 	if (val != CPUFREQ_NOTIFY)
2661da177e4SLinus Torvalds 		return 0;
2671da177e4SLinus Torvalds 	table = cpufreq_frequency_get_table(cpu);
2681da177e4SLinus Torvalds 	if (!table)
2691da177e4SLinus Torvalds 		return 0;
2701da177e4SLinus Torvalds 	if ((ret = cpufreq_stats_create_table(policy, table)))
2711da177e4SLinus Torvalds 		return ret;
2721da177e4SLinus Torvalds 	return 0;
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds static int
2761da177e4SLinus Torvalds cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
2771da177e4SLinus Torvalds 		void *data)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	struct cpufreq_freqs *freq = data;
2801da177e4SLinus Torvalds 	struct cpufreq_stats *stat;
2811da177e4SLinus Torvalds 	int old_index, new_index;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	if (val != CPUFREQ_POSTCHANGE)
2841da177e4SLinus Torvalds 		return 0;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	stat = cpufreq_stats_table[freq->cpu];
2871da177e4SLinus Torvalds 	if (!stat)
2881da177e4SLinus Torvalds 		return 0;
2891da177e4SLinus Torvalds 	old_index = freq_table_get_index(stat, freq->old);
2901da177e4SLinus Torvalds 	new_index = freq_table_get_index(stat, freq->new);
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	cpufreq_stats_update(freq->cpu);
2931da177e4SLinus Torvalds 	if (old_index == new_index)
2941da177e4SLinus Torvalds 		return 0;
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	spin_lock(&cpufreq_stats_lock);
2971da177e4SLinus Torvalds 	stat->last_index = new_index;
2981da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
2991da177e4SLinus Torvalds 	stat->trans_table[old_index * stat->max_state + new_index]++;
3001da177e4SLinus Torvalds #endif
3011da177e4SLinus Torvalds 	stat->total_trans++;
3021da177e4SLinus Torvalds 	spin_unlock(&cpufreq_stats_lock);
3031da177e4SLinus Torvalds 	return 0;
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds 
306bb1a813dSSam Ravnborg static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
307c32b6b8eSAshok Raj 					unsigned long action, void *hcpu)
308c32b6b8eSAshok Raj {
309c32b6b8eSAshok Raj 	unsigned int cpu = (unsigned long)hcpu;
310c32b6b8eSAshok Raj 
311c32b6b8eSAshok Raj 	switch (action) {
312c32b6b8eSAshok Raj 	case CPU_ONLINE:
313c32b6b8eSAshok Raj 		cpufreq_update_policy(cpu);
314c32b6b8eSAshok Raj 		break;
315c32b6b8eSAshok Raj 	case CPU_DEAD:
316c32b6b8eSAshok Raj 		cpufreq_stats_free_table(cpu);
317c32b6b8eSAshok Raj 		break;
318c32b6b8eSAshok Raj 	}
319c32b6b8eSAshok Raj 	return NOTIFY_OK;
320c32b6b8eSAshok Raj }
321c32b6b8eSAshok Raj 
322c32b6b8eSAshok Raj static struct notifier_block cpufreq_stat_cpu_notifier =
323c32b6b8eSAshok Raj {
324c32b6b8eSAshok Raj 	.notifier_call = cpufreq_stat_cpu_callback,
325c32b6b8eSAshok Raj };
326c32b6b8eSAshok Raj 
3271da177e4SLinus Torvalds static struct notifier_block notifier_policy_block = {
3281da177e4SLinus Torvalds 	.notifier_call = cpufreq_stat_notifier_policy
3291da177e4SLinus Torvalds };
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds static struct notifier_block notifier_trans_block = {
3321da177e4SLinus Torvalds 	.notifier_call = cpufreq_stat_notifier_trans
3331da177e4SLinus Torvalds };
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds static int
3361da177e4SLinus Torvalds __init cpufreq_stats_init(void)
3371da177e4SLinus Torvalds {
3381da177e4SLinus Torvalds 	int ret;
3391da177e4SLinus Torvalds 	unsigned int cpu;
340c32b6b8eSAshok Raj 
3411da177e4SLinus Torvalds 	spin_lock_init(&cpufreq_stats_lock);
3421da177e4SLinus Torvalds 	if ((ret = cpufreq_register_notifier(&notifier_policy_block,
3431da177e4SLinus Torvalds 				CPUFREQ_POLICY_NOTIFIER)))
3441da177e4SLinus Torvalds 		return ret;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	if ((ret = cpufreq_register_notifier(&notifier_trans_block,
3471da177e4SLinus Torvalds 				CPUFREQ_TRANSITION_NOTIFIER))) {
3481da177e4SLinus Torvalds 		cpufreq_unregister_notifier(&notifier_policy_block,
3491da177e4SLinus Torvalds 				CPUFREQ_POLICY_NOTIFIER);
3501da177e4SLinus Torvalds 		return ret;
3511da177e4SLinus Torvalds 	}
3521da177e4SLinus Torvalds 
35365edc68cSChandra Seetharaman 	register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
354c32b6b8eSAshok Raj 	lock_cpu_hotplug();
355c32b6b8eSAshok Raj 	for_each_online_cpu(cpu) {
356c32b6b8eSAshok Raj 		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
357c32b6b8eSAshok Raj 			(void *)(long)cpu);
358c32b6b8eSAshok Raj 	}
359c32b6b8eSAshok Raj 	unlock_cpu_hotplug();
3601da177e4SLinus Torvalds 	return 0;
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds static void
3631da177e4SLinus Torvalds __exit cpufreq_stats_exit(void)
3641da177e4SLinus Torvalds {
3651da177e4SLinus Torvalds 	unsigned int cpu;
366c32b6b8eSAshok Raj 
3671da177e4SLinus Torvalds 	cpufreq_unregister_notifier(&notifier_policy_block,
3681da177e4SLinus Torvalds 			CPUFREQ_POLICY_NOTIFIER);
3691da177e4SLinus Torvalds 	cpufreq_unregister_notifier(&notifier_trans_block,
3701da177e4SLinus Torvalds 			CPUFREQ_TRANSITION_NOTIFIER);
37165edc68cSChandra Seetharaman 	unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
372c32b6b8eSAshok Raj 	lock_cpu_hotplug();
373c32b6b8eSAshok Raj 	for_each_online_cpu(cpu) {
374c32b6b8eSAshok Raj 		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
375c32b6b8eSAshok Raj 			(void *)(long)cpu);
376c32b6b8eSAshok Raj 	}
377c32b6b8eSAshok Raj 	unlock_cpu_hotplug();
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
3811da177e4SLinus Torvalds MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats through sysfs filesystem");
3821da177e4SLinus Torvalds MODULE_LICENSE ("GPL");
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds module_init(cpufreq_stats_init);
3851da177e4SLinus Torvalds module_exit(cpufreq_stats_exit);
386