summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGlauber Costa <gcosta@redhat.com>2008-06-24 09:34:08 -0300
committerIngo Molnar <mingo@elte.hu>2008-07-09 08:51:41 +0200
commit0a4d8a472f645d99f86303db1462b64e371b090d (patch)
treedd6b4b3d4a5cb415b06e8e1625ea811a9012119d /arch
parentff1b15b646177c6cc465ac2dd0be6ae16e965654 (diff)
x86: provide delay loop for x86_64.
This is for consistency with i386. We call use_tsc_delay() at tsc initialization for x86_64, so we'll be always using it. Signed-off-by: Glauber Costa <gcosta@redhat.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/tsc.c1
-rw-r--r--arch/x86/lib/delay_64.c44
2 files changed, 41 insertions, 4 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 3c36f92160c..4a775d00195 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -513,6 +513,7 @@ void __init tsc_init(void)
*/
for_each_possible_cpu(cpu)
set_cyc2ns_scale(cpu_khz, cpu);
+ use_tsc_delay();
if (tsc_disabled > 0)
return;
diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c
index 4c441be9264..d0326d07c84 100644
--- a/arch/x86/lib/delay_64.c
+++ b/arch/x86/lib/delay_64.c
@@ -22,13 +22,28 @@
#include <asm/smp.h>
#endif
-int __devinit read_current_timer(unsigned long *timer_value)
+/* simple loop based delay: */
+static void delay_loop(unsigned long loops)
{
- rdtscll(*timer_value);
- return 0;
+ asm volatile(
+ " test %0,%0 \n"
+ " jz 3f \n"
+ " jmp 1f \n"
+
+ ".align 16 \n"
+ "1: jmp 2f \n"
+
+ ".align 16 \n"
+ "2: dec %0 \n"
+ " jnz 2b \n"
+ "3: dec %0 \n"
+
+ : /* we don't need output */
+ :"a" (loops)
+ );
}
-void __delay(unsigned long loops)
+static void delay_tsc(unsigned long loops)
{
unsigned bclock, now;
int cpu;
@@ -63,6 +78,27 @@ void __delay(unsigned long loops)
}
preempt_enable();
}
+
+static void (*delay_fn)(unsigned long) = delay_loop;
+
+void use_tsc_delay(void)
+{
+ delay_fn = delay_tsc;
+}
+
+int __devinit read_current_timer(unsigned long *timer_value)
+{
+ if (delay_fn == delay_tsc) {
+ rdtscll(*timer_value);
+ return 0;
+ }
+ return -1;
+}
+
+void __delay(unsigned long loops)
+{
+ delay_fn(loops);
+}
EXPORT_SYMBOL(__delay);
inline void __const_udelay(unsigned long xloops)