summaryrefslogtreecommitdiff
path: root/arch/x86/lib/delay_32.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-06-16 11:24:43 +0200
committerIngo Molnar <mingo@elte.hu>2008-06-16 11:24:43 +0200
commit8bbd54d69e9c66adbf544e21d8dcfb15fb9198f7 (patch)
tree95f30814fc759c2cb523dbea95bc531c7f8f3231 /arch/x86/lib/delay_32.c
parent8c2238eaaf0f774ca0f8d9daad7a616429bbb7f1 (diff)
parent066519068ad2fbe98c7f45552b1f592903a9c8c8 (diff)
Merge branch 'linus' into core/softlockuptip-core-softlockup-2008-06-16_09.24_Mon
Diffstat (limited to 'arch/x86/lib/delay_32.c')
-rw-r--r--arch/x86/lib/delay_32.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/arch/x86/lib/delay_32.c b/arch/x86/lib/delay_32.c
index 4535e6d147ad..d710f2d167bb 100644
--- a/arch/x86/lib/delay_32.c
+++ b/arch/x86/lib/delay_32.c
@@ -44,13 +44,36 @@ static void delay_loop(unsigned long loops)
static void delay_tsc(unsigned long loops)
{
unsigned long bclock, now;
+ int cpu;
- preempt_disable(); /* TSC's are per-cpu */
+ preempt_disable();
+ cpu = smp_processor_id();
rdtscl(bclock);
- do {
- rep_nop();
+ for (;;) {
rdtscl(now);
- } while ((now-bclock) < loops);
+ if ((now - bclock) >= loops)
+ break;
+
+ /* Allow RT tasks to run */
+ preempt_enable();
+ rep_nop();
+ preempt_disable();
+
+ /*
+ * It is possible that we moved to another CPU, and
+ * since TSC's are per-cpu we need to calculate
+ * that. The delay must guarantee that we wait "at
+ * least" the amount of time. Being moved to another
+ * CPU could make the wait longer but we just need to
+ * make sure we waited long enough. Rebalance the
+ * counter for this CPU.
+ */
+ if (unlikely(cpu != smp_processor_id())) {
+ loops -= (now - bclock);
+ cpu = smp_processor_id();
+ rdtscl(bclock);
+ }
+ }
preempt_enable();
}