summary refs log tree commit diff
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-06-12 07:47:44 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-06-12 07:47:44 -0700
commitdc10885d68ae5893038e009f82cbb14a05aa9dd0 (patch)
tree873929ff5bbb9263d1a325abd0f6a4c8fe26d208 /include
parent631025b4d87d5a9d7e04a1ed652d247191e223d4 (diff)
parent9412e28649d0272df5e4af57bb378926fd4df580 (diff)
downloadlinux-dc10885d68ae5893038e009f82cbb14a05aa9dd0.tar.gz
Merge branch 'core/iter-div' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'core/iter-div' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  always_inline timespec_add_ns
  add an inlined version of iter_div_u64_rem
  common implementation of iterative div/mod
Diffstat (limited to 'include')
-rw-r--r--include/linux/math64.h21
-rw-r--r--include/linux/time.h16
2 files changed, 27 insertions, 10 deletions
diff --git a/include/linux/math64.h b/include/linux/math64.h
index c1a5f81501ff..c87f1528703a 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -81,4 +81,25 @@ static inline s64 div_s64(s64 dividend, s32 divisor)
 }
 #endif
 
+u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
+
+static __always_inline u32
+__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
+{
+	u32 ret = 0;
+
+	while (dividend >= divisor) {
+		/* The following asm() prevents the compiler from
+		   optimising this loop into a modulo operation.  */
+		asm("" : "+rm"(dividend));
+
+		dividend -= divisor;
+		ret++;
+	}
+
+	*remainder = dividend;
+
+	return ret;
+}
+
 #endif /* _LINUX_MATH64_H */
diff --git a/include/linux/time.h b/include/linux/time.h
index d32ef0ad4c0a..e15206a7e82e 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -6,6 +6,7 @@
 #ifdef __KERNEL__
 # include <linux/cache.h>
 # include <linux/seqlock.h>
+# include <linux/math64.h>
 #endif
 
 #ifndef _STRUCT_TIMESPEC
@@ -169,18 +170,13 @@ extern struct timeval ns_to_timeval(const s64 nsec);
  * timespec_add_ns - Adds nanoseconds to a timespec
  * @a:		pointer to timespec to be incremented
  * @ns:		unsigned nanoseconds value to be added
+ *
+ * This must always be inlined because its used from the x86-64 vdso,
+ * which cannot call other kernel functions.
  */
-static inline void timespec_add_ns(struct timespec *a, u64 ns)
+static __always_inline void timespec_add_ns(struct timespec *a, u64 ns)
 {
-	ns += a->tv_nsec;
-	while(unlikely(ns >= NSEC_PER_SEC)) {
-		/* The following asm() prevents the compiler from
-		 * optimising this loop into a modulo operation.  */
-		asm("" : "+r"(ns));
-
-		ns -= NSEC_PER_SEC;
-		a->tv_sec++;
-	}
+	a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
 	a->tv_nsec = ns;
 }
 #endif /* __KERNEL__ */