diff options
-rw-r--r-- | PATCHCFG | 4 | ||||
-rw-r--r-- | patches/revert-cpuidle-simplification.patch | 146 |
2 files changed, 150 insertions, 0 deletions
@@ -12,6 +12,10 @@ PATCHES=( # add upstream patch from 2.6.25 series #ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-2.6.25.1.bz2%1 + # Fix regression in cpuidle code + # See: http://bugzilla.kernel.org/show_bug.cgi?id=10482 + revert-cpuidle-simplification.patch%1 + # Add 2.6.25 prepatch #ftp://ftp.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.25-rc9.bz2%1 #ftp://ftp.kernel.org/pub/linux/kernel/v2.6/snapshots/patch-2.6.25-rc8-git8.bz2%1 diff --git a/patches/revert-cpuidle-simplification.patch b/patches/revert-cpuidle-simplification.patch new file mode 100644 index 0000000..cec5196 --- /dev/null +++ b/patches/revert-cpuidle-simplification.patch @@ -0,0 +1,146 @@ +reverted: +--- b/arch/x86/kernel/process_32.c ++++ a/arch/x86/kernel/process_32.c +@@ -82,6 +82,7 @@ + */ + void (*pm_idle)(void); + EXPORT_SYMBOL(pm_idle); ++static DEFINE_PER_CPU(unsigned int, cpu_idle_state); + + void disable_hlt(void) + { +@@ -189,6 +190,9 @@ + while (!need_resched()) { + void (*idle)(void); + ++ if (__get_cpu_var(cpu_idle_state)) ++ __get_cpu_var(cpu_idle_state) = 0; ++ + check_pgt_cache(); + rmb(); + idle = pm_idle; +@@ -216,19 +220,40 @@ + { + } + +-/* +- * cpu_idle_wait - Used to ensure that all the CPUs discard old value of +- * pm_idle and update to new pm_idle value. Required while changing pm_idle +- * handler on SMP systems. +- * +- * Caller must have changed pm_idle to the new value before the call. Old +- * pm_idle value will not be used by any CPU after the return of this function. +- */ + void cpu_idle_wait(void) + { ++ unsigned int cpu, this_cpu = get_cpu(); ++ cpumask_t map, tmp = current->cpus_allowed; ++ ++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); ++ put_cpu(); ++ ++ cpus_clear(map); ++ for_each_online_cpu(cpu) { ++ per_cpu(cpu_idle_state, cpu) = 1; ++ cpu_set(cpu, map); ++ } ++ ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ wmb(); ++ do { ++ ssleep(1); ++ for_each_online_cpu(cpu) { ++ if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) ++ cpu_clear(cpu, map); ++ } ++ cpus_and(map, map, cpu_online_map); ++ /* ++ * We waited 1 sec, if a CPU still did not call idle ++ * it may be because it is in idle and not waking up ++ * because it has nothing to do. ++ * Give all the remaining CPUS a kick. ++ */ ++ smp_call_function_mask(map, do_nothing, NULL, 0); ++ } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); +- smp_mb(); +- /* kick all the CPUs so that they exit out of pm_idle */ +- smp_call_function(do_nothing, NULL, 0, 1); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +reverted: +--- b/arch/x86/kernel/process_64.c ++++ a/arch/x86/kernel/process_64.c +@@ -63,6 +63,7 @@ + */ + void (*pm_idle)(void); + EXPORT_SYMBOL(pm_idle); ++static DEFINE_PER_CPU(unsigned int, cpu_idle_state); + + static ATOMIC_NOTIFIER_HEAD(idle_notifier); + +@@ -172,6 +173,9 @@ + while (!need_resched()) { + void (*idle)(void); + ++ if (__get_cpu_var(cpu_idle_state)) ++ __get_cpu_var(cpu_idle_state) = 0; ++ + rmb(); + idle = pm_idle; + if (!idle) +@@ -203,19 +207,40 @@ + { + } + +-/* +- * cpu_idle_wait - Used to ensure that all the CPUs discard old value of +- * pm_idle and update to new pm_idle value. Required while changing pm_idle +- * handler on SMP systems. +- * +- * Caller must have changed pm_idle to the new value before the call. Old +- * pm_idle value will not be used by any CPU after the return of this function. +- */ + void cpu_idle_wait(void) + { ++ unsigned int cpu, this_cpu = get_cpu(); ++ cpumask_t map, tmp = current->cpus_allowed; ++ ++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); ++ put_cpu(); ++ ++ cpus_clear(map); ++ for_each_online_cpu(cpu) { ++ per_cpu(cpu_idle_state, cpu) = 1; ++ cpu_set(cpu, map); ++ } ++ ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ wmb(); ++ do { ++ ssleep(1); ++ for_each_online_cpu(cpu) { ++ if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) ++ cpu_clear(cpu, map); ++ } ++ cpus_and(map, map, cpu_online_map); ++ /* ++ * We waited 1 sec, if a CPU still did not call idle ++ * it may be because it is in idle and not waking up ++ * because it has nothing to do. ++ * Give all the remaining CPUS a kick. ++ */ ++ smp_call_function_mask(map, do_nothing, 0, 0); ++ } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); +- smp_mb(); +- /* kick all the CPUs so that they exit out of pm_idle */ +- smp_call_function(do_nothing, NULL, 0, 1); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + |