aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-09-26 04:52:40 -0400
committerAndi Kleen <andi@basil.nowhere.org>2006-09-26 04:52:40 -0400
commita15da49debaf7f09460a886b0ecd08588410715e (patch)
tree685ed022695ff03cec167c6690815e08191a803c
parent1c9c0a6ca35e9325cea811d734d6ab7352be086b (diff)
[PATCH] Fix idle notifiers
Previously exit_idle would be called more often than enter_idle Now instead of using complicated tests just keep track of it using the per CPU variable as a flip flop. I moved the idle state into the PDA to make the access more efficient. Original bug report and an initial patch from Stephane Eranian, but redone by AK. Cc: Stephane Eranian <eranian@hpl.hp.com> Signed-off-by: Andi Kleen <ak@suse.de>
-rw-r--r--arch/x86_64/kernel/process.c15
-rw-r--r--include/asm-x86_64/pda.h3
2 files changed, 11 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 885c318f76ab..458006ae19f3 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -80,25 +80,25 @@ void idle_notifier_unregister(struct notifier_block *n)
80} 80}
81EXPORT_SYMBOL(idle_notifier_unregister); 81EXPORT_SYMBOL(idle_notifier_unregister);
82 82
83enum idle_state { CPU_IDLE, CPU_NOT_IDLE };
84static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
85
86void enter_idle(void) 83void enter_idle(void)
87{ 84{
88 __get_cpu_var(idle_state) = CPU_IDLE; 85 write_pda(isidle, 1);
89 atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); 86 atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
90} 87}
91 88
92static void __exit_idle(void) 89static void __exit_idle(void)
93{ 90{
94 __get_cpu_var(idle_state) = CPU_NOT_IDLE; 91 if (read_pda(isidle) == 0)
92 return;
93 write_pda(isidle, 0);
95 atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); 94 atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
96} 95}
97 96
98/* Called from interrupts to signify idle end */ 97/* Called from interrupts to signify idle end */
99void exit_idle(void) 98void exit_idle(void)
100{ 99{
101 if (current->pid | read_pda(irqcount)) 100 /* idle loop has pid 0 */
101 if (current->pid)
102 return; 102 return;
103 __exit_idle(); 103 __exit_idle();
104} 104}
@@ -220,6 +220,9 @@ void cpu_idle (void)
220 play_dead(); 220 play_dead();
221 enter_idle(); 221 enter_idle();
222 idle(); 222 idle();
223 /* In many cases the interrupt that ended idle
224 has already called exit_idle. But some idle
225 loops can be woken up without interrupt. */
223 __exit_idle(); 226 __exit_idle();
224 } 227 }
225 228
diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h
index 531f48a6c3af..14996d962bac 100644
--- a/include/asm-x86_64/pda.h
+++ b/include/asm-x86_64/pda.h
@@ -25,7 +25,8 @@ struct x8664_pda {
25 int nodenumber; /* number of current node */ 25 int nodenumber; /* number of current node */
26 unsigned int __softirq_pending; 26 unsigned int __softirq_pending;
27 unsigned int __nmi_count; /* number of NMI on this CPUs */ 27 unsigned int __nmi_count; /* number of NMI on this CPUs */
28 int mmu_state; 28 short mmu_state;
29 short isidle;
29 struct mm_struct *active_mm; 30 struct mm_struct *active_mm;
30 unsigned apic_timer_irqs; 31 unsigned apic_timer_irqs;
31} ____cacheline_aligned_in_smp; 32} ____cacheline_aligned_in_smp;