diff options
| author | John Stultz <john.stultz@linaro.org> | 2012-09-04 16:14:46 -0400 |
|---|---|---|
| committer | John Stultz <john.stultz@linaro.org> | 2012-09-24 12:38:09 -0400 |
| commit | 650ea02475106e8d6bdf561896d2ffe0d1c0ebb4 (patch) | |
| tree | 0e4e06e525c8e47cd3379addbbc4895f20347df7 | |
| parent | 92bb1fcf57a0c2e45f7e67fbf0a8ed475a749236 (diff) | |
time: Convert x86_64 to using new update_vsyscall
Switch x86_64 to using sub-ns precise vsyscall
Cc: Tony Luck <tony.luck@intel.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
| -rw-r--r-- | arch/x86/Kconfig | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/vgtod.h | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/vsyscall_64.c | 47 | ||||
| -rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 22 |
4 files changed, 45 insertions, 30 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e3f3c1a5a744..8ec3a1aa4abd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -93,7 +93,7 @@ config X86 | |||
| 93 | select GENERIC_CLOCKEVENTS | 93 | select GENERIC_CLOCKEVENTS |
| 94 | select ARCH_CLOCKSOURCE_DATA if X86_64 | 94 | select ARCH_CLOCKSOURCE_DATA if X86_64 |
| 95 | select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) | 95 | select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) |
| 96 | select GENERIC_TIME_VSYSCALL_OLD if X86_64 | 96 | select GENERIC_TIME_VSYSCALL if X86_64 |
| 97 | select KTIME_SCALAR if X86_32 | 97 | select KTIME_SCALAR if X86_32 |
| 98 | select GENERIC_STRNCPY_FROM_USER | 98 | select GENERIC_STRNCPY_FROM_USER |
| 99 | select GENERIC_STRNLEN_USER | 99 | select GENERIC_STRNLEN_USER |
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index 8b38be2de9e1..46e24d36b7da 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h | |||
| @@ -17,8 +17,8 @@ struct vsyscall_gtod_data { | |||
| 17 | 17 | ||
| 18 | /* open coded 'struct timespec' */ | 18 | /* open coded 'struct timespec' */ |
| 19 | time_t wall_time_sec; | 19 | time_t wall_time_sec; |
| 20 | u32 wall_time_nsec; | 20 | u64 wall_time_snsec; |
| 21 | u32 monotonic_time_nsec; | 21 | u64 monotonic_time_snsec; |
| 22 | time_t monotonic_time_sec; | 22 | time_t monotonic_time_sec; |
| 23 | 23 | ||
| 24 | struct timezone sys_tz; | 24 | struct timezone sys_tz; |
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 77dde2953c64..3a3e8c9e280d 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c | |||
| @@ -82,32 +82,41 @@ void update_vsyscall_tz(void) | |||
| 82 | vsyscall_gtod_data.sys_tz = sys_tz; | 82 | vsyscall_gtod_data.sys_tz = sys_tz; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, | 85 | void update_vsyscall(struct timekeeper *tk) |
| 86 | struct clocksource *clock, u32 mult) | ||
| 87 | { | 86 | { |
| 88 | struct timespec monotonic; | 87 | struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; |
| 89 | 88 | ||
| 90 | write_seqcount_begin(&vsyscall_gtod_data.seq); | 89 | write_seqcount_begin(&vdata->seq); |
| 91 | 90 | ||
| 92 | /* copy vsyscall data */ | 91 | /* copy vsyscall data */ |
| 93 | vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode; | 92 | vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode; |
| 94 | vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; | 93 | vdata->clock.cycle_last = tk->clock->cycle_last; |
| 95 | vsyscall_gtod_data.clock.mask = clock->mask; | 94 | vdata->clock.mask = tk->clock->mask; |
| 96 | vsyscall_gtod_data.clock.mult = mult; | 95 | vdata->clock.mult = tk->mult; |
| 97 | vsyscall_gtod_data.clock.shift = clock->shift; | 96 | vdata->clock.shift = tk->shift; |
| 98 | 97 | ||
| 99 | vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; | 98 | vdata->wall_time_sec = tk->xtime_sec; |
| 100 | vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; | 99 | vdata->wall_time_snsec = tk->xtime_nsec; |
| 100 | |||
| 101 | vdata->monotonic_time_sec = tk->xtime_sec | ||
| 102 | + tk->wall_to_monotonic.tv_sec; | ||
| 103 | vdata->monotonic_time_snsec = tk->xtime_nsec | ||
| 104 | + (tk->wall_to_monotonic.tv_nsec | ||
| 105 | << tk->shift); | ||
| 106 | while (vdata->monotonic_time_snsec >= | ||
| 107 | (((u64)NSEC_PER_SEC) << tk->shift)) { | ||
| 108 | vdata->monotonic_time_snsec -= | ||
| 109 | ((u64)NSEC_PER_SEC) << tk->shift; | ||
| 110 | vdata->monotonic_time_sec++; | ||
| 111 | } | ||
| 101 | 112 | ||
| 102 | monotonic = timespec_add(*wall_time, *wtm); | 113 | vdata->wall_time_coarse.tv_sec = tk->xtime_sec; |
| 103 | vsyscall_gtod_data.monotonic_time_sec = monotonic.tv_sec; | 114 | vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); |
| 104 | vsyscall_gtod_data.monotonic_time_nsec = monotonic.tv_nsec; | ||
| 105 | 115 | ||
| 106 | vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); | 116 | vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse, |
| 107 | vsyscall_gtod_data.monotonic_time_coarse = | 117 | tk->wall_to_monotonic); |
| 108 | timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm); | ||
| 109 | 118 | ||
| 110 | write_seqcount_end(&vsyscall_gtod_data.seq); | 119 | write_seqcount_end(&vdata->seq); |
| 111 | } | 120 | } |
| 112 | 121 | ||
| 113 | static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, | 122 | static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, |
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 885eff49d6ab..4df6c373421a 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
| @@ -80,7 +80,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | 82 | ||
| 83 | notrace static inline long vgetns(void) | 83 | notrace static inline u64 vgetsns(void) |
| 84 | { | 84 | { |
| 85 | long v; | 85 | long v; |
| 86 | cycles_t cycles; | 86 | cycles_t cycles; |
| @@ -91,21 +91,24 @@ notrace static inline long vgetns(void) | |||
| 91 | else | 91 | else |
| 92 | return 0; | 92 | return 0; |
| 93 | v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask; | 93 | v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask; |
| 94 | return (v * gtod->clock.mult) >> gtod->clock.shift; | 94 | return v * gtod->clock.mult; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /* Code size doesn't matter (vdso is 4k anyway) and this is faster. */ | 97 | /* Code size doesn't matter (vdso is 4k anyway) and this is faster. */ |
| 98 | notrace static int __always_inline do_realtime(struct timespec *ts) | 98 | notrace static int __always_inline do_realtime(struct timespec *ts) |
| 99 | { | 99 | { |
| 100 | unsigned long seq, ns; | 100 | unsigned long seq; |
| 101 | u64 ns; | ||
| 101 | int mode; | 102 | int mode; |
| 102 | 103 | ||
| 104 | ts->tv_nsec = 0; | ||
| 103 | do { | 105 | do { |
| 104 | seq = read_seqcount_begin(>od->seq); | 106 | seq = read_seqcount_begin(>od->seq); |
| 105 | mode = gtod->clock.vclock_mode; | 107 | mode = gtod->clock.vclock_mode; |
| 106 | ts->tv_sec = gtod->wall_time_sec; | 108 | ts->tv_sec = gtod->wall_time_sec; |
| 107 | ts->tv_nsec = gtod->wall_time_nsec; | 109 | ns = gtod->wall_time_snsec; |
| 108 | ns = vgetns(); | 110 | ns += vgetsns(); |
| 111 | ns >>= gtod->clock.shift; | ||
| 109 | } while (unlikely(read_seqcount_retry(>od->seq, seq))); | 112 | } while (unlikely(read_seqcount_retry(>od->seq, seq))); |
| 110 | 113 | ||
| 111 | timespec_add_ns(ts, ns); | 114 | timespec_add_ns(ts, ns); |
| @@ -114,15 +117,18 @@ notrace static int __always_inline do_realtime(struct timespec *ts) | |||
| 114 | 117 | ||
| 115 | notrace static int do_monotonic(struct timespec *ts) | 118 | notrace static int do_monotonic(struct timespec *ts) |
| 116 | { | 119 | { |
| 117 | unsigned long seq, ns; | 120 | unsigned long seq; |
| 121 | u64 ns; | ||
| 118 | int mode; | 122 | int mode; |
| 119 | 123 | ||
| 124 | ts->tv_nsec = 0; | ||
| 120 | do { | 125 | do { |
| 121 | seq = read_seqcount_begin(>od->seq); | 126 | seq = read_seqcount_begin(>od->seq); |
| 122 | mode = gtod->clock.vclock_mode; | 127 | mode = gtod->clock.vclock_mode; |
| 123 | ts->tv_sec = gtod->monotonic_time_sec; | 128 | ts->tv_sec = gtod->monotonic_time_sec; |
| 124 | ts->tv_nsec = gtod->monotonic_time_nsec; | 129 | ns = gtod->monotonic_time_snsec; |
| 125 | ns = vgetns(); | 130 | ns += vgetsns(); |
| 131 | ns >>= gtod->clock.shift; | ||
| 126 | } while (unlikely(read_seqcount_retry(>od->seq, seq))); | 132 | } while (unlikely(read_seqcount_retry(>od->seq, seq))); |
| 127 | timespec_add_ns(ts, ns); | 133 | timespec_add_ns(ts, ns); |
| 128 | 134 | ||
