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
111 lines
2.2 KiB
C
111 lines
2.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_X86_VGTOD_H
|
|
#define _ASM_X86_VGTOD_H
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/clocksource.h>
|
|
|
|
#include <uapi/linux/time.h>
|
|
|
|
#ifdef BUILD_VDSO32_64
|
|
typedef u64 gtod_long_t;
|
|
#else
|
|
typedef unsigned long gtod_long_t;
|
|
#endif
|
|
|
|
struct vgtod_ts {
|
|
u64 sec;
|
|
u64 nsec;
|
|
};
|
|
|
|
#define VGTOD_BASES (CLOCK_MONOTONIC_COARSE + 1)
|
|
#define VGTOD_HRES (BIT(CLOCK_REALTIME) | BIT(CLOCK_MONOTONIC))
|
|
#define VGTOD_COARSE (BIT(CLOCK_REALTIME_COARSE) | BIT(CLOCK_MONOTONIC_COARSE))
|
|
|
|
/*
|
|
* vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time
|
|
* so be carefull by modifying this structure.
|
|
*/
|
|
struct vsyscall_gtod_data {
|
|
unsigned int seq;
|
|
|
|
int vclock_mode;
|
|
u64 cycle_last;
|
|
u64 mask;
|
|
u32 mult;
|
|
u32 shift;
|
|
|
|
struct vgtod_ts basetime[VGTOD_BASES];
|
|
|
|
int tz_minuteswest;
|
|
int tz_dsttime;
|
|
};
|
|
extern struct vsyscall_gtod_data vsyscall_gtod_data;
|
|
|
|
extern int vclocks_used;
|
|
static inline bool vclock_was_used(int vclock)
|
|
{
|
|
return READ_ONCE(vclocks_used) & (1 << vclock);
|
|
}
|
|
|
|
static inline unsigned int gtod_read_begin(const struct vsyscall_gtod_data *s)
|
|
{
|
|
unsigned int ret;
|
|
|
|
repeat:
|
|
ret = READ_ONCE(s->seq);
|
|
if (unlikely(ret & 1)) {
|
|
cpu_relax();
|
|
goto repeat;
|
|
}
|
|
smp_rmb();
|
|
return ret;
|
|
}
|
|
|
|
static inline int gtod_read_retry(const struct vsyscall_gtod_data *s,
|
|
unsigned int start)
|
|
{
|
|
smp_rmb();
|
|
return unlikely(s->seq != start);
|
|
}
|
|
|
|
static inline void gtod_write_begin(struct vsyscall_gtod_data *s)
|
|
{
|
|
++s->seq;
|
|
smp_wmb();
|
|
}
|
|
|
|
static inline void gtod_write_end(struct vsyscall_gtod_data *s)
|
|
{
|
|
smp_wmb();
|
|
++s->seq;
|
|
}
|
|
|
|
#ifdef CONFIG_X86_64
|
|
|
|
#define VGETCPU_CPU_MASK 0xfff
|
|
|
|
static inline unsigned int __getcpu(void)
|
|
{
|
|
unsigned int p;
|
|
|
|
/*
|
|
* Load per CPU data from GDT. LSL is faster than RDTSCP and
|
|
* works on all CPUs. This is volatile so that it orders
|
|
* correctly wrt barrier() and to keep gcc from cleverly
|
|
* hoisting it out of the calling function.
|
|
*
|
|
* If RDPID is available, use it.
|
|
*/
|
|
alternative_io ("lsl %[seg],%[p]",
|
|
".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */
|
|
X86_FEATURE_RDPID,
|
|
[p] "=a" (p), [seg] "r" (__PER_CPU_SEG));
|
|
|
|
return p;
|
|
}
|
|
|
|
#endif /* CONFIG_X86_64 */
|
|
|
|
#endif /* _ASM_X86_VGTOD_H */
|