Messages in this thread Patches in this message | | | From | "Olsen, Jim" <> | Subject | [PATCH] udelay() for Alpha | Date | Tue, 7 Sep 1999 20:12:17 -0400 |
| |
Here is a patch for udelay() on alpha. It uses the processor cycle counter to time the delay. It should fix the problem on EV6 processors where udelay(1000) was sometimes delaying for 2 milliseconds. On my DS20 this caused the ncr53c8xx driver to miscalculate the speed of the ncr53c875 chip.
The problem is due to the alignment of the __delay() loop instructions differing between the calibration loop and a particular instance of the macro expansion. I have included a test program below.
I left the __delay() macro intact because various drives still use it directly. However, I believe its use should be deprecated. In particular the video drivers that contain "__delay(200)" need to convert to an appropriate udelay() before faster processors shrink the delay too much.
Thank you for your consideration,
Jim Olsen
--- linux-2.2.12/arch/alpha/kernel/alpha_ksyms.c Wed Aug 25 20:29:45 1999 +++ patch-2.2.12/arch/alpha/kernel/alpha_ksyms.c Tue Sep 7 17:39:22 1999 @@ -29,6 +29,7 @@ #include <asm/machvec.h> #include <asm/pgtable.h> #include <asm/semaphore.h> +#include <asm/delay.h> #define __KERNEL_SYSCALLS__ #include <asm/unistd.h> @@ -97,6 +98,7 @@ EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); +EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); --- linux-2.2.12/arch/alpha/lib/Makefile Sat Jan 16 20:02:51 1999 +++ patch-2.2.12/arch/alpha/lib/Makefile Fri Sep 3 15:51:42 1999 @@ -7,7 +7,7 @@ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ - csum_ipv6_magic.o strcasecmp.o semaphore.o \ + csum_ipv6_magic.o strcasecmp.o semaphore.o delay.o \ srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o lib.a: $(OBJS) --- linux-2.2.12/include/asm-alpha/delay.h Tue Sep 7 15:48:56 1999 +++ patch-2.2.12/include/asm-alpha/delay.h Tue Sep 7 16:34:42 1999 @@ -1,8 +1,6 @@ #ifndef __ALPHA_DELAY_H #define __ALPHA_DELAY_H -#include <asm/smp.h> - /* * Copyright (C) 1993 Linus Torvalds * @@ -12,59 +10,13 @@ extern __inline__ void __delay(unsigned long loops) { - __asm__ __volatile__(".align 3\n" + __asm__ __volatile__(".align 4\n\tnop\n" "1:\tsubq %0,1,%0\n\t" "bge %0,1b": "=r" (loops) : "0" (loops)); } -/* - * division by multiplication: you don't have to worry about - * loss of precision. - * - * Use only for very small delays ( < 1 msec). Should probably use a - * lookup table, really, as the multiplications take much too long with - * short delays. This is a "reasonable" implementation, though (and the - * first constant multiplications gets optimized away if the delay is - * a constant). - * - * Optimize small constants further by exposing the second multiplication - * to the compiler. In addition, mulq is 2 cycles faster than umulh. - */ - -extern __inline__ void -__udelay(unsigned long usecs, unsigned long lps) -{ - /* compute (usecs * 2**64 / 10**6) * loops_per_sec / 2**64 */ - - usecs *= 0x000010c6f7a0b5edUL; /* 2**64 / 1000000 */ - __asm__("umulh %1,%2,%0" :"=r" (usecs) :"r" (usecs),"r" (lps)); - __delay(usecs); -} - -extern __inline__ void -__small_const_udelay(unsigned long usecs, unsigned long lps) -{ - /* compute (usecs * 2**32 / 10**6) * loops_per_sec / 2**32 */ - - usecs *= 0x10c6; /* 2^32 / 10^6 */ - usecs *= lps; - usecs >>= 32; - __delay(usecs); -} - -#ifdef __SMP__ -#define udelay(usecs) \ - (__builtin_constant_p(usecs) && usecs < 0x100000000UL \ - ? __small_const_udelay(usecs, \ - cpu_data[smp_processor_id()].loops_per_sec) \ - : __udelay(usecs, \ - cpu_data[smp_processor_id()].loops_per_sec)) -#else -#define udelay(usecs) \ - (__builtin_constant_p(usecs) && usecs < 0x100000000UL \ - ? __small_const_udelay(usecs, loops_per_sec) \ - : __udelay(usecs, loops_per_sec)) -#endif +extern void __udelay(unsigned long usecs); +#define udelay(usecs) (__udelay(usecs)) #endif /* defined(__ALPHA_DELAY_H) */ --- /dev/null Tue May 5 16:32:27 1998 +++ patch-2.2.12/arch/alpha/lib/delay.c Tue Sep 7 17:24:01 1999 @@ -0,0 +1,40 @@ +/* + * linux/arch/alpha/kernel/delay.c + * + * Copyright (C) 1999 Jim Olsen <jim.olsen@compaq.com <mailto:jim.olsen@compaq.com> > + * + * Delay loop for alpha processors. + * + */ + +#include <linux/delay.h> +#include <asm/hwrpb.h> +#include <asm/uaccess.h> + +static inline __u32 rpcc(void) +{ + __u32 result; + asm volatile ("rpcc %0" : "=r"(result)); + return result; +} + +void __udelay(unsigned long usecs) +{ + unsigned long start, now, count, mhz; + + start = (unsigned long)rpcc(); + mhz = hwrpb->cycle_freq / 1000000; + count = 0; + + do { + now = (unsigned long)rpcc(); + if ( start > now ) { + count += 0x100000000UL; + } + count += (now - start); + while( count > mhz && --usecs ) { + count -= mhz; + } + start = now; + } while( usecs ); +} ============================================================================ = /* * time.c - test udelay() on alpha processors. * * try various compile options: * * gcc -O1 -c -o time.o time.c * gcc -O2 -mcpu=ev5 -Wa,-mev6 -c -o time.o time.c * * insmod time.o; rmmod time * * obviously every udelay(1000) should be ~1000 usec. * * 2.2.12 on DS20: after udelay patch: * u1: 1007 usec u1: 1000 usec * u2: 998 usec u2: 1000 usec * u3: 1997 usec u3: 1000 usec * d1: 1996 usec d1: 1006 usec * d2: 999 usec d2: 997 usec * d3: 2019 usec d3: 998 usec * 2045 jiffies per udelay(1000000) 1023 jiffies per udelay(1000000) */ #define __KERNEL__ #define MODULE #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/time.h> #include <asm/timex.h> #include <asm/hwrpb.h>
extern unsigned long volatile jiffies;
void pcc_time(char *string, unsigned long start, unsigned long end) { if ( start > end ) end += 0x100000000UL; printk ("%s: %d usec\n", string, (int)((end-start)/(hwrpb->cycle_freq/1000000))); }
int init_module(void) { unsigned long start, end; start = get_cycles(); udelay(1000); end = get_cycles(); pcc_time( "u1", start, end);
__asm__ __volatile__(".align 4"); start = get_cycles(); udelay(1000); end = get_cycles(); pcc_time( "u2", start, end);
start = get_cycles(); __asm__ __volatile__(".align 4"); udelay(1000); end = get_cycles(); pcc_time( "u3", start, end);
start = get_cycles(); __delay(loops_per_sec/1000); end = get_cycles(); pcc_time( "d1", start, end);
__asm__ __volatile__(".align 4"); start = get_cycles(); __delay(loops_per_sec/1000); end = get_cycles(); pcc_time( "d2", start, end);
start = get_cycles(); __asm__ __volatile__(".align 4"); __delay(loops_per_sec/1000); end = get_cycles(); pcc_time( "d3", start, end);
start = jiffies; udelay(1000000); printk ("%d jiffies per udelay(1000000)\n", jiffies-start); return 0; } void cleanup_module(void) { printk(".\n"); }
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |