diff options
| -rw-r--r-- | arch/x86/include/asm/timer.h | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/tsc.c | 3 | ||||
| -rw-r--r-- | include/linux/kernel.h | 13 |
3 files changed, 17 insertions, 7 deletions
diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h index 431793e5d484..34baa0eb5d0c 100644 --- a/arch/x86/include/asm/timer.h +++ b/arch/x86/include/asm/timer.h | |||
| @@ -57,14 +57,10 @@ DECLARE_PER_CPU(unsigned long long, cyc2ns_offset); | |||
| 57 | 57 | ||
| 58 | static inline unsigned long long __cycles_2_ns(unsigned long long cyc) | 58 | static inline unsigned long long __cycles_2_ns(unsigned long long cyc) |
| 59 | { | 59 | { |
| 60 | unsigned long long quot; | ||
| 61 | unsigned long long rem; | ||
| 62 | int cpu = smp_processor_id(); | 60 | int cpu = smp_processor_id(); |
| 63 | unsigned long long ns = per_cpu(cyc2ns_offset, cpu); | 61 | unsigned long long ns = per_cpu(cyc2ns_offset, cpu); |
| 64 | quot = (cyc >> CYC2NS_SCALE_FACTOR); | 62 | ns += mult_frac(cyc, per_cpu(cyc2ns, cpu), |
| 65 | rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1); | 63 | (1UL << CYC2NS_SCALE_FACTOR)); |
| 66 | ns += quot * per_cpu(cyc2ns, cpu) + | ||
| 67 | ((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR); | ||
| 68 | return ns; | 64 | return ns; |
| 69 | } | 65 | } |
| 70 | 66 | ||
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index a62c201c97ec..183c5925a9fe 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -620,7 +620,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) | |||
| 620 | 620 | ||
| 621 | if (cpu_khz) { | 621 | if (cpu_khz) { |
| 622 | *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; | 622 | *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; |
| 623 | *offset = ns_now - (tsc_now * *scale >> CYC2NS_SCALE_FACTOR); | 623 | *offset = ns_now - mult_frac(tsc_now, *scale, |
| 624 | (1UL << CYC2NS_SCALE_FACTOR)); | ||
| 624 | } | 625 | } |
| 625 | 626 | ||
| 626 | sched_clock_idle_wakeup_event(0); | 627 | sched_clock_idle_wakeup_event(0); |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e8343422240a..d801acb5e680 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
| @@ -85,6 +85,19 @@ | |||
| 85 | } \ | 85 | } \ |
| 86 | ) | 86 | ) |
| 87 | 87 | ||
| 88 | /* | ||
| 89 | * Multiplies an integer by a fraction, while avoiding unnecessary | ||
| 90 | * overflow or loss of precision. | ||
| 91 | */ | ||
| 92 | #define mult_frac(x, numer, denom)( \ | ||
| 93 | { \ | ||
| 94 | typeof(x) quot = (x) / (denom); \ | ||
| 95 | typeof(x) rem = (x) % (denom); \ | ||
| 96 | (quot * (numer)) + ((rem * (numer)) / (denom)); \ | ||
| 97 | } \ | ||
| 98 | ) | ||
| 99 | |||
| 100 | |||
| 88 | #define _RET_IP_ (unsigned long)__builtin_return_address(0) | 101 | #define _RET_IP_ (unsigned long)__builtin_return_address(0) |
| 89 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | 102 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) |
| 90 | 103 | ||
