summary refs log tree commit diff
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorAndrew Morton <akpm@linux-foundation.org>2007-11-14 17:00:41 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-14 18:45:44 -0800
commit35d5d08a085c56f153458c3f5d8ce24123617faf (patch)
tree2db6e598e87809bc1ce7838861b2cff18e5fe60d /arch/x86/lib
parent7eea436433b7b18045f272562e256976f593f7c0 (diff)
downloadlinux-35d5d08a085c56f153458c3f5d8ce24123617faf.tar.gz
x86: disable preemption in delay_tsc()
Marin Mitov points out that delay_tsc() can misbehave if it is preempted and
rescheduled on a different CPU which has a skewed TSC.  Fix it by disabling
preemption.

(I assume that the worst-case behaviour here is a stall of 2^32 cycles)

Cc: Andi Kleen <ak@suse.de>
Cc: Marin Mitov <mitov@issp.bas.bg>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/delay_32.c3
-rw-r--r--arch/x86/lib/delay_64.c11
2 files changed, 10 insertions, 4 deletions
diff --git a/arch/x86/lib/delay_32.c b/arch/x86/lib/delay_32.c
index 952e7a89c2ac..aad9d95469dc 100644
--- a/arch/x86/lib/delay_32.c
+++ b/arch/x86/lib/delay_32.c
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/preempt.h>
 #include <linux/delay.h>
 
 #include <asm/processor.h>
@@ -42,11 +43,13 @@ static void delay_tsc(unsigned long loops)
 {
 	unsigned long bclock, now;
 
+	preempt_disable();		/* TSC's are per-cpu */
 	rdtscl(bclock);
 	do {
 		rep_nop();
 		rdtscl(now);
 	} while ((now-bclock) < loops);
+	preempt_enable();
 }
 
 /*
diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c
index 0ebbfb9e7c7f..45cdd3fbd91c 100644
--- a/arch/x86/lib/delay_64.c
+++ b/arch/x86/lib/delay_64.c
@@ -10,7 +10,9 @@
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/preempt.h>
 #include <linux/delay.h>
+
 #include <asm/delay.h>
 #include <asm/msr.h>
 
@@ -27,14 +29,15 @@ int read_current_timer(unsigned long *timer_value)
 void __delay(unsigned long loops)
 {
 	unsigned bclock, now;
-	
+
+	preempt_disable();		/* TSC's are pre-cpu */
 	rdtscl(bclock);
-	do
-	{
+	do {
 		rep_nop(); 
 		rdtscl(now);
 	}
-	while((now-bclock) < loops);
+	while ((now-bclock) < loops);
+	preempt_enable();
 }
 EXPORT_SYMBOL(__delay);