[ARM] 3346/1: Fix udelay() for HZ values different from 100
authorPeter Teichmann <mail@peter-teichmann.de>
Mon, 20 Mar 2006 17:10:09 +0000 (17:10 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 21 Mar 2006 22:06:07 +0000 (22:06 +0000)
Patch from Peter Teichmann

Currently, if the kernels HZ value is greater than 100, delays with the udelay function are too short. This can cause trouble for instance with the zd1201 usb wlan driver.

This patch suggests a solution that keeps the overhead small and maintains (hopefully) sufficient resolution.

Signed-off-by: Peter Teichmann
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/lib/delay.S
include/asm-arm/delay.h

index b3fb475b41202e987667813d5799c0dc8fc282ba..9183b06c0e2f2a77499db21f05205d0bb6907dfe 100644 (file)
@@ -9,28 +9,32 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/param.h>
                .text
 
 .LC0:          .word   loops_per_jiffy
+.LC1:          .word   (2199023*HZ)>>11
 
 /*
- * 0 <= r0 <= 2000
+ * r0  <= 2000
+ * lpj <= 0x01ffffff (max. 3355 bogomips)
+ * HZ  <= 1000
  */
+
 ENTRY(__udelay)
-               mov     r2,     #0x6800
-               orr     r2, r2, #0x00db
+               ldr     r2, .LC1
                mul     r0, r2, r0
-ENTRY(__const_udelay)                          @ 0 <= r0 <= 0x01ffffff
+ENTRY(__const_udelay)                          @ 0 <= r0 <= 0x7fffff06
                ldr     r2, .LC0
-               ldr     r2, [r2]                @ max = 0x0fffffff
-               mov     r0, r0, lsr #11         @ max = 0x00003fff
-               mov     r2, r2, lsr #11         @ max = 0x0003ffff
+               ldr     r2, [r2]                @ max = 0x01ffffff
+               mov     r0, r0, lsr #14         @ max = 0x0001ffff
+               mov     r2, r2, lsr #10         @ max = 0x00007fff
                mul     r0, r2, r0              @ max = 2^32-1
                movs    r0, r0, lsr #6
                RETINSTR(moveq,pc,lr)
 
 /*
- * loops = (r0 * 0x10c6 * 100 * loops_per_jiffy) / 2^32
+ * loops = r0 * HZ * loops_per_jiffy / 1000000
  *
  * Oh, if only we had a cycle counter...
  */
index 1704360e969964e9f59063ab862163fee4f52231..b2deda1815496d83ab3dde5c9eb2c4f5194c7b1e 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef __ASM_ARM_DELAY_H
 #define __ASM_ARM_DELAY_H
 
+#include <asm/param.h> /* HZ */
+
 extern void __delay(int loops);
 
 /*
@@ -13,7 +15,7 @@ extern void __delay(int loops);
  * it, it means that you're calling udelay() with an out of range value.
  *
  * With currently imposed limits, this means that we support a max delay
- * of 2000us and 671 bogomips
+ * of 2000us. Further limits: HZ<=1000 and bogomips<=3355
  */
 extern void __bad_udelay(void);
 
@@ -32,10 +34,10 @@ extern void __const_udelay(unsigned long);
 
 #define MAX_UDELAY_MS 2
 
-#define udelay(n)                                              \
-       (__builtin_constant_p(n) ?                              \
-         ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() :      \
-                       __const_udelay((n) * 0x68dbul)) :       \
+#define udelay(n)                                                      \
+       (__builtin_constant_p(n) ?                                      \
+         ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() :              \
+                       __const_udelay((n) * ((2199023U*HZ)>>11))) :    \
          __udelay(n))
 
 #endif /* defined(_ARM_DELAY_H) */