lkml.org 
[lkml]   [1999]   [Sep]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
From
Subject[PATCH] udelay() for Alpha
Date
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/

\
 
 \ /
  Last update: 2005-03-22 13:53    [W:0.029 / U:0.028 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site