Commit 0656dd6d authored by Russell King's avatar Russell King

[ARM] Fix ARM do_div() implementation

The ARM do_div() implementation was rather lax in that it only
performed a 32-bit divide.  This cset fixes this oversight by
providing a 64-bit by 32-bit division in asm.

This is necessary for posix-timers to function correctly.
parent 2875f70c
...@@ -69,6 +69,7 @@ extern void __udivmoddi4(void); ...@@ -69,6 +69,7 @@ extern void __udivmoddi4(void);
extern void __udivsi3(void); extern void __udivsi3(void);
extern void __umodsi3(void); extern void __umodsi3(void);
extern void abort(void); extern void abort(void);
extern void do_div64(void);
extern void ret_from_exception(void); extern void ret_from_exception(void);
extern void fpundefinstr(void); extern void fpundefinstr(void);
...@@ -234,6 +235,7 @@ EXPORT_SYMBOL_NOVERS(__umoddi3); ...@@ -234,6 +235,7 @@ EXPORT_SYMBOL_NOVERS(__umoddi3);
EXPORT_SYMBOL_NOVERS(__udivmoddi4); EXPORT_SYMBOL_NOVERS(__udivmoddi4);
EXPORT_SYMBOL_NOVERS(__udivsi3); EXPORT_SYMBOL_NOVERS(__udivsi3);
EXPORT_SYMBOL_NOVERS(__umodsi3); EXPORT_SYMBOL_NOVERS(__umodsi3);
EXPORT_SYMBOL_NOVERS(do_div64);
/* bitops */ /* bitops */
EXPORT_SYMBOL(_set_bit_le); EXPORT_SYMBOL(_set_bit_le);
......
...@@ -13,7 +13,7 @@ obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ ...@@ -13,7 +13,7 @@ obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
strnlen_user.o strchr.o strrchr.o testchangebit.o \ strnlen_user.o strchr.o strrchr.o testchangebit.o \
testclearbit.o testsetbit.o uaccess.o getuser.o \ testclearbit.o testsetbit.o uaccess.o getuser.o \
putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
ucmpdi2.o udivdi3.o lib1funcs.o ucmpdi2.o udivdi3.o lib1funcs.o div64.o
obj-m := obj-m :=
obj-n := obj-n :=
......
#include <linux/linkage.h>
ql .req r0 @ quotient low
qh .req r1 @ quotient high
dl .req r3 @ divisor low
dh .req r2 @ divisor high
nl .req r4 @ dividend low
nh .req r5 @ dividend high
ENTRY(do_div64)
stmfd sp!, {r4, r5, lr}
mov nl, r0
movs nh, r1 @ if high bits are zero
movne lr, #33
moveq lr, #1 @ only divide low bits
moveq nh, r0
1: cmp nh, dh
bls 2f
add lr, lr, #1
movs dh, dh, lsl #1 @ left justify divisor
bpl 1b
2: movs nh, r1
moveq dl, dh
moveq dh, #0
movne dl, #0
mov ql, #0
mov qh, #0
3: subs ip, nl, dl @ trial subtraction
sbcs ip, nh, dh
movcs nh, ip @ only update if successful
subcs nl, nl, dl @ (repeat the subtraction)
adcs ql, ql, ql @ C=1 if successful, shift into
adc qh, qh, qh @ quotient
movs dh, dh, lsr #1 @ shift base high part right
mov dl, dl, rrx @ shift base low part right
subs lr, lr, #1
bne 3b
mov r2, nl
ldmfd sp!, {r4, r5, pc}
...@@ -4,9 +4,13 @@ ...@@ -4,9 +4,13 @@
/* We're not 64-bit, but... */ /* We're not 64-bit, but... */
#define do_div(n,base) \ #define do_div(n,base) \
({ \ ({ \
int __res; \ register int __res asm("r2") = base; \
__res = ((unsigned long)n) % (unsigned int)base; \ register unsigned long long __n asm("r0") = n; \
n = ((unsigned long)n) / (unsigned int)base; \ asm("bl do_div64" \
: "=r" (__n), "=r" (__res) \
: "0" (__n), "1" (__res) \
: "r3", "ip", "lr", "cc"); \
n = __n; \
__res; \ __res; \
}) })
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment