--- a/arch/x86/include/asm/timer.h 2014-07-07 09:44:22.087054001 +0900 +++ b/arch/x86/include/asm/timer.h 2014-07-07 09:44:55.877054001 +0900 @@ -63,14 +63,10 @@ static inline unsigned long long __cycles_2_ns(unsigned long long cyc) { - unsigned long long quot; - unsigned long long rem; int cpu = smp_processor_id(); unsigned long long ns = per_cpu(cyc2ns_offset, cpu); - quot = (cyc >> CYC2NS_SCALE_FACTOR); - rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1); - ns += quot * per_cpu(cyc2ns, cpu) + - ((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR); + ns += mult_frac(cyc, per_cpu(cyc2ns, cpu), + (1UL << CYC2NS_SCALE_FACTOR)); return ns; } --- a/arch/x86/kernel/tsc.c 2014-07-07 09:45:13.257054001 +0900 +++ b/arch/x86/kernel/tsc.c 2014-07-07 09:48:02.817054001 +0900 @@ -625,7 +625,7 @@ if (cpu_khz) { *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; - *offset = ns_now - (tsc_now * *scale >> CYC2NS_SCALE_FACTOR); + *offset = ns_now - mult_frac(tsc_now, *scale, (1UL << CYC2NS_SCALE_FACTOR)); } sched_clock_idle_wakeup_event(0); --- a/include/linux/kernel.h 2014-07-07 09:48:23.607054001 +0900 +++ b/include/linux/kernel.h 2014-07-07 09:50:31.627054001 +0900 @@ -66,6 +66,19 @@ } \ ) +/* + * Multiplies an integer by a fraction, while avoiding unnecessary + * overflow or loss of precision. + */ +#define mult_frac(x, numer, denom)( \ +{ \ + typeof(x) quot = (x) / (denom); \ + typeof(x) rem = (x) % (denom); \ + (quot * (numer)) + ((rem * (numer)) / (denom)); \ +} \ +) + + #define _RET_IP_ (unsigned long)__builtin_return_address(0) #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })