Skip to contentSkip to conversation

64-bit divide tweaks

PATCH In review Momchil Velikov 6 participants 7 messages Jan 25, 2002 – Feb 7, 2002

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 64-bit divide tweaks

Hi there,

printk, etc. are broken wrt printing 64-bit numbers (%ll, %L).

This patch fixes do_div, which did (on some archs) 32-bit divide.

Regards,
-velco

===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====

drivers/net/sk98lin/skproc.c +0 -11
@@ -339,17 +339,6 @@
  return (Rest);
 }
 
-
-#if 0
-#define do_div(n,base) ({ \
-long long __res; \
-__res = ((unsigned long long) n) % (unsigned) base; \
-n = ((unsigned long long) n) / (unsigned) base; \
-__res; })
-
-#endif
-
-
 /*****************************************************************************
  *
  * SkNumber - Print results

===== include/asm-arm/div64.h 1.1 vs edited =====

include/asm-arm/div64.h +2 -3
@@ -1,12 +1,11 @@
 #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;		\
 	__res;							\
 })
 

===== include/asm-cris/div64.h 1.1 vs edited =====

include/asm-cris/div64.h +2 -3
@@ -3,12 +3,11 @@
 
 /* copy from asm-arm */
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;	\
 	__res;							\
 })
 

===== include/asm-m68k/div64.h 1.1 vs edited =====

include/asm-m68k/div64.h +2 -2
@@ -26,8 +26,8 @@
 #else
 #define do_div(n,base) ({					\
 	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
 	__res;							\
 })
 #endif

===== include/asm-ppc/div64.h 1.1 vs edited =====

include/asm-ppc/div64.h +5 -6
@@ -4,10 +4,9 @@
 #ifndef __PPC_DIV64
 #define __PPC_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif

===== include/asm-sh/div64.h 1.1 vs edited =====

include/asm-sh/div64.h +5 -6
@@ -1,10 +1,9 @@
 #ifndef __ASM_SH_DIV64
 #define __ASM_SH_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif /* __ASM_SH_DIV64 */

===== include/asm-sparc/div64.h 1.1 vs edited =====

include/asm-sparc/div64.h +2 -3
@@ -1,11 +1,10 @@
 #ifndef __SPARC_DIV64
 #define __SPARC_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base) ({ \
 	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
+	__res = ((unsigned long long) n) % (unsigned) base; \
+	n = ((unsigned long long) n) / (unsigned) base; \
 	__res; })
 
 #endif /* __SPARC_DIV64 */
#1 lore raw

If you are gonna hack them all anyway, why not turn them into static inlines...

Signature · 3 lines
Jeff Garzik      | "I went through my candy like hot oatmeal
Building 1024    |  through an internally-buttered weasel."
MandrakeSoft     |             - goats.com
#2 lore raw
Quoted 2 lines · Jeff Garzik

If you are gonna hack them all anyway, why not turn them into static inlines...

Probably a good idea, but then all user need some change like
do_div(n,base) --> do_div(&n,base)
as do_div currently is not valid C semantics.

Tim

#3 lore raw
In reply to Momchil Velikov
Quoted 5 lines · Momchil Velikov

Hi there,

printk, etc. are broken wrt printing 64-bit numbers (%ll, %L).

This patch fixes do_div, which did (on some archs) 32-bit divide.

Have you tried compiling any of these arches?

Anything that doesn't include libgcc will die a link missing symbols for __udivdi3 and __umoddi3.

Quoted 136 lines

Regards,
-velco

===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====

drivers/net/sk98lin/skproc.c +0 -11
@@ -339,17 +339,6 @@
  return (Rest);
 }
 
-
-#if 0
-#define do_div(n,base) ({ \
-long long __res; \
-__res = ((unsigned long long) n) % (unsigned) base; \
-n = ((unsigned long long) n) / (unsigned) base; \
-__res; })
-
-#endif
-
-
 /*****************************************************************************
  *
  * SkNumber - Print results

===== include/asm-arm/div64.h 1.1 vs edited =====

include/asm-arm/div64.h +2 -3
@@ -1,12 +1,11 @@
 #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;		\
 	__res;							\
 })
 

===== include/asm-cris/div64.h 1.1 vs edited =====

include/asm-cris/div64.h +2 -3
@@ -3,12 +3,11 @@
 
 /* copy from asm-arm */
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;	\
 	__res;							\
 })
 

===== include/asm-m68k/div64.h 1.1 vs edited =====

include/asm-m68k/div64.h +2 -2
@@ -26,8 +26,8 @@
 #else
 #define do_div(n,base) ({					\
 	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
 	__res;							\
 })
 #endif

===== include/asm-ppc/div64.h 1.1 vs edited =====

include/asm-ppc/div64.h +5 -6
@@ -4,10 +4,9 @@
 #ifndef __PPC_DIV64
 #define __PPC_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif

===== include/asm-sh/div64.h 1.1 vs edited =====

include/asm-sh/div64.h +5 -6
@@ -1,10 +1,9 @@
 #ifndef __ASM_SH_DIV64
 #define __ASM_SH_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif /* __ASM_SH_DIV64 */

===== include/asm-sparc/div64.h 1.1 vs edited =====

include/asm-sparc/div64.h +2 -4
@@ -1,11 +1,10 @@
 #ifndef __SPARC_DIV64
 #define __SPARC_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base) ({ \
 	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
+	__res = ((unsigned long long) n) % (unsigned) base; \
+	n = ((unsigned long long) n) / (unsigned) base; \
 	__res; })
 
 #endif /* __SPARC_DIV64 */
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
Troy Benjegerdes | master of mispeeling | 'da hozer' |  [email protected]
-----"If this message isn't misspelled, I didn't write it" -- Me -----
"Why do musicians compose symphonies and poets write poems? They do it
because life wouldn't have any meaning for them if they didn't. That's 
why I draw cartoons. It's my life." -- Charles Schulz
#4 lore raw
In reply to Momchil Velikov
Quoted 3 lines · Momchil Velikov

Hi there,
printk, etc. are broken wrt printing 64-bit numbers (%ll, %L). This patch fixes do_div, which did (on some archs) 32-bit divide.

Wrong.

Correct one is to supply each arch with their native way to handle the division. Remember, the base (divisor) is SMALLISH (2 to 16).

Where you are unable to do it, the C code that is still present in
include/asm-parisc/div64.h alternate code branch will do it.

This code is needed because the Linux kernel DOES NOT WANT TO use gcc builtin functions normally available via libgcc. This is primarily to detect when 32-bit machine does arbitrary (and expensive) divisions on 64-bit values. E.g. stupid code slipped into fast-paths.

Quoted 2 lines

Regards,
-velco

/Matti Aarnio (who originally created this %Ld printing code,
and which others have mutated since then..)

Quoted 131 lines

===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====

drivers/net/sk98lin/skproc.c +0 -11
@@ -339,17 +339,6 @@
  return (Rest);
 }
 
-
-#if 0
-#define do_div(n,base) ({ \
-long long __res; \
-__res = ((unsigned long long) n) % (unsigned) base; \
-n = ((unsigned long long) n) / (unsigned) base; \
-__res; })
-
-#endif
-
-
 /*****************************************************************************
  *
  * SkNumber - Print results

===== include/asm-arm/div64.h 1.1 vs edited =====

include/asm-arm/div64.h +2 -3
@@ -1,12 +1,11 @@
 #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;		\
 	__res;							\
 })
 

===== include/asm-cris/div64.h 1.1 vs edited =====

include/asm-cris/div64.h +2 -3
@@ -3,12 +3,11 @@
 
 /* copy from asm-arm */
 
-/* We're not 64-bit, but... */
 #define do_div(n,base)						\
 ({								\
 	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
+	__res = ((unsigned long long)n) % (unsigned int)base;	\
+	n = ((unsigned long long)n) / (unsigned int)base;	\
 	__res;							\
 })
 

===== include/asm-m68k/div64.h 1.1 vs edited =====

include/asm-m68k/div64.h +2 -2
@@ -26,8 +26,8 @@
 #else
 #define do_div(n,base) ({					\
 	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
 	__res;							\
 })
 #endif

===== include/asm-ppc/div64.h 1.1 vs edited =====

include/asm-ppc/div64.h +5 -6
@@ -4,10 +4,9 @@
 #ifndef __PPC_DIV64
 #define __PPC_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif

===== include/asm-sh/div64.h 1.1 vs edited =====

include/asm-sh/div64.h +5 -6
@@ -1,10 +1,9 @@
 #ifndef __ASM_SH_DIV64
 #define __ASM_SH_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({					\
+	int __res;						\
+	__res = ((unsigned long long) n) % (unsigned) base;	\
+	n = ((unsigned long long) n) / (unsigned) base;		\
+	__res; })
 #endif /* __ASM_SH_DIV64 */

===== include/asm-sparc/div64.h 1.1 vs edited =====

include/asm-sparc/div64.h +2 -4
@@ -1,11 +1,10 @@
 #ifndef __SPARC_DIV64
 #define __SPARC_DIV64
 
-/* We're not 64-bit, but... */
 #define do_div(n,base) ({ \
 	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
+	__res = ((unsigned long long) n) % (unsigned) base; \
+	n = ((unsigned long long) n) / (unsigned) base; \
 	__res; })
 
 #endif /* __SPARC_DIV64 */
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#5 lore raw

64-bit divide cleanup (tested on ppc)

In reply to Momchil Velikov

Attached is a patch to get rid of asm/div64.h on arches that don't have optimized asm routines.

I didn't include removeing the various arch/div64.h file yet, since I want some comments on this.

Index: drivers/acpi/include/platform/aclinux.h
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/drivers/acpi/include/platform/aclinux.h,v retrieving revision 1.1

acpi/include/platform/aclinux.h +1 -1
diff -u -r1.1 aclinux.h
@@ -36,9 +36,9 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
+
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/div64.h>
 
 #define strtoul simple_strtoul
 

Index: drivers/net/sk98lin/skproc.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/drivers/net/sk98lin/skproc.c,v retrieving revision 1.1

net/sk98lin/skproc.c +1 -55

68 lines not on this page · raw message

Index: drivers/video/matrox/matroxfb_maven.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/drivers/video/matrox/matroxfb_maven.c,v retrieving revision 1.1

video/matrox/matroxfb_maven.c +4 -4
diff -u -r1.1 matroxfb_maven.c
@@ -15,7 +15,8 @@
 #include "matroxfb_DAC1064.h"
 #include <linux/i2c.h>
 #include <linux/matroxfb.h>
-#include <asm/div64.h>
+#define USE_SLOW_64BIT_DIVIDES
+#include <linux/div64.h>
 #include <asm/uaccess.h>
 
 #define MAVEN_I2CID	(0x1B)
@@ -698,9 +699,8 @@
 			int vdec;
 			int vlen;
 
-#define MATROX_USE64BIT_DIVIDE
 			if (mt->VTotal) {
-#ifdef MATROX_USE64BIT_DIVIDE
+#ifdef USE_SLOW_64BIT_DIVIDES
 				u64 f1;
 				u32 a;
 				u32 b;
@@ -709,7 +709,7 @@
 				b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
 
 				f1 = ((u64)a) << 15;	/* *32768 */
-				do_div(f1, b);
+				do_div(&f1, b);
 				vdec = f1;
 #else
 				vdec = m->vlines * 32768 / mt->VTotal;

Index: fs/affs/file.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/affs/file.c,v retrieving revision 1.1

affs/file.c +0 -1
diff -u -r1.1 file.c
@@ -12,7 +12,6 @@
  *  affs regular file handling primitives
  */
 
-#include <asm/div64.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/sched.h>

Index: fs/affs/inode.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/affs/inode.c,v retrieving revision 1.1

affs/inode.c +0 -1
diff -u -r1.1 inode.c
@@ -10,7 +10,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#include <asm/div64.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/slab.h>

Index: fs/ntfs/util.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/ntfs/util.c,v retrieving revision 1.1

ntfs/util.c +3 -2
diff -u -r1.1 util.c
@@ -13,7 +13,8 @@
 #include "util.h"
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <asm/div64.h>		/* For do_div(). */
+#define USE_SLOW_64BIT_DIVIDES
+#include <linux/div64.h>		/* For do_div(). */
 #include "support.h"
 
 /*
@@ -233,7 +234,7 @@
 {
 	/* Subtract the NTFS time offset, then convert to 1s intervals. */
 	ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
-	do_div(t, 10000000);
+	do_div(&t, 10000000);
 	return (ntfs_time_t)t;
 }
 

Index: fs/smbfs/proc.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/smbfs/proc.c,v retrieving revision 1.1

smbfs/proc.c +4 -2
diff -u -r1.1 proc.c
@@ -18,12 +18,14 @@
 #include <linux/dirent.h>
 #include <linux/nls.h>
 
+#define USE_SLOW_64BIT_DIVIDES
+#include <linux/div64.h>
+
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
 #include <linux/smb_mount.h>
 
 #include <asm/string.h>
-#include <asm/div64.h>
 
 #include "smb_debug.h"
 #include "proto.h"
@@ -375,7 +377,7 @@
 	/* FIXME: what about the timezone difference? */
 	/* Subtract the NTFS time offset, then convert to 1s intervals. */
 	u64 t = ntutc - NTFS_TIME_OFFSET;
-	do_div(t, 10000000);
+	do_div(&t, 10000000);
 	return (time_t)t;
 }
 

Index: lib/vsprintf.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/lib/vsprintf.c,v retrieving revision 1.1

vsprintf.c +23 -14
diff -u -r1.1 vsprintf.c
@@ -19,9 +19,9 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/kernel.h>
+/* #define USE_SLOW_64BIT_DIVIDE */
+#include <linux/div64.h>
 
-#include <asm/div64.h>
-
 /**
  * simple_strtoul - convert a string to an unsigned long
  * @cp: The start of the string
@@ -165,7 +165,7 @@
 	if (num == 0)
 		tmp[i++]='0';
 	else while (num != 0)
-		tmp[i++] = digits[do_div(num,base)];
+		tmp[i++] = digits[do_div(&num,base)];
 	if (i > precision)
 		precision = i;
 	size -= precision;
@@ -426,22 +426,31 @@
 				}
 				continue;
 		}
-		if (qualifier == 'L')
+
+		switch (qualifier) {
+		case 'L':
 			num = va_arg(args, long long);
-		else if (qualifier == 'l') {
-			num = va_arg(args, unsigned long);
+			break;
+		case 'l':
 			if (flags & SIGN)
-				num = (signed long) num;
-		} else if (qualifier == 'Z') {
+				num = (signed long long) va_arg(args, long);
+			else
+				num = va_arg(args, unsigned long);
+			break;
+		case 'Z':
 			num = va_arg(args, size_t);
-		} else if (qualifier == 'h') {
-			num = (unsigned short) va_arg(args, int);
+			break;
+		case 'h':
 			if (flags & SIGN)
-				num = (signed short) num;
-		} else {
-			num = va_arg(args, unsigned int);
+				num = (signed long long) va_arg(args, int);
+			else
+				num = va_arg(args, unsigned int);
+			break;
+		default:
 			if (flags & SIGN)
-				num = (signed int) num;
+				num = (signed long long) va_arg(args, int);
+			else
+				num = va_arg(args, unsigned int);
 		}
 		str = number(str, end, num, base,
 				field_width, precision, flags);

Index: include/linux/div64.h
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/include/linux/div64.h

linux/div64.h new file +85 -0

85 lines not on this page · raw message

#6 lore raw

Re: 64-bit divide cleanup (tested on ppc)

In reply to Momchil Velikov

Hi Troy,

sorry for the delay, I was sick :-(

Quoted 4 lines · Troy Benjegerdes

Attached is a patch to get rid of asm/div64.h on arches that don't have optimized asm routines.

I didn't include removeing the various arch/div64.h file yet, since I want some comments on this.

[snipped]

Quoted 50 lines

===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/ntfs/util.c,v retrieving revision 1.1
diff -u -r1.1 util.c

ntfs/util.c +3 -2
@@ -13,7 +13,8 @@
 #include "util.h"
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <asm/div64.h>		/* For do_div(). */
+#define USE_SLOW_64BIT_DIVIDES
+#include <linux/div64.h>		/* For do_div(). */
 #include "support.h"
 
 /*
@@ -233,7 +234,7 @@
 {
 	/* Subtract the NTFS time offset, then convert to 1s intervals. */
 	ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
-	do_div(t, 10000000);
+	do_div(&t, 10000000);
 	return (ntfs_time_t)t;
 }
 

Index: fs/smbfs/proc.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/fs/smbfs/proc.c,v retrieving revision 1.1
diff -u -r1.1 proc.c

smbfs/proc.c +3 -1
@@ -18,12 +18,14 @@
 #include <linux/dirent.h>
 #include <linux/nls.h>
 
+#define USE_SLOW_64BIT_DIVIDES
+#include <linux/div64.h>
+
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
 #include <linux/smb_mount.h>
 
 #include <asm/string.h>
-#include <asm/div64.h>
 
 #include "smb_debug.h"
 #include "proto.h"

smbfs/proc.c line 382

Quoted 7 lines
smbfs/proc.c +1 -1
@@ -375,7 +377,7 @@
 	/* FIXME: what about the timezone difference? */
 	/* Subtract the NTFS time offset, then convert to 1s intervals. */
 	u64 t = ntutc - NTFS_TIME_OFFSET;
-	do_div(t, 10000000);
+	do_div(&t, 10000000);
 	return (time_t)t;
 }

At least for these 2, your patch is wrong. 10000000 is not especially small and the algorithm you propose does not work for these. It is limited to about 65536 actually.

Quoted 21 lines

Index: lib/vsprintf.c
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/lib/vsprintf.c,v retrieving revision 1.1
diff -u -r1.1 vsprintf.c

vsprintf.c +2 -2
@@ -19,9 +19,9 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/kernel.h>
+/* #define USE_SLOW_64BIT_DIVIDE */
+#include <linux/div64.h>
 
-#include <asm/div64.h>
-
 /**
  * simple_strtoul - convert a string to an unsigned long
  * @cp: The start of the string

vsprintf.c line 168

Quoted 5 lines
vsprintf.c +1 -1
@@ -165,7 +165,7 @@
 	if (num == 0)
 		tmp[i++]='0';
 	else while (num != 0)
-		tmp[i++] = digits[do_div(num,base)];
+		tmp[i++] = digits[do_div(&num,base)];

Forcing to use slow do_div version even when base is 8 or 16 is not nice. Heck I believe that seperating it into several cases and having a different 2 or 3 distinct loops (one for base 10, the other or 2 others for shifts by 3 or 4) could actually result in smaller code. On PPC and Alpha at lesat the compiler knows how to do a divide by 10 with a multiply high or however it's called instruction.

Oh, and what abour removing the if and doing a do {...} while(num!=0) instead ?

Quoted 53 lines
vsprintf.c +20 -11
 	if (i > precision)
 		precision = i;
 	size -= precision;
@@ -426,22 +426,31 @@
 				}
 				continue;
 		}
-		if (qualifier == 'L')
+
+		switch (qualifier) {
+		case 'L':
 			num = va_arg(args, long long);
-		else if (qualifier == 'l') {
-			num = va_arg(args, unsigned long);
+			break;
+		case 'l':
 			if (flags & SIGN)
-				num = (signed long) num;
-		} else if (qualifier == 'Z') {
+				num = (signed long long) va_arg(args, long);
+			else
+				num = va_arg(args, unsigned long);
+			break;
+		case 'Z':
 			num = va_arg(args, size_t);
-		} else if (qualifier == 'h') {
-			num = (unsigned short) va_arg(args, int);
+			break;
+		case 'h':
 			if (flags & SIGN)
-				num = (signed short) num;
-		} else {
-			num = va_arg(args, unsigned int);
+				num = (signed long long) va_arg(args, int);
+			else
+				num = va_arg(args, unsigned int);
+			break;
+		default:
 			if (flags & SIGN)
-				num = (signed int) num;
+				num = (signed long long) va_arg(args, int);
+			else
+				num = va_arg(args, unsigned int);
 		}
 		str = number(str, end, num, base,
 				field_width, precision, flags);

Index: include/linux/div64.h
===================================================================
RCS file: /cvsdev/hhl-2.4.17/linux/include/linux/div64.h diff -N div64.h

linux/div64.h line 4

Quoted 4 lines
linux/div64.h new file +4 -0
@@ -0,0 +1,85 @@
+/*
+ * include/linux/div64.h
+ *
+ * Primarily used by vsprintf to divide a 64 bit int N by a small integer base
                                                               ^^^^^

Read the comments, here goes you 10000000 factor. The modulo once shifted left by 16 bits can easily overflow.... Perhaps you should patch it s/small/_small_/ to better see it.

Quoted 44 lines
linux/div64.h new file +44 -0
+ * We really do NOT want to encourage people to do slow 64 bit divides in
+ * the kernel, so the 'default' version of this function panics if you
+ * try and divide a 64 bit number by anything other than 8 or 16.
+ *
+ * If you really *really* need this, and are prepared to be flamed by 
+ * lkml, #define USE_SLOW_64BIT_DIVIDES before including this file.
+ */
+#ifndef __DIV64
+#define __DIV64
+
+#include <linux/config.h>
+
+/* configurable  */
+#undef __USE_ASM
+
+
+#ifdef __USE_ASM
+/* yeah, this is a mess, and leaves out m68k.... */
+# if defined(CONFIG_X86) || define(CONFIG_ARCH_S390) || defined(CONFIG_MIPS)
+#  define __USE_ASM__
+# endif
+#endif
+
+#ifdef __USE_ASM__
+#include <asm/div64.h>
+#else /* __USE_ASM__ */
+static inline int do_div(unsigned long long * n, unsigned long base)
+{
+	int res = 0;
+	unsigned long long t = *n;
+	if ( t == (unsigned long)t ){ /* this should handle 64 bit platforms */
+		res = ((unsigned long) t) % base;
+		t = ((unsigned long) t) / base;
+	} else {
+#ifndef USE_SLOW_64BIT_DIVIDES 
+		switch (base) {
+			case 8:
+				res = ((unsigned long) t & 0x7);
+				t = t >> 3;
+				break;
+			case 16:
+				res = ((unsigned long) t & 0xf);
+				t = t >> 4;
+				break;

linux/div64.h line 58

Quoted 10 lines
linux/div64.h new file +10 -0
+			default:
+				panic("do_div called with 64 bit arg and unsupported base\n", base);
+		}
+#else /* USE_SLOW_64BIT_DIVIDES */
+		/* this was stolen from the old asm-parisc/div64.h */
+		/*
+		 * Copyright (C) 1999 Hewlett-Packard Co
+		 * Copyright (C) 1999 David Mosberger-Tang <[email protected]>
+		 *
+		 * vsprintf uses this to divide a 64-bit integer N by a small 

s/small/_small_/ just to be sure that the comment is understood.

For the 10000000 case, I believe a simple stupid looping algorithm is the only solution which does not result in code size explosion.

Regards,
Gabriel.