From: Vincenzo Frascino <[email protected]> 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 <[email protected]>
> Signed-off-by: Vincenzo Frascino <[email protected]>
>
>
> 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

Reply via email to