Blame view

lib/div64.c 1.64 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  /*
   * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
   *
   * Based on former do_div() implementation from asm-parisc/div64.h:
   *	Copyright (C) 1999 Hewlett-Packard Co
   *	Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
   *
   *
   * Generic C version of 64bit/32bit division and modulo, with
   * 64bit result and 32bit remainder.
   *
   * The fast case for (n>>32 == 0) is handled inline by do_div(). 
   *
   * Code generated for this function might be very inefficient
   * for some CPUs. __div64_32() can be overridden by linking arch-specific
   * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
   */
  
  #include <linux/types.h>
  #include <linux/module.h>
  #include <asm/div64.h>
  
  /* Not needed on 64bit architectures */
  #if BITS_PER_LONG == 32
cb8c181f2   David S. Miller   [S390]: Fix build...
25
  uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  {
  	uint64_t rem = *n;
  	uint64_t b = base;
  	uint64_t res, d = 1;
  	uint32_t high = rem >> 32;
  
  	/* Reduce the thing a bit first */
  	res = 0;
  	if (high >= base) {
  		high /= base;
  		res = (uint64_t) high << 32;
  		rem -= (uint64_t) (high*base) << 32;
  	}
  
  	while ((int64_t)b > 0 && b < rem) {
  		b = b+b;
  		d = d+d;
  	}
  
  	do {
  		if (rem >= b) {
  			rem -= b;
  			res += d;
  		}
  		b >>= 1;
  		d >>= 1;
  	} while (d);
  
  	*n = res;
  	return rem;
  }
  
  EXPORT_SYMBOL(__div64_32);
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
59
60
61
  /* 64bit divisor, dividend and result. dynamic precision */
  uint64_t div64_64(uint64_t dividend, uint64_t divisor)
  {
22b9a0a3a   Stephen Hemminger   [LIB]: div64_64 o...
62
  	uint32_t high, d;
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
63

22b9a0a3a   Stephen Hemminger   [LIB]: div64_64 o...
64
65
66
  	high = divisor >> 32;
  	if (high) {
  		unsigned int shift = fls(high);
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
67
68
69
  
  		d = divisor >> shift;
  		dividend >>= shift;
22b9a0a3a   Stephen Hemminger   [LIB]: div64_64 o...
70
71
  	} else
  		d = divisor;
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
72

22b9a0a3a   Stephen Hemminger   [LIB]: div64_64 o...
73
  	do_div(dividend, d);
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
74
75
76
77
  
  	return dividend;
  }
  EXPORT_SYMBOL(div64_64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  #endif /* BITS_PER_LONG == 32 */