Commit 5335712e authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ia32 idle using PNI monitor/mwait

From: "Nakajima, Jun" <jun.nakajima@intel.com>

Attached is a patch that enables PNI (Prescott New Instructions)
monitor/mwait in the kernel idle handler.
parent ee9966a5
...@@ -393,7 +393,7 @@ running once the system is up. ...@@ -393,7 +393,7 @@ running once the system is up.
See Documentation/ide.txt. See Documentation/ide.txt.
idle= [HW] idle= [HW]
Format: poll Format: idle=poll or idle=halt
in2000= [HW,SCSI] in2000= [HW,SCSI]
See header of drivers/scsi/in2000.c. See header of drivers/scsi/in2000.c.
......
...@@ -164,7 +164,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) ...@@ -164,7 +164,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
} }
#endif #endif
select_idle_routine(c);
if (c->cpuid_level > 1) { if (c->cpuid_level > 1) {
/* supports eax=2 call */ /* supports eax=2 call */
int i, j, n; int i, j, n;
......
...@@ -151,11 +151,57 @@ void cpu_idle (void) ...@@ -151,11 +151,57 @@ void cpu_idle (void)
} }
} }
/*
* This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
* which can obviate IPI to trigger checking of need_resched.
* We execute MONITOR against need_resched and enter 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)
{
local_irq_enable();
if (!need_resched()) {
set_thread_flag(TIF_POLLING_NRFLAG);
do {
__monitor((void *)&current_thread_info()->flags, 0, 0);
if (need_resched())
break;
__mwait(0, 0);
} while (!need_resched());
clear_thread_flag(TIF_POLLING_NRFLAG);
}
}
void __init select_idle_routine(const struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_MWAIT)) {
printk("monitor/mwait feature present.\n");
/*
* Skip, if setup has overridden idle.
* Also, take care of system with asymmetric CPUs.
* Use, mwait_idle only if all cpus support it.
* If not, we fallback to default_idle()
*/
if (!pm_idle) {
printk("using mwait in idle threads.\n");
pm_idle = mwait_idle;
}
return;
}
pm_idle = default_idle;
return;
}
static int __init idle_setup (char *str) static int __init idle_setup (char *str)
{ {
if (!strncmp(str, "poll", 4)) { if (!strncmp(str, "poll", 4)) {
printk("using polling idle threads.\n"); printk("using polling idle threads.\n");
pm_idle = poll_idle; pm_idle = poll_idle;
} else if (!strncmp(str, "halt", 4)) {
printk("using halt in idle threads.\n");
pm_idle = default_idle;
} }
return 1; return 1;
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ #define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
......
...@@ -272,6 +272,22 @@ extern int MCA_bus; ...@@ -272,6 +272,22 @@ extern int MCA_bus;
#define pc98 0 #define pc98 0
#endif #endif
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));
}
/* from system description table in BIOS. Mostly for MCA use, but /* from system description table in BIOS. Mostly for MCA use, but
others may find it useful. */ others may find it useful. */
...@@ -601,4 +617,6 @@ extern inline void prefetchw(const void *x) ...@@ -601,4 +617,6 @@ extern inline void prefetchw(const void *x)
} }
#define spin_lock_prefetch(x) prefetchw(x) #define spin_lock_prefetch(x) prefetchw(x)
extern void select_idle_routine(const struct cpuinfo_x86 *c);
#endif /* __ASM_I386_PROCESSOR_H */ #endif /* __ASM_I386_PROCESSOR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment