diff options
-rw-r--r-- | include/asm-x86/div64.h | 20 | ||||
-rw-r--r-- | include/linux/math64.h | 72 | ||||
-rw-r--r-- | lib/div64.c | 23 |
3 files changed, 113 insertions, 2 deletions
diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h index 0dbf8bf3ef0a..c7892cfe9ce6 100644 --- a/include/asm-x86/div64.h +++ b/include/asm-x86/div64.h | |||
@@ -51,6 +51,26 @@ static inline long div_ll_X_l_rem(long long divs, long div, long *rem) | |||
51 | 51 | ||
52 | } | 52 | } |
53 | 53 | ||
54 | static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) | ||
55 | { | ||
56 | union { | ||
57 | u64 v64; | ||
58 | u32 v32[2]; | ||
59 | } d = { dividend }; | ||
60 | u32 upper; | ||
61 | |||
62 | upper = d.v32[1]; | ||
63 | d.v32[1] = 0; | ||
64 | if (upper >= divisor) { | ||
65 | d.v32[1] = upper / divisor; | ||
66 | upper %= divisor; | ||
67 | } | ||
68 | asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) : | ||
69 | "rm" (divisor), "0" (d.v32[0]), "1" (upper)); | ||
70 | return d.v64; | ||
71 | } | ||
72 | #define div_u64_rem div_u64_rem | ||
73 | |||
54 | extern uint64_t div64_64(uint64_t dividend, uint64_t divisor); | 74 | extern uint64_t div64_64(uint64_t dividend, uint64_t divisor); |
55 | 75 | ||
56 | #else | 76 | #else |
diff --git a/include/linux/math64.h b/include/linux/math64.h new file mode 100644 index 000000000000..6d1716641008 --- /dev/null +++ b/include/linux/math64.h | |||
@@ -0,0 +1,72 @@ | |||
1 | #ifndef _LINUX_MATH64_H | ||
2 | #define _LINUX_MATH64_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <asm/div64.h> | ||
6 | |||
7 | #if BITS_PER_LONG == 64 | ||
8 | |||
9 | /** | ||
10 | * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder | ||
11 | * | ||
12 | * This is commonly provided by 32bit archs to provide an optimized 64bit | ||
13 | * divide. | ||
14 | */ | ||
15 | static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) | ||
16 | { | ||
17 | *remainder = dividend % divisor; | ||
18 | return dividend / divisor; | ||
19 | } | ||
20 | |||
21 | /** | ||
22 | * div_s64_rem - signed 64bit divide with 32bit divisor with remainder | ||
23 | */ | ||
24 | static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder) | ||
25 | { | ||
26 | *remainder = dividend % divisor; | ||
27 | return dividend / divisor; | ||
28 | } | ||
29 | |||
30 | #elif BITS_PER_LONG == 32 | ||
31 | |||
32 | #ifndef div_u64_rem | ||
33 | static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) | ||
34 | { | ||
35 | *remainder = do_div(dividend, divisor); | ||
36 | return dividend; | ||
37 | } | ||
38 | #endif | ||
39 | |||
40 | #ifndef div_s64_rem | ||
41 | extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder); | ||
42 | #endif | ||
43 | |||
44 | #endif /* BITS_PER_LONG */ | ||
45 | |||
46 | /** | ||
47 | * div_u64 - unsigned 64bit divide with 32bit divisor | ||
48 | * | ||
49 | * This is the most common 64bit divide and should be used if possible, | ||
50 | * as many 32bit archs can optimize this variant better than a full 64bit | ||
51 | * divide. | ||
52 | */ | ||
53 | #ifndef div_u64 | ||
54 | static inline u64 div_u64(u64 dividend, u32 divisor) | ||
55 | { | ||
56 | u32 remainder; | ||
57 | return div_u64_rem(dividend, divisor, &remainder); | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | /** | ||
62 | * div_s64 - signed 64bit divide with 32bit divisor | ||
63 | */ | ||
64 | #ifndef div_s64 | ||
65 | static inline s64 div_s64(s64 dividend, s32 divisor) | ||
66 | { | ||
67 | s32 remainder; | ||
68 | return div_s64_rem(dividend, divisor, &remainder); | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | #endif /* _LINUX_MATH64_H */ | ||
diff --git a/lib/div64.c b/lib/div64.c index b71cf93c529a..689bd76833fa 100644 --- a/lib/div64.c +++ b/lib/div64.c | |||
@@ -16,9 +16,8 @@ | |||
16 | * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. | 16 | * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
21 | #include <asm/div64.h> | 20 | #include <linux/math64.h> |
22 | 21 | ||
23 | /* Not needed on 64bit architectures */ | 22 | /* Not needed on 64bit architectures */ |
24 | #if BITS_PER_LONG == 32 | 23 | #if BITS_PER_LONG == 32 |
@@ -58,6 +57,26 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base) | |||
58 | 57 | ||
59 | EXPORT_SYMBOL(__div64_32); | 58 | EXPORT_SYMBOL(__div64_32); |
60 | 59 | ||
60 | #ifndef div_s64_rem | ||
61 | s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder) | ||
62 | { | ||
63 | u64 quotient; | ||
64 | |||
65 | if (dividend < 0) { | ||
66 | quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder); | ||
67 | *remainder = -*remainder; | ||
68 | if (divisor > 0) | ||
69 | quotient = -quotient; | ||
70 | } else { | ||
71 | quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder); | ||
72 | if (divisor < 0) | ||
73 | quotient = -quotient; | ||
74 | } | ||
75 | return quotient; | ||
76 | } | ||
77 | EXPORT_SYMBOL(div_s64_rem); | ||
78 | #endif | ||
79 | |||
61 | /* 64bit divisor, dividend and result. dynamic precision */ | 80 | /* 64bit divisor, dividend and result. dynamic precision */ |
62 | uint64_t div64_64(uint64_t dividend, uint64_t divisor) | 81 | uint64_t div64_64(uint64_t dividend, uint64_t divisor) |
63 | { | 82 | { |