diff options
-rw-r--r-- | arch/x86/include/asm/idle.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/apm_32.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 32 |
3 files changed, 38 insertions, 5 deletions
diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h index 192e5a02a8c..c288e3ca9f7 100644 --- a/arch/x86/include/asm/idle.h +++ b/arch/x86/include/asm/idle.h @@ -1,13 +1,8 @@ #ifndef _ASM_X86_IDLE_H #define _ASM_X86_IDLE_H -#ifdef CONFIG_X86_64 void enter_idle(void); void exit_idle(void); -#else /* !CONFIG_X86_64 */ -static inline void enter_idle(void) { } -static inline void exit_idle(void) { } -#endif /* CONFIG_X86_64 */ void c1e_remove_cpu(int cpu); diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 0e4f24c2a74..1d1b58cb8d0 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -227,6 +227,7 @@ #include <linux/suspend.h> #include <linux/kthread.h> #include <linux/jiffies.h> +#include <linux/idle.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -947,10 +948,15 @@ recalc: break; } } + enter_idle(); if (original_pm_idle) original_pm_idle(); else default_idle(); + /* In many cases the interrupt that ended idle + has already called exit_idle. But some idle + loops can be woken up without interrupt. */ + __exit_idle(); local_irq_disable(); jiffies_since_last_check = jiffies - last_jiffies; if (jiffies_since_last_check > idle_period) diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 8d128783af4..f580a4332f8 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -38,6 +38,8 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/kdebug.h> +#include <linux/notifier.h> +#include <linux/idle.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -59,6 +61,30 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); +static DEFINE_PER_CPU(unsigned char, is_idle); + +void enter_idle(void) +{ + percpu_write(is_idle, 1); + notify_idle(IDLE_START); +} + +static void __exit_idle(void) +{ + if (x86_test_and_clear_bit_percpu(0, is_idle) == 0) + return; + notify_idle(IDLE_END); +} + +/* Called from interrupts to signify idle end */ +void exit_idle(void) +{ + /* idle loop has pid 0 */ + if (current->pid) + return; + __exit_idle(); +} + /* * Return saved PC of a blocked thread. */ @@ -107,10 +133,16 @@ void cpu_idle(void) play_dead(); local_irq_disable(); + enter_idle(); /* Don't trace irqs off for idle */ stop_critical_timings(); pm_idle(); start_critical_timings(); + + /* In many cases the interrupt that ended idle + has already called exit_idle. But some idle + loops can be woken up without interrupt. */ + __exit_idle(); } tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); |