
 - div_long_long_rem(): add a generic version in asm-generic/div64.h;

 - add div_long_long_rem() implemented in terms of do_div() for those
   architectures that define their own assembly optimized version;

 - asm-arm/div64.h:do_div(): add missing parenthesis for macro args

 - kill dupes of div_long_long_rem() defined on-the-fly in
   linux/time.h and kernel/posix-timers.c;

 - make div_long_long_rem() arguments consistent with do_div() and
   its current usage (it's u64/u32 -> u32/u32).

 - add casts where a signed integer was being passed for the remainder;


Applies to 2.6.0-test1. Tested on i386 and m68knommu. Sorry if it
breaks any other architecture (it shouldn't, but...).


diff -Nrup linux-2.6.0-test1.orig/include/asm-generic/div64.h linux-2.6.0-test1/include/asm-generic/div64.h
--- linux-2.6.0-test1.orig/include/asm-generic/div64.h	2003-07-14 05:37:32.000000000 +0200
+++ linux-2.6.0-test1/include/asm-generic/div64.h	2003-07-15 04:56:08.000000000 +0200
@@ -4,6 +4,7 @@
  * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
  * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
  *
+ *
  * The semantics of do_div() are:
  *
  * uint32_t do_div(uint64_t *n, uint32_t base)
@@ -15,6 +16,17 @@
  *
  * NOTE: macro parameter n is evaluated multiple times,
  *       beware of side effects!
+ *
+ *
+ * Semantics for div_long_long_rem():
+ *
+ * uint32_t div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+ * {
+ * 	*rem = n % base;
+ * 	return n / base;
+ * }
+ *
+ * NOTE: this will do an exception if result overflows.
  */
 
 #include <linux/types.h>
@@ -30,6 +42,13 @@
 	__rem;							\
  })
 
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	*rem = n % base;
+	return n / base;
+}
+
 #elif BITS_PER_LONG == 32
 
 extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
@@ -49,6 +68,18 @@ extern uint32_t __div64_32(uint64_t *div
 	__rem;						\
  })
 
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	if (likely((n >> 32) == 0)) {
+		*rem = ((uint32_t)n) % base;
+		return ((uint32_t)n) / base;
+	} else {
+		*rem = __div64_32(&n, base);
+		return n;
+	}
+}
+
 #else /* BITS_PER_LONG == ?? */
 
 # error do_div() does not yet support the C64
@@ -56,3 +87,4 @@ extern uint32_t __div64_32(uint64_t *div
 #endif /* BITS_PER_LONG */
 
 #endif /* _ASM_GENERIC_DIV64_H */
+
diff -Nrup linux-2.6.0-test1.orig/include/asm-arm/div64.h linux-2.6.0-test1/include/asm-arm/div64.h
--- linux-2.6.0-test1.orig/include/asm-arm/div64.h	2003-07-14 05:33:50.000000000 +0200
+++ linux-2.6.0-test1/include/asm-arm/div64.h	2003-07-15 05:23:42.000000000 +0200
@@ -1,18 +1,32 @@
 #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
+#include <linux/types.h>
+
 /* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
-	register int __res asm("r2") = base;			\
-	register unsigned long long __n asm("r0") = n;		\
+	register int __res asm("r2") = (base);			\
+	register unsigned long long __n asm("r0") = (n);	\
 	asm("bl do_div64"					\
 		: "=r" (__n), "=r" (__res)			\
 		: "0" (__n), "1" (__res)			\
 		: "r3", "ip", "lr", "cc");			\
-	n = __n;						\
+	(n) = __n;						\
 	__res;							\
 })
 
+/*
+ * See <asm-generic/div64.h> for specifications.
+ *
+ * FIXME: performance could be improved by writing specific asm
+ */
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	*rem = do_div(n, base);
+	return n;
+}
+
 #endif
 
diff -Nrup linux-2.6.0-test1.orig/include/asm-i386/div64.h linux-2.6.0-test1/include/asm-i386/div64.h
--- linux-2.6.0-test1.orig/include/asm-i386/div64.h	2003-07-14 05:28:55.000000000 +0200
+++ linux-2.6.0-test1/include/asm-i386/div64.h	2003-07-15 06:02:42.000000000 +0200
@@ -1,6 +1,12 @@
 #ifndef __I386_DIV64
 #define __I386_DIV64
 
+#include <linux/types.h>
+
+/* See asm-generic/div64.h for semantics of
+ * do_div() and div_long_long_rem()
+ */
+
 #define do_div(n,base) ({ \
 	unsigned long __upper, __low, __high, __mod; \
 	asm("":"=a" (__low), "=d" (__high):"A" (n)); \
@@ -14,22 +20,14 @@
 	__mod; \
 })
 
-/*
- * (long)X = ((long long)divs) / (long)div
- * (long)rem = ((long long)divs) % (long)div
- *
- * Warning, this will do an exception if X overflows.
- */
-#define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c)
-
-extern inline long
-div_ll_X_l_rem(long long divs, long div, long *rem)
+extern inline uint32_t
+div_long_long_rem(uint64_t divs, uint32_t div, uint32_t *rem)
 {
-	long dum2;
-      __asm__("divl %2":"=a"(dum2), "=d"(*rem)
-      :	"rm"(div), "A"(divs));
-
-	return dum2;
+	uint32_t result;
+	__asm__("divl %2":"=a"(result), "=d"(*rem)
+		: "rm"(div), "A"(divs));
 
+	return result;
 }
+
 #endif
diff -Nrup linux-2.6.0-test1.orig/include/asm-m68k/div64.h linux-2.6.0-test1/include/asm-m68k/div64.h
--- linux-2.6.0-test1.orig/include/asm-m68k/div64.h	2003-07-14 05:37:59.000000000 +0200
+++ linux-2.6.0-test1/include/asm-m68k/div64.h	2003-07-15 05:23:53.000000000 +0200
@@ -1,6 +1,8 @@
 #ifndef _M68K_DIV64_H
 #define _M68K_DIV64_H
 
+#include <linux/types.h>
+
 /* n = n / base; return rem; */
 
 #define do_div(n, base) ({					\
@@ -23,4 +25,16 @@
 	__rem;							\
 })
 
+/*
+ * See <asm-generic/div64.h> for specifications.
+ *
+ * FIXME: performance could be improved by writing specific asm
+ */
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	*rem = do_div(n, base);
+	return n;
+}
+
 #endif /* _M68K_DIV64_H */
diff -Nrup linux-2.6.0-test1.orig/include/asm-mips/div64.h linux-2.6.0-test1/include/asm-mips/div64.h
--- linux-2.6.0-test1.orig/include/asm-mips/div64.h	2003-07-14 05:36:33.000000000 +0200
+++ linux-2.6.0-test1/include/asm-mips/div64.h	2003-07-15 05:24:16.000000000 +0200
@@ -8,6 +8,8 @@
 #ifndef _ASM_DIV64_H
 #define _ASM_DIV64_H
 
+#include <linux/types.h>
+
 /*
  * No traps on overflows for any of these...
  */
@@ -73,4 +75,16 @@
 	(n) = __quot; \
 	__mod; })
 
+/*
+ * See <asm-generic/div64.h> for specifications.
+ *
+ * FIXME: performance could be improved by writing specific asm
+ */
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	*rem = do_div(n, base);
+	return n;
+}
+
 #endif /* _ASM_DIV64_H */
diff -Nrup linux-2.6.0-test1.orig/include/asm-s390/div64.h linux-2.6.0-test1/include/asm-s390/div64.h
--- linux-2.6.0-test1.orig/include/asm-s390/div64.h	2003-07-14 05:35:52.000000000 +0200
+++ linux-2.6.0-test1/include/asm-s390/div64.h	2003-07-15 05:24:28.000000000 +0200
@@ -3,6 +3,8 @@
 
 #ifndef __s390x__
 
+#include <linux/types.h>
+
 /* for do_div "base" needs to be smaller than 2^31-1 */
 #define do_div(n, base) ({                                      \
 	unsigned long long __n = (n);				\
@@ -42,6 +44,18 @@
         __r;                                                    \
 })
 
+/*
+ * See <asm-generic/div64.h> for specifications.
+ *
+ * FIXME: performance could be improved by writing specific asm
+ */
+extern inline uint32_t
+div_long_long_rem(uint64_t n, uint32_t base, uint32_t *rem)
+{
+	*rem = do_div(n, base);
+	return n;
+}
+
 #else /* __s390x__ */
 #include <asm-generic/div64.h>
 #endif /* __s390x__ */
diff -Nrup linux-2.6.0-test1.orig/include/linux/time.h linux-2.6.0-test1/include/linux/time.h
--- linux-2.6.0-test1.orig/include/linux/time.h	2003-07-14 05:35:16.000000000 +0200
+++ linux-2.6.0-test1/include/linux/time.h	2003-07-15 05:20:26.000000000 +0200
@@ -28,14 +28,6 @@ struct timezone {
 #include <linux/seqlock.h>
 #include <linux/timex.h>
 #include <asm/div64.h>
-#ifndef div_long_long_rem
-
-#define div_long_long_rem(dividend,divisor,remainder) ({ \
-		       u64 result = dividend;		\
-		       *remainder = do_div(result,divisor); \
-		       result; })
-
-#endif
 
 /*
  * Have the 32 bit jiffies value wrap 5 minutes after boot
@@ -122,7 +114,7 @@ jiffies_to_timespec(unsigned long jiffie
 	 * one divide.
 	 */
 	u64 nsec = (u64)jiffies * TICK_NSEC; 
-	value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec);
+	value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, (uint32_t *)&value->tv_nsec);
 }
 
 /* Same for "timeval" */
@@ -150,7 +142,7 @@ jiffies_to_timeval(unsigned long jiffies
 	 * one divide.
 	 */
 	u64 nsec = (u64)jiffies * TICK_NSEC; 
-	value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
+	value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, (uint32_t *)&value->tv_usec);
 	value->tv_usec /= NSEC_PER_USEC;
 }
 
diff -Nrup linux-2.6.0-test1.orig/kernel/posix-timers.c linux-2.6.0-test1/kernel/posix-timers.c
--- linux-2.6.0-test1.orig/kernel/posix-timers.c	2003-07-14 05:34:32.000000000 +0200
+++ linux-2.6.0-test1/kernel/posix-timers.c	2003-07-15 05:21:24.000000000 +0200
@@ -23,16 +23,8 @@
 #include <linux/idr.h>
 #include <linux/posix-timers.h>
 #include <linux/wait.h>
-
-#ifndef div_long_long_rem
 #include <asm/div64.h>
 
-#define div_long_long_rem(dividend,divisor,remainder) ({ \
-		       u64 result = dividend;		\
-		       *remainder = do_div(result,divisor); \
-		       result; })
-
-#endif
 #define CLOCK_REALTIME_RES TICK_NSEC  // In nano seconds.
 
 static inline u64  mpy_l_X_l_ll(unsigned long mpy1,unsigned long mpy2)
@@ -1226,7 +1218,7 @@ do_clock_nanosleep(clockid_t which_clock
 		left *= TICK_NSEC;
 		tsave->tv_sec = div_long_long_rem(left, 
 						  NSEC_PER_SEC, 
-						  &tsave->tv_nsec);
+						  (uint32_t *)&tsave->tv_nsec);
 		restart_block->fn = clock_nanosleep_restart;
 		restart_block->arg0 = which_clock;
 		restart_block->arg1 = (unsigned long)tsave;
