Userspace governor registers a frequency change notifier at init time, even when no CPU is set to userspace governor. Make it register only when atleast one CPU is using userspace. Signed-off-by: Venkatesh Pallipadi Index: linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_userspace.c =================================================================== --- linux-2.6.22-rc-mm.orig/drivers/cpufreq/cpufreq_userspace.c +++ linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_userspace.c @@ -37,6 +37,7 @@ static unsigned int cpu_set_freq[NR_CPUS static unsigned int cpu_is_managed[NR_CPUS]; static DEFINE_MUTEX (userspace_mutex); +static int cpus_using_userspace_governor; #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) @@ -47,7 +48,11 @@ userspace_cpufreq_notifier(struct notifi { struct cpufreq_freqs *freq = data; - dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", freq->cpu, freq->new); + if (!cpu_is_managed[freq->cpu]) + return 0; + + dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", + freq->cpu, freq->new); cpu_cur_freq[freq->cpu] = freq->new; return 0; @@ -142,6 +147,13 @@ static int cpufreq_governor_userspace(st if (rc) goto start_out; + if (cpus_using_userspace_governor == 0) { + cpufreq_register_notifier( + &userspace_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + cpus_using_userspace_governor++; + cpu_is_managed[cpu] = 1; cpu_min_freq[cpu] = policy->min; cpu_max_freq[cpu] = policy->max; @@ -153,6 +165,13 @@ start_out: break; case CPUFREQ_GOV_STOP: mutex_lock(&userspace_mutex); + cpus_using_userspace_governor--; + if (cpus_using_userspace_governor == 0) { + cpufreq_unregister_notifier( + &userspace_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + cpu_is_managed[cpu] = 0; cpu_min_freq[cpu] = 0; cpu_max_freq[cpu] = 0; @@ -198,7 +217,6 @@ EXPORT_SYMBOL(cpufreq_gov_userspace); static int __init cpufreq_gov_userspace_init(void) { - cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); return cpufreq_register_governor(&cpufreq_gov_userspace); } @@ -206,7 +224,6 @@ static int __init cpufreq_gov_userspace_ static void __exit cpufreq_gov_userspace_exit(void) { cpufreq_unregister_governor(&cpufreq_gov_userspace); - cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } Due to rounding and inexact jiffy accounting, idle_ticks can sometimes be higher than total_ticks. Make sure those cases are handled as zero load case. Signed-off-by: Venkatesh Pallipadi Index: linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_ondemand.c =================================================================== --- linux-2.6.22-rc-mm.orig/drivers/cpufreq/cpufreq_ondemand.c +++ linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_ondemand.c @@ -325,7 +325,7 @@ static struct attribute_group dbs_attr_g static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) { unsigned int idle_ticks, total_ticks; - unsigned int load; + unsigned int load = 0; cputime64_t cur_jiffies; struct cpufreq_policy *policy; @@ -370,7 +370,8 @@ static void dbs_check_cpu(struct cpu_dbs if (tmp_idle_ticks < idle_ticks) idle_ticks = tmp_idle_ticks; } - load = (100 * (total_ticks - idle_ticks)) / total_ticks; + if (likely(total_ticks > idle_ticks)) + load = (100 * (total_ticks - idle_ticks)) / total_ticks; /* Check for frequency increase */ if (load > dbs_tuners_ins.up_threshold) { With tickless kernel and software coordination os P-states, ondemand can look at wrong idle statistics. This can happen when ondemand sampling is happening on CPU 0 and due to software coordination sampling also looks at utilization of CPU 1. If CPU 1 is in tickless state at that moment, its idle statistics will not be uptodate and CPU 0 thinks CPU 1 is idle for less amount of time than it actually is. This can be resolved by looking at all the busy times of CPUs, which is accurate, even with tickless, and use that to determine idle time in a round about way (total time - busy time). Thanks to Arjan for originally reporting this ondemand issue on Lenovo T61. Signed-off-by: Venkatesh Pallipadi Index: linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_ondemand.c =================================================================== --- linux-2.6.22-rc-mm.orig/drivers/cpufreq/cpufreq_ondemand.c +++ linux-2.6.22-rc-mm/drivers/cpufreq/cpufreq_ondemand.c @@ -96,15 +96,25 @@ static struct dbs_tuners { static inline cputime64_t get_cpu_idle_time(unsigned int cpu) { - cputime64_t retval; + cputime64_t idle_time; + cputime64_t cur_jiffies; + cputime64_t busy_time; - retval = cputime64_add(kstat_cpu(cpu).cpustat.idle, - kstat_cpu(cpu).cpustat.iowait); + cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); + busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user, + kstat_cpu(cpu).cpustat.system); - if (dbs_tuners_ins.ignore_nice) - retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice); + busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq); + busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq); + busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal); - return retval; + if (!dbs_tuners_ins.ignore_nice) { + busy_time = cputime64_add(busy_time, + kstat_cpu(cpu).cpustat.nice); + } + + idle_time = cputime64_sub(cur_jiffies, busy_time); + return idle_time; } /* @@ -339,7 +349,8 @@ static void dbs_check_cpu(struct cpu_dbs cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); total_ticks = (unsigned int) cputime64_sub(cur_jiffies, this_dbs_info->prev_cpu_wall); - this_dbs_info->prev_cpu_wall = cur_jiffies; + this_dbs_info->prev_cpu_wall = get_jiffies_64(); + if (!total_ticks) return; /*