diff -urNp --exclude CVS --exclude BitKeeper x-ref/arch/i386/kernel/process.c x/arch/i386/kernel/process.c --- x-ref/arch/i386/kernel/process.c 2003-09-23 03:41:08.000000000 +0200 +++ x/arch/i386/kernel/process.c 2003-09-23 03:41:09.000000000 +0200 @@ -145,11 +145,54 @@ void cpu_idle (void) } } +/* + * This is a kind of hybrid between poll and halt idle routines. This uses new + * Monitor/Mwait instructions on P4 processors with PNI. We Monitor + * need_resched and go to optimized wait state through Mwait. + * Whenever someone changes need_resched, we would be woken up from Mwait + * (without an IPI). + */ +static void mwait_idle (void) +{ + int oldval; + + __sti(); + /* Setting need_resched to -1 skips sending IPI during idle resched */ + oldval = xchg(¤t->need_resched, -1); + if (!oldval) { + do { + __monitor((void *)¤t->need_resched, 0, 0); + if (current->need_resched != -1) + break; + __mwait(0, 0); + + } while (current->need_resched == -1); + } +} + +int __init select_idle_routine(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if (cpu_has(c, X86_FEATURE_MWAIT)) { + printk("Monitor/Mwait feature present.\n"); + if (!pm_idle) { + pm_idle = mwait_idle; + } + return 1; + } + pm_idle = default_idle; + return 1; +} + static int __init idle_setup (char *str) { if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); pm_idle = poll_idle; + } else if (!strncmp(str, "halt", 4)) { + printk("using halt in idle threads.\n"); + pm_idle = default_idle; } return 1; diff -urNp --exclude CVS --exclude BitKeeper x-ref/arch/i386/kernel/setup.c x/arch/i386/kernel/setup.c --- x-ref/arch/i386/kernel/setup.c 2003-09-23 03:41:06.000000000 +0200 +++ x/arch/i386/kernel/setup.c 2003-09-23 03:41:09.000000000 +0200 @@ -2293,6 +2293,8 @@ static struct _cache_table cache_table[] { 0x00, 0, 0} }; +int select_idle_routine(void); + static void __init init_intel(struct cpuinfo_x86 *c) { unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ @@ -2316,6 +2318,7 @@ static void __init init_intel(struct cpu } #endif /* CONFIG_X86_F00F_WORKS_OK */ + select_idle_routine(); if (c->cpuid_level > 1) { /* supports eax=2 call */ int i, j, n; @@ -3024,6 +3027,12 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Intel Defined (cpuid 1 and ecx) */ + NULL, NULL, NULL, "monitor-mwait", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; struct cpuinfo_x86 *c = v; int i, n = c - cpu_data; diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/asm-i386/cpufeature.h x/include/asm-i386/cpufeature.h --- x-ref/include/asm-i386/cpufeature.h 2003-09-23 03:41:06.000000000 +0200 +++ x/include/asm-i386/cpufeature.h 2003-09-23 03:42:56.000000000 +0200 @@ -71,6 +71,7 @@ #define X86_FEATURE_P4 (3*32+ 7) /* P4 */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ +#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor-Mwait feature present */ #define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/asm-i386/processor.h x/include/asm-i386/processor.h --- x-ref/include/asm-i386/processor.h 2003-09-23 03:41:07.000000000 +0200 +++ x/include/asm-i386/processor.h 2003-09-23 03:41:09.000000000 +0200 @@ -485,4 +485,21 @@ static inline void rep_nop(void) #define ARCH_HAS_SMP_BALANCE +static __inline__ void __monitor(const void *eax, unsigned long ecx, + unsigned long edx) +{ + /* "monitor %eax,%ecx,%edx;" */ + asm volatile( + ".byte 0x0f,0x01,0xc8;" + : :"a" (eax), "c" (ecx), "d"(edx)); +} + +static __inline__ void __mwait(unsigned long eax, unsigned long ecx) +{ + /* "mwait %eax,%ecx;" */ + asm volatile( + ".byte 0x0f,0x01,0xc9;" + : :"a" (eax), "c" (ecx)); +} + #endif /* __ASM_I386_PROCESSOR_H */