[ARM] 3346/1: Fix udelay() for HZ values different from 100
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>
This commit is contained in:
parent
0328ad23cf
commit
6d4518d76f
2 changed files with 19 additions and 13 deletions
|
@ -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...
|
||||
*/
|
||||
|
|
|
@ -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) */
|
||||
|
|
Loading…
Reference in a new issue