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-01 21:41:47.000000000 +0200 +++ x/arch/i386/kernel/process.c 2003-09-01 21:41:48.000000000 +0200 @@ -144,11 +144,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-01 21:41:45.000000000 +0200 +++ x/arch/i386/kernel/setup.c 2003-09-01 21:41:48.000000000 +0200 @@ -2278,6 +2278,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 */ @@ -2301,6 +2303,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; @@ -2764,7 +2767,8 @@ void __init identify_cpu(struct cpuinfo_ /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { - cpuid(0x00000001, &tfms, &junk, &junk, + cpuid(0x00000001, &tfms, &junk, + &c->x86_capability[4], &c->x86_capability[0]); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; @@ -2990,6 +2994,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-01 21:41:45.000000000 +0200 +++ x/include/asm-i386/cpufeature.h 2003-09-01 21:43:34.000000000 +0200 @@ -10,7 +10,7 @@ /* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */ #define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT) -#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */ +#define NCAPINTS 5 /* Currently we have 5 32-bit words worth of info */ /* Intel-defined CPU features, CPUID level 0x00000001, word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ @@ -65,6 +65,7 @@ #define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ /* 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 */ #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) 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-01 21:41:46.000000000 +0200 +++ x/include/asm-i386/processor.h 2003-09-01 21:41:48.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 */