From: Vincenzo Frascino <vincenzo.frascino@xxxxxxx> On Thursday, May 30, 2019 7:16 AM > > The x86 vDSO library requires some adaptations to take advantage of the > newly introduced generic vDSO library. > > Introduce the following changes: > - Modification of vdso.c to be compliant with the common vdso datapage > - Use of lib/vdso for gettimeofday > > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Signed-off-by: Vincenzo Frascino <vincenzo.frascino@xxxxxxx> > > > diff --git a/arch/x86/include/asm/mshyperv-tsc.h b/arch/x86/include/asm/mshyperv-tsc.h > new file mode 100644 > index 000000000000..99c98ccea0bf > --- /dev/null > +++ b/arch/x86/include/asm/mshyperv-tsc.h > @@ -0,0 +1,76 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef _ASM_X86_MSHYPER_TSCPAGE_H > +#define _ASM_X86_MSHYPER_TSCPAGE_H > + > +#include <asm/hyperv-tlfs.h> > + > +#ifdef CONFIG_HYPERV_TSCPAGE > +struct ms_hyperv_tsc_page *hv_get_tsc_page(void); > +static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, > + u64 *cur_tsc) > +{ > + u64 scale, offset; > + u32 sequence; > + > + /* > + * The protocol for reading Hyper-V TSC page is specified in Hypervisor > + * Top-Level Functional Specification ver. 3.0 and above. To get the > + * reference time we must do the following: > + * - READ ReferenceTscSequence > + * A special '0' value indicates the time source is unreliable and we > + * need to use something else. The currently published specification > + * versions (up to 4.0b) contain a mistake and wrongly claim '-1' > + * instead of '0' as the special value, see commit c35b82ef0294. > + * - ReferenceTime = > + * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset > + * - READ ReferenceTscSequence again. In case its value has changed > + * since our first reading we need to discard ReferenceTime and repeat > + * the whole sequence as the hypervisor was updating the page in > + * between. > + */ > + do { > + sequence = READ_ONCE(tsc_pg->tsc_sequence); > + if (!sequence) > + return U64_MAX; > + /* > + * Make sure we read sequence before we read other values from > + * TSC page. > + */ > + smp_rmb(); > + > + scale = READ_ONCE(tsc_pg->tsc_scale); > + offset = READ_ONCE(tsc_pg->tsc_offset); > + *cur_tsc = rdtsc_ordered(); > + > + /* > + * Make sure we read sequence after we read all other values > + * from TSC page. > + */ > + smp_rmb(); > + > + } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence); > + > + return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset; > +} > + > +static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg) > +{ > + u64 cur_tsc; > + > + return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc); > +} > + > +#else > +static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void) > +{ > + return NULL; > +} > + > +static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, > + u64 *cur_tsc) > +{ > + BUG(); > + return U64_MAX; > +} > +#endif > +#endif > diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h > index cc60e617931c..db095a992f3e 100644 > --- a/arch/x86/include/asm/mshyperv.h > +++ b/arch/x86/include/asm/mshyperv.h > @@ -7,6 +7,7 @@ > #include <linux/nmi.h> > #include <asm/io.h> > #include <asm/hyperv-tlfs.h> > +#include <asm/mshyperv-tsc.h> > #include <asm/nospec-branch.h> > > #define VP_INVAL U32_MAX > @@ -387,73 +388,4 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, > } > #endif /* CONFIG_HYPERV */ > > -#ifdef CONFIG_HYPERV_TSCPAGE > -struct ms_hyperv_tsc_page *hv_get_tsc_page(void); > -static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, > - u64 *cur_tsc) > -{ > - u64 scale, offset; > - u32 sequence; > - > - /* > - * The protocol for reading Hyper-V TSC page is specified in Hypervisor > - * Top-Level Functional Specification ver. 3.0 and above. To get the > - * reference time we must do the following: > - * - READ ReferenceTscSequence > - * A special '0' value indicates the time source is unreliable and we > - * need to use something else. The currently published specification > - * versions (up to 4.0b) contain a mistake and wrongly claim '-1' > - * instead of '0' as the special value, see commit c35b82ef0294. > - * - ReferenceTime = > - * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset > - * - READ ReferenceTscSequence again. In case its value has changed > - * since our first reading we need to discard ReferenceTime and repeat > - * the whole sequence as the hypervisor was updating the page in > - * between. > - */ > - do { > - sequence = READ_ONCE(tsc_pg->tsc_sequence); > - if (!sequence) > - return U64_MAX; > - /* > - * Make sure we read sequence before we read other values from > - * TSC page. > - */ > - smp_rmb(); > - > - scale = READ_ONCE(tsc_pg->tsc_scale); > - offset = READ_ONCE(tsc_pg->tsc_offset); > - *cur_tsc = rdtsc_ordered(); > - > - /* > - * Make sure we read sequence after we read all other values > - * from TSC page. > - */ > - smp_rmb(); > - > - } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence); > - > - return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset; > -} > - > -static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg) > -{ > - u64 cur_tsc; > - > - return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc); > -} > - > -#else > -static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void) > -{ > - return NULL; > -} > - > -static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, > - u64 *cur_tsc) > -{ > - BUG(); > - return U64_MAX; > -} > -#endif > #endif Vincenzo -- these changes for Hyper-V are a subset of a larger patch set I have that moves all of the Hyper-V clock/timer code into a separate clocksource driver in drivers/clocksource, with an include file in includes/clocksource. That new include file should be able to work instead of your new mshyperv-tsc.h. It also has the benefit of being ISA neutral, so it will work with my in-progress patch set to support Linux on Hyper-V on ARM64. See https://lkml.org/lkml/2019/5/27/231 for the new clocksource driver patch set. Michael