1 /* 2 * Precise Delay Loops for i386 3 * 4 * Copyright (C) 1993 Linus Torvalds 5 * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> 6 * 7 * The __delay function must _NOT_ be inlined as its execution time 8 * depends wildly on alignment on many x86 processors. The additional 9 * jump magic is needed to get the timing stable on all the CPU's 10 * we have to worry about. 11 */ 12 13 #include <linux/config.h> 14 #include <linux/sched.h> 15 #include <linux/delay.h> 16 #include <asm/processor.h> 17 #include <asm/delay.h> 18 19 #ifdef CONFIG_SMP 20 #include <asm/smp.h> 21 #endif 22 23 int x86_udelay_tsc = 0; /* Delay via TSC */ 24 25 26 /* 27 * Do a udelay using the TSC for any CPU that happens 28 * to have one that we trust. 29 */ 30 __rdtsc_delay(unsigned long loops)31static void __rdtsc_delay(unsigned long loops) 32 { 33 unsigned long bclock, now; 34 35 rdtscl(bclock); 36 do 37 { 38 rep_nop(); 39 rdtscl(now); 40 } while ((now-bclock) < loops); 41 } 42 43 /* 44 * Non TSC based delay loop for 386, 486, MediaGX 45 */ 46 __loop_delay(unsigned long loops)47static void __loop_delay(unsigned long loops) 48 { 49 int d0; 50 __asm__ __volatile__( 51 "\tjmp 1f\n" 52 ".align 16\n" 53 "1:\tjmp 2f\n" 54 ".align 16\n" 55 "2:\tdecl %0\n\tjns 2b" 56 :"=&a" (d0) 57 :"0" (loops)); 58 } 59 extern void __cyclone_delay(unsigned long loops); 60 extern int use_cyclone; __delay(unsigned long loops)61void __delay(unsigned long loops) 62 { 63 if (use_cyclone) 64 __cyclone_delay(loops); 65 else if (x86_udelay_tsc) 66 __rdtsc_delay(loops); 67 else 68 __loop_delay(loops); 69 } 70 __const_udelay(unsigned long xloops)71inline void __const_udelay(unsigned long xloops) 72 { 73 int d0; 74 __asm__("mull %0" 75 :"=d" (xloops), "=&a" (d0) 76 :"1" (xloops),"0" (current_cpu_data.loops_per_jiffy)); 77 __delay(xloops * HZ); 78 } 79 __udelay(unsigned long usecs)80void __udelay(unsigned long usecs) 81 { 82 __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */ 83 } 84 __ndelay(unsigned long nsecs)85void __ndelay(unsigned long nsecs) 86 { 87 __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ 88 } 89