aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2018-09-17 08:45:38 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-10-04 17:00:25 -0400
commit49116f2081eeaf75316956705d46602b7eb735cc (patch)
tree4cf5dbd5a998d22d815cd61e03fa7c29c494759f
parent77e9c678c54f2d9214796c1c5bd0c7c7ccedd932 (diff)
x86/vdso: Introduce and use vgtod_ts
It's desired to support more clocks in the VDSO, e.g. CLOCK_TAI. This results either in indirect calls due to the larger switch case, which then requires retpolines or when the compiler is forced to avoid jump tables it results in even more conditionals. To avoid both variants which are bad for performance the high resolution functions and the coarse grained functions will be collapsed into one for each. That requires to store the clock specific base time in an array. Introcude struct vgtod_ts for storage and convert the data store, the update function and the individual clock functions over to use it. The new storage does not longer use gtod_long_t for seconds depending on 32 or 64 bit compile because this needs to be the full 64bit value even for 32bit when a Y2038 function is added. No point in keeping the distinction alive in the internal representation. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Andy Lutomirski <luto@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Matt Rickard <matt@softrans.com.au> Cc: Stephen Boyd <sboyd@kernel.org> Cc: John Stultz <john.stultz@linaro.org> Cc: Florian Weimer <fweimer@redhat.com> Cc: "K. Y. Srinivasan" <kys@microsoft.com> Cc: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: devel@linuxdriverproject.org Cc: virtualization@lists.linux-foundation.org Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Juergen Gross <jgross@suse.com> Link: https://lkml.kernel.org/r/20180917130707.324679401@linutronix.de
-rw-r--r--arch/x86/entry/vdso/vclock_gettime.c24
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_gtod.c47
-rw-r--r--arch/x86/include/asm/vgtod.h38
3 files changed, 60 insertions, 49 deletions
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index b50ee064beff..2c73e7f57316 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -208,6 +208,7 @@ notrace static inline u64 vgetsns(int *mode)
208/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */ 208/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
209notrace static int __always_inline do_realtime(struct timespec *ts) 209notrace static int __always_inline do_realtime(struct timespec *ts)
210{ 210{
211 struct vgtod_ts *base = &gtod->basetime[CLOCK_REALTIME];
211 unsigned int seq; 212 unsigned int seq;
212 u64 ns; 213 u64 ns;
213 int mode; 214 int mode;
@@ -215,8 +216,8 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
215 do { 216 do {
216 seq = gtod_read_begin(gtod); 217 seq = gtod_read_begin(gtod);
217 mode = gtod->vclock_mode; 218 mode = gtod->vclock_mode;
218 ts->tv_sec = gtod->wall_time_sec; 219 ts->tv_sec = base->sec;
219 ns = gtod->wall_time_snsec; 220 ns = base->nsec;
220 ns += vgetsns(&mode); 221 ns += vgetsns(&mode);
221 ns >>= gtod->shift; 222 ns >>= gtod->shift;
222 } while (unlikely(gtod_read_retry(gtod, seq))); 223 } while (unlikely(gtod_read_retry(gtod, seq)));
@@ -229,6 +230,7 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
229 230
230notrace static int __always_inline do_monotonic(struct timespec *ts) 231notrace static int __always_inline do_monotonic(struct timespec *ts)
231{ 232{
233 struct vgtod_ts *base = &gtod->basetime[CLOCK_MONOTONIC];
232 unsigned int seq; 234 unsigned int seq;
233 u64 ns; 235 u64 ns;
234 int mode; 236 int mode;
@@ -236,8 +238,8 @@ notrace static int __always_inline do_monotonic(struct timespec *ts)
236 do { 238 do {
237 seq = gtod_read_begin(gtod); 239 seq = gtod_read_begin(gtod);
238 mode = gtod->vclock_mode; 240 mode = gtod->vclock_mode;
239 ts->tv_sec = gtod->monotonic_time_sec; 241 ts->tv_sec = base->sec;
240 ns = gtod->monotonic_time_snsec; 242 ns = base->nsec;
241 ns += vgetsns(&mode); 243 ns += vgetsns(&mode);
242 ns >>= gtod->shift; 244 ns >>= gtod->shift;
243 } while (unlikely(gtod_read_retry(gtod, seq))); 245 } while (unlikely(gtod_read_retry(gtod, seq)));
@@ -250,21 +252,25 @@ notrace static int __always_inline do_monotonic(struct timespec *ts)
250 252
251notrace static void do_realtime_coarse(struct timespec *ts) 253notrace static void do_realtime_coarse(struct timespec *ts)
252{ 254{
255 struct vgtod_ts *base = &gtod->basetime[CLOCK_REALTIME_COARSE];
253 unsigned int seq; 256 unsigned int seq;
257
254 do { 258 do {
255 seq = gtod_read_begin(gtod); 259 seq = gtod_read_begin(gtod);
256 ts->tv_sec = gtod->wall_time_coarse_sec; 260 ts->tv_sec = base->sec;
257 ts->tv_nsec = gtod->wall_time_coarse_nsec; 261 ts->tv_nsec = base->nsec;
258 } while (unlikely(gtod_read_retry(gtod, seq))); 262 } while (unlikely(gtod_read_retry(gtod, seq)));
259} 263}
260 264
261notrace static void do_monotonic_coarse(struct timespec *ts) 265notrace static void do_monotonic_coarse(struct timespec *ts)
262{ 266{
267 struct vgtod_ts *base = &gtod->basetime[CLOCK_MONOTONIC_COARSE];
263 unsigned int seq; 268 unsigned int seq;
269
264 do { 270 do {
265 seq = gtod_read_begin(gtod); 271 seq = gtod_read_begin(gtod);
266 ts->tv_sec = gtod->monotonic_time_coarse_sec; 272 ts->tv_sec = base->sec;
267 ts->tv_nsec = gtod->monotonic_time_coarse_nsec; 273 ts->tv_nsec = base->nsec;
268 } while (unlikely(gtod_read_retry(gtod, seq))); 274 } while (unlikely(gtod_read_retry(gtod, seq)));
269} 275}
270 276
@@ -320,7 +326,7 @@ int gettimeofday(struct timeval *, struct timezone *)
320notrace time_t __vdso_time(time_t *t) 326notrace time_t __vdso_time(time_t *t)
321{ 327{
322 /* This is atomic on x86 so we don't need any locks. */ 328 /* This is atomic on x86 so we don't need any locks. */
323 time_t result = READ_ONCE(gtod->wall_time_sec); 329 time_t result = READ_ONCE(gtod->basetime[CLOCK_REALTIME].sec);
324 330
325 if (t) 331 if (t)
326 *t = result; 332 *t = result;
diff --git a/arch/x86/entry/vsyscall/vsyscall_gtod.c b/arch/x86/entry/vsyscall/vsyscall_gtod.c
index e1216dd95c04..31b9e5e0cfdf 100644
--- a/arch/x86/entry/vsyscall/vsyscall_gtod.c
+++ b/arch/x86/entry/vsyscall/vsyscall_gtod.c
@@ -31,6 +31,8 @@ void update_vsyscall(struct timekeeper *tk)
31{ 31{
32 int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; 32 int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
33 struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; 33 struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
34 struct vgtod_ts *base;
35 u64 nsec;
34 36
35 /* Mark the new vclock used. */ 37 /* Mark the new vclock used. */
36 BUILD_BUG_ON(VCLOCK_MAX >= 32); 38 BUILD_BUG_ON(VCLOCK_MAX >= 32);
@@ -45,34 +47,33 @@ void update_vsyscall(struct timekeeper *tk)
45 vdata->mult = tk->tkr_mono.mult; 47 vdata->mult = tk->tkr_mono.mult;
46 vdata->shift = tk->tkr_mono.shift; 48 vdata->shift = tk->tkr_mono.shift;
47 49
48 vdata->wall_time_sec = tk->xtime_sec; 50 base = &vdata->basetime[CLOCK_REALTIME];
49 vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; 51 base->sec = tk->xtime_sec;
52 base->nsec = tk->tkr_mono.xtime_nsec;
50 53
51 vdata->monotonic_time_sec = tk->xtime_sec 54 base = &vdata->basetime[CLOCK_MONOTONIC];
52 + tk->wall_to_monotonic.tv_sec; 55 base->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
53 vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec 56 nsec = tk->tkr_mono.xtime_nsec;
54 + ((u64)tk->wall_to_monotonic.tv_nsec 57 nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift);
55 << tk->tkr_mono.shift); 58 while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
56 while (vdata->monotonic_time_snsec >= 59 nsec -= ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
57 (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { 60 base->sec++;
58 vdata->monotonic_time_snsec -=
59 ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
60 vdata->monotonic_time_sec++;
61 } 61 }
62 base->nsec = nsec;
62 63
63 vdata->wall_time_coarse_sec = tk->xtime_sec; 64 base = &vdata->basetime[CLOCK_REALTIME_COARSE];
64 vdata->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >> 65 base->sec = tk->xtime_sec;
65 tk->tkr_mono.shift); 66 base->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
66 67
67 vdata->monotonic_time_coarse_sec = 68 base = &vdata->basetime[CLOCK_MONOTONIC_COARSE];
68 vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; 69 base->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
69 vdata->monotonic_time_coarse_nsec = 70 nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
70 vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; 71 nsec += tk->wall_to_monotonic.tv_nsec;
71 72 while (nsec >= NSEC_PER_SEC) {
72 while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { 73 nsec -= NSEC_PER_SEC;
73 vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; 74 base->sec++;
74 vdata->monotonic_time_coarse_sec++;
75 } 75 }
76 base->nsec = nsec;
76 77
77 gtod_write_end(vdata); 78 gtod_write_end(vdata);
78} 79}
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 91cad1f01027..10e534a1a51a 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -5,33 +5,37 @@
5#include <linux/compiler.h> 5#include <linux/compiler.h>
6#include <linux/clocksource.h> 6#include <linux/clocksource.h>
7 7
8#include <uapi/linux/time.h>
9
8#ifdef BUILD_VDSO32_64 10#ifdef BUILD_VDSO32_64
9typedef u64 gtod_long_t; 11typedef u64 gtod_long_t;
10#else 12#else
11typedef unsigned long gtod_long_t; 13typedef unsigned long gtod_long_t;
12#endif 14#endif
15
16struct vgtod_ts {
17 u64 sec;
18 u64 nsec;
19};
20
21#define VGTOD_BASES (CLOCK_MONOTONIC_COARSE + 1)
22#define VGTOD_HRES (BIT(CLOCK_REALTIME) | BIT(CLOCK_MONOTONIC))
23#define VGTOD_COARSE (BIT(CLOCK_REALTIME_COARSE) | BIT(CLOCK_MONOTONIC_COARSE))
24
13/* 25/*
14 * vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time 26 * vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time
15 * so be carefull by modifying this structure. 27 * so be carefull by modifying this structure.
16 */ 28 */
17struct vsyscall_gtod_data { 29struct vsyscall_gtod_data {
18 unsigned int seq; 30 unsigned int seq;
19 31
20 int vclock_mode; 32 int vclock_mode;
21 u64 cycle_last; 33 u64 cycle_last;
22 u64 mask; 34 u64 mask;
23 u32 mult; 35 u32 mult;
24 u32 shift; 36 u32 shift;
25 37
26 /* open coded 'struct timespec' */ 38 struct vgtod_ts basetime[VGTOD_BASES];
27 u64 wall_time_snsec;
28 gtod_long_t wall_time_sec;
29 gtod_long_t monotonic_time_sec;
30 u64 monotonic_time_snsec;
31 gtod_long_t wall_time_coarse_sec;
32 gtod_long_t wall_time_coarse_nsec;
33 gtod_long_t monotonic_time_coarse_sec;
34 gtod_long_t monotonic_time_coarse_nsec;
35 39
36 int tz_minuteswest; 40 int tz_minuteswest;
37 int tz_dsttime; 41 int tz_dsttime;