Skip to content

Commit

Permalink
[ARM] 3346/1: Fix udelay() for HZ values different from 100
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Peter Teichmann authored and Russell King committed Mar 21, 2006
1 parent 0328ad2 commit 6d4518d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 13 deletions.
20 changes: 12 additions & 8 deletions arch/arm/lib/delay.S
Original file line number Diff line number Diff line change
Expand Up @@ -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...
*/
Expand Down
12 changes: 7 additions & 5 deletions include/asm-arm/delay.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
#ifndef __ASM_ARM_DELAY_H
#define __ASM_ARM_DELAY_H

#include <asm/param.h> /* HZ */

extern void __delay(int loops);

/*
* This function intentionally does not exist; if you see references to
* 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);

Expand All @@ -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) */
Expand Down

0 comments on commit 6d4518d

Please sign in to comment.