summaryrefslogtreecommitdiffstats
path: root/arch/x86/lib/delay_64.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-06-14 05:52:39 +0200
committerDavid S. Miller <davem@davemloft.net>2008-06-14 05:52:39 +0200
commit4ae127d1b6c71f9240dd4245f240e6dd8fc98014 (patch)
treeb7aa27b3e0c655f4613fe2146cb57d7f69e421f6 /arch/x86/lib/delay_64.c
parentudp: reorder udp_iter_state to remove padding on 64bit builds (diff)
parentMerge git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6 (diff)
downloadlinux-4ae127d1b6c71f9240dd4245f240e6dd8fc98014.tar.xz
linux-4ae127d1b6c71f9240dd4245f240e6dd8fc98014.zip
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts: drivers/net/smc911x.c
Diffstat (limited to 'arch/x86/lib/delay_64.c')
-rw-r--r--arch/x86/lib/delay_64.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c
index bbc610518516..4c441be92641 100644
--- a/arch/x86/lib/delay_64.c
+++ b/arch/x86/lib/delay_64.c
@@ -31,14 +31,36 @@ int __devinit read_current_timer(unsigned long *timer_value)
void __delay(unsigned long loops)
{
unsigned bclock, now;
+ int cpu;
- preempt_disable(); /* TSC's are pre-cpu */
+ preempt_disable();
+ cpu = smp_processor_id();
rdtscl(bclock);
- do {
- rep_nop();
+ for (;;) {
rdtscl(now);
+ 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);
+ }
}
- while ((now-bclock) < loops);
preempt_enable();
}
EXPORT_SYMBOL(__delay);