summaryrefslogtreecommitdiff
path: root/patches
diff options
context:
space:
mode:
authorThomas Bächler <thomas@archlinux.org>2008-04-19 15:11:08 +0200
committerThomas Bächler <thomas@archlinux.org>2008-04-19 15:11:08 +0200
commit06217f8984f279c1ab3f11c43af994d7b489d1a4 (patch)
tree28225249f2d705e945eb07cffc73f95dc48e71b4 /patches
parent5b200e0d379bfa45d8a6b8530168f3d49cc7ed3e (diff)
Fix resume regression caused by changes in 2.6.25 cpuidle code
Diffstat (limited to 'patches')
-rw-r--r--patches/revert-cpuidle-simplification.patch146
1 files changed, 146 insertions, 0 deletions
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);
+