Commit 35d5d08a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7eea4364
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/preempt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -42,11 +43,13 @@ static void delay_tsc(unsigned long loops) ...@@ -42,11 +43,13 @@ static void delay_tsc(unsigned long loops)
{ {
unsigned long bclock, now; unsigned long bclock, now;
preempt_disable(); /* TSC's are per-cpu */
rdtscl(bclock); rdtscl(bclock);
do { do {
rep_nop(); rep_nop();
rdtscl(now); rdtscl(now);
} while ((now-bclock) < loops); } while ((now-bclock) < loops);
preempt_enable();
} }
/* /*
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/preempt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/msr.h> #include <asm/msr.h>
...@@ -27,14 +29,15 @@ int read_current_timer(unsigned long *timer_value) ...@@ -27,14 +29,15 @@ int read_current_timer(unsigned long *timer_value)
void __delay(unsigned long loops) void __delay(unsigned long loops)
{ {
unsigned bclock, now; unsigned bclock, now;
preempt_disable(); /* TSC's are pre-cpu */
rdtscl(bclock); rdtscl(bclock);
do do {
{
rep_nop(); rep_nop();
rdtscl(now); rdtscl(now);
} }
while((now-bclock) < loops); while ((now-bclock) < loops);
preempt_enable();
} }
EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__delay);
......
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