aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/process.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-01-11 16:44:36 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-11 22:04:55 -0500
commit95833c83f3b812c78e48db4eaa19f6c74958470b (patch)
tree8ad17da708141d66cf53c2113b4fe1710af929ec /arch/x86_64/kernel/process.c
parent6b050f8075823b0d9ec4fad38f4f552b74e5c5af (diff)
[PATCH] x86_64: Add idle notifiers
This adds a new notifier chain that is called with IDLE_START when a CPU goes idle and IDLE_END when it goes out of idle. The context can be idle thread or interrupt context. Since we cannot rely on MONITOR/MWAIT existing the idle end check currently has to be done in all interrupt handlers. They were originally inspired by the similar s390 implementation. They have a variety of applications: - They will be needed for CONFIG_NO_IDLE_HZ - They can be used for oprofile to fix up the missing time in idle when performance counters don't tick. - They can be used for better C state management in ACPI - They could be used for microstate accounting. This is just infrastructure so far, no users. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r--arch/x86_64/kernel/process.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index c9df991150b..669cf0ed326 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -36,6 +36,7 @@
36#include <linux/utsname.h> 36#include <linux/utsname.h>
37#include <linux/random.h> 37#include <linux/random.h>
38#include <linux/kprobes.h> 38#include <linux/kprobes.h>
39#include <linux/notifier.h>
39 40
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
@@ -50,6 +51,7 @@
50#include <asm/desc.h> 51#include <asm/desc.h>
51#include <asm/proto.h> 52#include <asm/proto.h>
52#include <asm/ia32.h> 53#include <asm/ia32.h>
54#include <asm/idle.h>
53 55
54asmlinkage extern void ret_from_fork(void); 56asmlinkage extern void ret_from_fork(void);
55 57
@@ -64,6 +66,50 @@ EXPORT_SYMBOL(boot_option_idle_override);
64void (*pm_idle)(void); 66void (*pm_idle)(void);
65static DEFINE_PER_CPU(unsigned int, cpu_idle_state); 67static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
66 68
69static struct notifier_block *idle_notifier;
70static DEFINE_SPINLOCK(idle_notifier_lock);
71
72void idle_notifier_register(struct notifier_block *n)
73{
74 unsigned long flags;
75 spin_lock_irqsave(&idle_notifier_lock, flags);
76 notifier_chain_register(&idle_notifier, n);
77 spin_unlock_irqrestore(&idle_notifier_lock, flags);
78}
79EXPORT_SYMBOL_GPL(idle_notifier_register);
80
81void idle_notifier_unregister(struct notifier_block *n)
82{
83 unsigned long flags;
84 spin_lock_irqsave(&idle_notifier_lock, flags);
85 notifier_chain_unregister(&idle_notifier, n);
86 spin_unlock_irqrestore(&idle_notifier_lock, flags);
87}
88EXPORT_SYMBOL(idle_notifier_unregister);
89
90enum idle_state { CPU_IDLE, CPU_NOT_IDLE };
91static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
92
93void enter_idle(void)
94{
95 __get_cpu_var(idle_state) = CPU_IDLE;
96 notifier_call_chain(&idle_notifier, IDLE_START, NULL);
97}
98
99static void __exit_idle(void)
100{
101 __get_cpu_var(idle_state) = CPU_NOT_IDLE;
102 notifier_call_chain(&idle_notifier, IDLE_END, NULL);
103}
104
105/* Called from interrupts to signify idle end */
106void exit_idle(void)
107{
108 if (current->pid | read_pda(irqcount))
109 return;
110 __exit_idle();
111}
112
67/* 113/*
68 * We use this if we don't have any better 114 * We use this if we don't have any better
69 * idle routine.. 115 * idle routine..
@@ -180,7 +226,9 @@ void cpu_idle (void)
180 idle = default_idle; 226 idle = default_idle;
181 if (cpu_is_offline(smp_processor_id())) 227 if (cpu_is_offline(smp_processor_id()))
182 play_dead(); 228 play_dead();
229 enter_idle();
183 idle(); 230 idle();
231 __exit_idle();
184 } 232 }
185 233
186 preempt_enable_no_resched(); 234 preempt_enable_no_resched();